-
Type: Improvement
-
Resolution: Done
-
Priority: Major - P3
-
Affects Version/s: None
-
Component/s: Shell
-
Fully Compatible
-
Repl 2019-08-26
-
0
The Math.random() function in JavaScript isn't seeded, so the mongo shell provides a Random.rand() function that can be seeded using the Random.srand() function. The C++ function that underlies Random.rand() uses the rand_r() function on POSIX systems and the rand() function on Windows. The RAND_MAX value used to scale the results to be a floating-point number between 0 and 1 is platform-specific. This means that even for the same seed, the pseudo-random number generator will produce different sequences on Windows, Linux, and OS X.
The Random.setRandomSeed() function seeds the pseudo-random number generator with a value generated by a SecureRandom instance. Some of our more complex JavaScript integration tests use a pseudo-random number generator to vary the test data and/or operations to make the test case more interesting each time. Having the pseudo-random number generator in the mongo shell be platform-independent would greatly aid in reproducing the exact test setup without requiring using the same platform as what the test failure occurred on.
#if !defined(_WIN32) ThreadLocalValue<unsigned int> _randomSeed; #endif BSONObj JSSrand(const BSONObj& a, void* data) { unsigned int seed; // grab the least significant bits of either the supplied argument or // a random number from SecureRandom. if (a.nFields() == 1 && a.firstElement().isNumber()) seed = static_cast<unsigned int>(a.firstElement().numberLong()); else { std::unique_ptr<SecureRandom> rand(SecureRandom::create()); seed = static_cast<unsigned int>(rand->nextInt64()); } #if !defined(_WIN32) _randomSeed.set(seed); #else srand(seed); #endif return BSON("" << static_cast<double>(seed)); } BSONObj JSRand(const BSONObj& a, void* data) { uassert(12519, "rand accepts no arguments", a.nFields() == 0); unsigned r; #if !defined(_WIN32) r = rand_r(&_randomSeed.getRef()); #else r = rand(); #endif return BSON("" << double(r) / (double(RAND_MAX) + 1)); }