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

Secondaries generate a UUID for a replicated collection on their own if one isn't provided

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Major - P3 Major - P3
    • 3.6.0-rc0
    • Affects Version/s: None
    • Component/s: Replication, Storage
    • None
    • Fully Compatible
    • ALL
    • Hide
      python buildscripts/resmoke.py --suites=no_server server31018.js
      
      repro_server31018.js
      (function() {
          "use strict";
      
          load("jstests/libs/parallelTester.js");  // for ScopedThread and CountDownLatch
      
          const rst = new ReplSetTest({nodes: 2});
          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 secondary = rst.getSecondary();
      
          const primaryDB = primary.getDB("test");
          const secondaryDB = secondary.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(
                      primaryDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}));
      
                  if (res.featureCompatibilityVersion === "3.4") {
                      assert.commandWorked(
                          primaryDB.adminCommand({setFeatureCompatibilityVersion: "3.6"}));
                      continue;
                  }
              }
      
              // Otherwise, we implicitly create a collection via an insert operation and verify that the
              // collection has identical metadata on the primary and the secondary.
              {
                  primaryDB.mycoll.drop();
                  assert.writeOK(primaryDB.mycoll.insert({}, {writeConcern: {w: 2}}));
      
                  const primaryCollectionInfos = primaryDB.getCollectionInfos({name: "mycoll"});
                  assert.eq(1, primaryCollectionInfos.length, tojson(primaryCollectionInfos));
      
                  const secondaryCollectionInfos = secondaryDB.getCollectionInfos({name: "mycoll"});
                  assert.eq(1, secondaryCollectionInfos.length, tojson(secondaryCollectionInfos));
      
                  assert.eq(primaryCollectionInfos[0],
                            secondaryCollectionInfos[0],
                            "Expected primary and secondary to have the same collection metadata");
              }
          }
      
          rst.stopSet();
      })();
      
      Show
      python buildscripts/resmoke.py --suites=no_server server31018.js repro_server31018.js ( function () { "use strict" ; load( "jstests/libs/parallelTester.js" ); // for ScopedThread and CountDownLatch const rst = new ReplSetTest({nodes: 2}); 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 secondary = rst.getSecondary(); const primaryDB = primary.getDB( "test" ); const secondaryDB = secondary.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( primaryDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1})); if (res.featureCompatibilityVersion === "3.4" ) { assert.commandWorked( primaryDB.adminCommand({setFeatureCompatibilityVersion: "3.6" })); continue ; } } // Otherwise, we implicitly create a collection via an insert operation and verify that the // collection has identical metadata on the primary and the secondary. { primaryDB.mycoll.drop(); assert.writeOK(primaryDB.mycoll.insert({}, {writeConcern: {w: 2}})); const primaryCollectionInfos = primaryDB.getCollectionInfos({name: "mycoll" }); assert.eq(1, primaryCollectionInfos.length, tojson(primaryCollectionInfos)); const secondaryCollectionInfos = secondaryDB.getCollectionInfos({name: "mycoll" }); assert.eq(1, secondaryCollectionInfos.length, tojson(secondaryCollectionInfos)); assert.eq(primaryCollectionInfos[0], secondaryCollectionInfos[0], "Expected primary and secondary to have the same collection metadata" ); } } rst.stopSet(); })();
    • Storage 2017-10-02, Storage 2017-10-23
    • 0

      If a secondary during steady-state replication receives an oplog entry for creating a collection without a UUID while it is in featureCompatibilityVersion=3.6, then it must abort because the alternative is data corruption.

      Note: This issue was only found due to a race condition in the "setFeatureCompatibilityVersion" command allowing for this possibility (SERVER-31017). I suspect it is possible to simulate this more easily in sync_tail_test.cpp by using the multiSyncApply_noAbort() function.

      2017-09-10T10:58:45.756-0400 2017-09-10T10:58:45.752-0400 E QUERY    [thread1] Error: [{
      2017-09-10T10:58:45.756-0400 	"name" : "mycoll",
      2017-09-10T10:58:45.756-0400 	"type" : "collection",
      2017-09-10T10:58:45.756-0400 	"options" : {
      2017-09-10T10:58:45.757-0400
      2017-09-10T10:58:45.757-0400 	},
      2017-09-10T10:58:45.757-0400 	"info" : {
      2017-09-10T10:58:45.757-0400 		"readOnly" : false
      2017-09-10T10:58:45.757-0400 	},
      2017-09-10T10:58:45.757-0400 	"idIndex" : {
      2017-09-10T10:58:45.757-0400 		"v" : 2,
      2017-09-10T10:58:45.757-0400 		"key" : {
      2017-09-10T10:58:45.757-0400 			"_id" : 1
      2017-09-10T10:58:45.757-0400 		},
      2017-09-10T10:58:45.758-0400 		"name" : "_id_",
      2017-09-10T10:58:45.758-0400 		"ns" : "test.mycoll"
      2017-09-10T10:58:45.758-0400 	}
      2017-09-10T10:58:45.758-0400 }] != [{
      2017-09-10T10:58:45.758-0400 	"name" : "mycoll",
      2017-09-10T10:58:45.758-0400 	"type" : "collection",
      2017-09-10T10:58:45.758-0400 	"options" : {
      2017-09-10T10:58:45.758-0400
      2017-09-10T10:58:45.758-0400 	},
      2017-09-10T10:58:45.758-0400 	"info" : {
      2017-09-10T10:58:45.758-0400 		"readOnly" : false,
      2017-09-10T10:58:45.759-0400 		"uuid" : UUID("440a716d-c32d-49d0-a39b-87c564ac61c6")
      2017-09-10T10:58:45.759-0400 	},
      2017-09-10T10:58:45.759-0400 	"idIndex" : {
      2017-09-10T10:58:45.759-0400 		"v" : 2,
      2017-09-10T10:58:45.759-0400 		"key" : {
      2017-09-10T10:58:45.759-0400 			"_id" : 1
      2017-09-10T10:58:45.760-0400 		},
      2017-09-10T10:58:45.760-0400 		"name" : "_id_",
      2017-09-10T10:58:45.760-0400 		"ns" : "test.mycoll"
      2017-09-10T10:58:45.760-0400 	}
      2017-09-10T10:58:45.760-0400 }] are not equal : Expected primary and secondary to have the same collection metadata :
      

            Assignee:
            geert.bosch@mongodb.com Geert Bosch
            Reporter:
            max.hirschhorn@mongodb.com Max Hirschhorn
            Votes:
            0 Vote for this issue
            Watchers:
            7 Start watching this issue

              Created:
              Updated:
              Resolved: