diff options
Diffstat (limited to 'jstests/replsets/update_commit_point_from_sync_source_ignores_term.js')
-rw-r--r-- | jstests/replsets/update_commit_point_from_sync_source_ignores_term.js | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/jstests/replsets/update_commit_point_from_sync_source_ignores_term.js b/jstests/replsets/update_commit_point_from_sync_source_ignores_term.js new file mode 100644 index 00000000000..7915dfd4b7b --- /dev/null +++ b/jstests/replsets/update_commit_point_from_sync_source_ignores_term.js @@ -0,0 +1,87 @@ +/** + * Tests that even if the sync source's lastOpCommitted is in a higher term than the node's + * lastApplied, the node can update its own lastOpCommitted to its lastApplied. + * @tags: [requires_majority_read_concern] + */ +(function() { + "use strict"; + + load("jstests/libs/write_concern_util.js"); // for [stop|restart]ServerReplication. + + const dbName = "test"; + const collName = "coll"; + + // Set up a ReplSetTest where nodes only sync one oplog entry at a time. + const rst = new ReplSetTest( + {nodes: 5, useBridge: true, nodeOptions: {setParameter: "bgSyncOplogFetcherBatchSize=1"}}); + rst.startSet(); + const config = rst.getReplSetConfig(); + // Ban chaining and prevent elections. + config.settings = {chainingAllowed: false, electionTimeoutMillis: 12 * 60 * 60 * 1000}; + rst.initiate(config); + + const nodeA = rst.nodes[0]; + const nodeB = rst.nodes[1]; + const nodeC = rst.nodes[2]; + const nodeD = rst.nodes[3]; + const nodeE = rst.nodes[4]; + + jsTest.log("Node A is primary in term 1. Replicate a write to Node E that is not committed."); + assert.eq(nodeA, rst.getPrimary()); + // Ensure Node E has a majority committed snapshot. + assert.commandWorked(nodeA.getDB(dbName)[collName].insert({_id: "dummy"})); + rst.awaitLastOpCommitted(); + stopServerReplication([nodeB, nodeC, nodeD]); + assert.commandWorked(nodeA.getDB(dbName)[collName].insert({_id: "term 1, doc 1"})); + rst.awaitReplication(undefined, undefined, [nodeE]); + assert.eq(0, + nodeE.getDB(dbName)[collName] + .find({_id: "term 1, doc 1"}) + .readConcern("majority") + .itcount()); + + jsTest.log("Disconnect Node E. Perform a new write."); + nodeE.disconnect([nodeA, nodeB, nodeC, nodeD]); + restartServerReplication([nodeB, nodeC, nodeD]); + assert.commandWorked(nodeA.getDB(dbName)[collName].insert({_id: "term 1, doc 2"})); + + jsTest.log("Step up Node B in term 2. Commit a new write."); + // Ensure Node B is caught up, so that it can become primary. + rst.awaitReplication(undefined, undefined, [nodeB]); + assert.commandWorked(nodeB.adminCommand({replSetStepUp: 1})); + rst.waitForState(nodeA, ReplSetTest.State.SECONDARY); + assert.eq(nodeB, rst.getPrimary()); + assert.commandWorked( + nodeB.getDB(dbName)[collName].insert({_id: "term 2"}, {writeConcern: {w: "majority"}})); + // Node E might sync from Node A or Node B. Ensure they both have the new commit point. + rst.awaitLastOpCommitted(undefined, [nodeA]); + + jsTest.log("Allow Node E to replicate the last write from term 1."); + // The stopReplProducerOnDocument failpoint ensures that Node E stops replicating before + // applying the document {msg: "new primary"}, which is the first document of term 2. This + // depends on the oplog fetcher batch size being 1. + assert.commandWorked(nodeE.adminCommand({ + configureFailPoint: "stopReplProducerOnDocument", + mode: "alwaysOn", + data: {document: {msg: "new primary"}} + })); + nodeE.reconnect([nodeA, nodeB, nodeC, nodeD]); + assert.soon(() => { + return nodeE.getDB(dbName)[collName].find({_id: "term 1, doc 2"}).itcount() === 1; + }); + assert.eq(0, nodeE.getDB(dbName)[collName].find({_id: "term 2"}).itcount()); + + jsTest.log("Node E now knows that its first write is majority committed."); + // It does not yet know that {_id: "term 1, doc 2"} is committed. Its last batch was {_id: "term + // 1, doc 2"}. The sync source's lastOpCommitted was in term 2, so Node E updated its + // lastOpCommitted to its lastApplied, which did not yet include {_id: "term 1, doc 2"}. + assert.eq(1, + nodeE.getDB(dbName)[collName] + .find({_id: "term 1, doc 1"}) + .readConcern("majority") + .itcount()); + + assert.commandWorked( + nodeE.adminCommand({configureFailPoint: "stopReplProducerOnDocument", mode: "off"})); + rst.stopSet(); +}()); |