Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-24437

Use a platform-independent PRNG in the mongo shell for Random.rand()

    • 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));
      }
      

            Assignee:
            jason.chan@mongodb.com Jason Chan
            Reporter:
            max.hirschhorn@mongodb.com Max Hirschhorn
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: