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

    XMLWordPrintableJSON

Details

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Major - P3 Major - P3
    • 3.6.0-rc0
    • None
    • 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

    Description

      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 :
      

      Attachments

        Activity

          People

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

            Dates

              Created:
              Updated:
              Resolved: