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

Race condition in setFeatureCompatibilityVersion command leads to fCV=3.6 and isSchemaVersion36=false

    • Type: Icon: Bug Bug
    • Resolution: Gone away
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • Component/s: Storage
    • None
    • Fully Compatible
    • ALL
    • Hide
      python buildscripts/resmoke.py --suites=no_server repro_server31017.js
      
      repro_server31017.js
      (function() {
          "use strict";
      
          load("jstests/libs/parallelTester.js");  // for ScopedThread and CountDownLatch
      
          const rst = new ReplSetTest({nodes: 1});
          rst.startSet();
          rst.initiate();
      
          function setFCV(host, version, barrier) {
              const conn = new Mongo(host);
      
              barrier.countDown();
              barrier.await();
      
              try {
                  assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: version}));
                  return {ok: 1};
              } catch (e) {
                  return {ok: 0, error: e.toString(), stack: e.stack};
              }
          }
      
          const primary = rst.getPrimary();
          const db = primary.getDB("test");
      
          while (true) {
              // We create two threads: one to set the server's featureCompatibilityVersion to "3.4" and
              // another to set the server's featureCompatibilityVersion to "3.6".
              {
                  const barrier = new CountDownLatch(2);
                  const thread34 = new ScopedThread(setFCV, primary.host, "3.4", barrier);
                  const thread36 = new ScopedThread(setFCV, primary.host, "3.6", barrier);
      
                  thread34.start();
                  thread36.start();
      
                  thread34.join();
                  thread36.join();
      
                  assert.commandWorked(thread34.returnData());
                  assert.commandWorked(thread36.returnData());
              }
      
              // If the thread that sets the server's featureCompatibilityVersion to "3.4" did its update
              // to the featureCompatibilityVersion document last, then we reset the server's
              // featureCompatibilityVersion to "3.6" and try again.
              {
                  const res = assert.commandWorked(
                      db.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}));
      
                  if (res.featureCompatibilityVersion === "3.4") {
                      assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: "3.6"}));
                      continue;
                  }
              }
      
              // Otherwise, we implicitly create a collection via an insert operation and verify that
              // collections are always created with UUIDs when the server's featureCompatibilityVersion
              // is "3.6".
              {
                  db.mycoll.drop();
                  assert.writeOK(db.mycoll.insert({}));
      
                  const collectionInfos = db.getCollectionInfos({name: "mycoll"});
                  assert.eq(1, collectionInfos.length, tojson(collectionInfos));
                  assert(collectionInfos[0].info.hasOwnProperty("uuid"),
                         "Expected collection to have a UUID since featureCompatibilityVersion is 3.6: " +
                             tojson(collectionInfos));
              }
          }
      
          rst.stopSet();
      })();
      
      Show
      python buildscripts/resmoke.py --suites=no_server repro_server31017.js repro_server31017.js ( function () { "use strict" ; load( "jstests/libs/parallelTester.js" ); // for ScopedThread and CountDownLatch const rst = new ReplSetTest({nodes: 1}); rst.startSet(); rst.initiate(); function setFCV(host, version, barrier) { const conn = new Mongo(host); barrier.countDown(); barrier.await(); try { assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: version})); return {ok: 1}; } catch (e) { return {ok: 0, error: e.toString(), stack: e.stack}; } } const primary = rst.getPrimary(); const db = primary.getDB( "test" ); while ( true ) { // We create two threads: one to set the server's featureCompatibilityVersion to "3.4" and // another to set the server's featureCompatibilityVersion to "3.6" . { const barrier = new CountDownLatch(2); const thread34 = new ScopedThread(setFCV, primary.host, "3.4" , barrier); const thread36 = new ScopedThread(setFCV, primary.host, "3.6" , barrier); thread34.start(); thread36.start(); thread34.join(); thread36.join(); assert.commandWorked(thread34.returnData()); assert.commandWorked(thread36.returnData()); } // If the thread that sets the server's featureCompatibilityVersion to "3.4" did its update // to the featureCompatibilityVersion document last, then we reset the server's // featureCompatibilityVersion to "3.6" and try again. { const res = assert.commandWorked( db.adminCommand({getParameter: 1, featureCompatibilityVersion: 1})); if (res.featureCompatibilityVersion === "3.4" ) { assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: "3.6" })); continue ; } } // Otherwise, we implicitly create a collection via an insert operation and verify that // collections are always created with UUIDs when the server's featureCompatibilityVersion // is "3.6" . { db.mycoll.drop(); assert.writeOK(db.mycoll.insert({})); const collectionInfos = db.getCollectionInfos({name: "mycoll" }); assert.eq(1, collectionInfos.length, tojson(collectionInfos)); assert(collectionInfos[0].info.hasOwnProperty( "uuid" ), "Expected collection to have a UUID since featureCompatibilityVersion is 3.6: " + tojson(collectionInfos)); } } rst.stopSet(); })();
    • Sharding 2017-10-23

      This issue is caused by allowing serverGlobalParams.featureCompatibility.isSchemaVersion36 to be set to false after the featureCompatibilityVersion document has been updated as part of FeatureCompatibilityVersion::set(). Consider the following sequence of events with two threads when the server starts out in featureCompatibilityVersion=3.6.

      Thread in {setFCV: "3.4"}                 Thread in {setFCV: "3.6"}
                |                                         |
                |                                         |
      FCV::set() called                                   |
                |                                         |
      fCV document changed to "3.4"                       |
                |                                         |
      fCV global set to "3.4" via OpObserver              |
                |                                         |
      isSchemaVersion36 global set to false               |
      via OpObserver                                      |
                |                                         |
                |                                         |
                |                               FCV::set() called
                |                                         |
                |                               fCV document changed to "3.6"
                |                                         |
                |                               fCV global set to "3.6" via OpObserver
                |                                         |
                |                               isSchemaVersion36 global set to true
                |                               via OpObserver
                |                                         |
                |                                         |
      isSchemaVersion36 global set to false               |
      via setFCV                                          |
      

            Assignee:
            esha.maharishi@mongodb.com Esha Maharishi (Inactive)
            Reporter:
            max.hirschhorn@mongodb.com Max Hirschhorn
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: