diff options
author | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2019-02-21 11:24:31 -0500 |
---|---|---|
committer | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2019-02-25 15:36:04 -0500 |
commit | 54cc4d76250719b247080c1195d4b672322d989e (patch) | |
tree | 09298afdf6d20c8aba20cd7f10d2151ced3e3c11 | |
parent | f5e0120d8b8ac05baea642f423abb55a5a8b8f65 (diff) | |
download | mongo-54cc4d76250719b247080c1195d4b672322d989e.tar.gz |
SERVER-39719 Ensure that a node performing an initial sync from a secondary with a in-progress index build creates the index before initial sync is done
(cherry picked from commit efefc4f94203c3e6119916b89255017d117e982f)
-rw-r--r-- | jstests/replsets/secondary_as_sync_source.js | 88 | ||||
-rw-r--r-- | src/mongo/shell/replsettest.js | 9 |
2 files changed, 97 insertions, 0 deletions
diff --git a/jstests/replsets/secondary_as_sync_source.js b/jstests/replsets/secondary_as_sync_source.js new file mode 100644 index 00000000000..6f446842daa --- /dev/null +++ b/jstests/replsets/secondary_as_sync_source.js @@ -0,0 +1,88 @@ +/** + * Tests that a new replica set member performing an initial sync from a secondary node as the sync + * source, which has an in-progress index build will also build the index as part of the initial + * sync operation. + * @tags: [requires_replication] + */ +(function() { + 'use strict'; + + load("jstests/replsets/rslib.js"); + + const dbName = "test"; + const collName = "coll"; + + const firstIndexName = "_first"; + + function addTestDocuments(db) { + let size = 100; + jsTest.log("Creating " + size + " test documents."); + var bulk = db.getCollection(collName).initializeUnorderedBulkOp(); + for (var i = 0; i < size; ++i) { + bulk.insert({i: i}); + } + assert.writeOK(bulk.execute()); + } + + let replSet = new ReplSetTest({name: "indexBuilds", nodes: 2, useBridge: true}); + let nodes = replSet.nodeList(); + + replSet.startSet({startClean: true}); + replSet.initiate({ + _id: "indexBuilds", + members: [ + {_id: 0, host: nodes[0]}, + {_id: 1, host: nodes[1], votes: 0, priority: 0}, + ] + }); + + let primary = replSet.getPrimary(); + let primaryDB = primary.getDB(dbName); + + let secondary = replSet.getSecondary(); + let secondaryDB = secondary.getDB(dbName); + + addTestDocuments(primaryDB); + + jsTest.log("Hanging index builds on the secondary node"); + assert.commandWorked(secondaryDB.adminCommand( + {configureFailPoint: "hangAfterStartingIndexBuild", mode: "alwaysOn"})); + + jsTest.log("Beginning index build: " + firstIndexName); + assert.commandWorked(primaryDB.runCommand({ + createIndexes: collName, + indexes: [{key: {i: 1}, name: firstIndexName, background: true}], + writeConcern: {w: 2} + })); + + jsTest.log("Adding a new node to the replica set"); + let newNode = replSet.add({rsConfig: {votes: 0, priority: 0}}); + + // Ensure that the new node and primary cannot communicate to each other. + newNode.disconnect(primary); + + replSet.reInitiate(); + + // Wait for the new node to finish initial sync. + waitForState(newNode, ReplSetTest.State.SECONDARY); + + // Let the 'secondary' finish its index build. + jsTest.log("Removing index build hang on the secondary node to allow it to finish"); + assert.commandWorked( + secondaryDB.adminCommand({configureFailPoint: "hangAfterStartingIndexBuild", mode: "off"})); + + // Wait for the index builds to finish. + replSet.waitForAllIndexBuildsToFinish(dbName, collName); + jsTest.log("Checking if the indexes match between the new node and the secondary node"); + + let newNodeDB = newNode.getDB(dbName); + jsTest.log("New nodes indexes:"); + printjson(newNodeDB.getCollection(collName).getIndexes()); + jsTest.log("Secondary nodes indexes:"); + printjson(secondaryDB.getCollection(collName).getIndexes()); + + assert.eq(newNodeDB.getCollection(collName).getIndexes().length, + secondaryDB.getCollection(collName).getIndexes().length); + + replSet.stopSet(); +})(); diff --git a/src/mongo/shell/replsettest.js b/src/mongo/shell/replsettest.js index aeae8d76eec..5848b2f288e 100644 --- a/src/mongo/shell/replsettest.js +++ b/src/mongo/shell/replsettest.js @@ -1475,6 +1475,15 @@ var ReplSetTest = function(opts) { }, "awaiting replication", timeout); }; + this.waitForAllIndexBuildsToFinish = function(dbName, collName) { + // Run a no-op command and wait for it to be applied on secondaries. Due to the asynchronous + // completion nature of indexes on secondaries, we can guarantee an index build is complete + // on all secondaries once all secondaries have applied this collMod command. + assert.commandWorked(this.getPrimary().getDB(dbName).runCommand( + {collMod: collName, usePowerOf2Sizes: true})); + this.awaitReplication(); + }; + this.getHashesUsingSessions = function(sessions, dbName, { filterCapped: filterCapped = true, filterMapReduce: filterMapReduce = true, |