diff options
author | Jason Chan <jason.chan@10gen.com> | 2021-05-12 14:58:22 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-05-12 21:19:06 +0000 |
commit | e18366d160ee7e44dc3e82e18fb69cf91eda915b (patch) | |
tree | 11972be32f05b1270aaa8b39640fe41f1f84758d /jstests | |
parent | 70299e858e3f54c01fdb96cdd1c430972500b97f (diff) | |
download | mongo-e18366d160ee7e44dc3e82e18fb69cf91eda915b.tar.gz |
SERVER-56713 Avoid creating retryable findAndModify images while in initial sync
Diffstat (limited to 'jstests')
-rw-r--r-- | jstests/noPassthrough/store_retryable_find_and_modify_images_in_side_collection.js | 3 | ||||
-rw-r--r-- | jstests/replsets/retryable_writes_initial_sync.js | 127 |
2 files changed, 128 insertions, 2 deletions
diff --git a/jstests/noPassthrough/store_retryable_find_and_modify_images_in_side_collection.js b/jstests/noPassthrough/store_retryable_find_and_modify_images_in_side_collection.js index 26c49a816c4..b1bb008c285 100644 --- a/jstests/noPassthrough/store_retryable_find_and_modify_images_in_side_collection.js +++ b/jstests/noPassthrough/store_retryable_find_and_modify_images_in_side_collection.js @@ -44,8 +44,7 @@ function checkImageCollection(conn, sessionInfo, expectedTs, expectedImage, expectedImageKind) { const coll = conn.getDB('config').image_collection; - const imageDoc = - coll.findOne({'_id.id': sessionInfo.sessionId}); + const imageDoc = coll.findOne({'_id.id': sessionInfo.sessionId}); assert.eq(sessionInfo.txnNum, imageDoc.txnNum, imageDoc); assert.eq(expectedImage, imageDoc.image, imageDoc); diff --git a/jstests/replsets/retryable_writes_initial_sync.js b/jstests/replsets/retryable_writes_initial_sync.js new file mode 100644 index 00000000000..b6a663dc319 --- /dev/null +++ b/jstests/replsets/retryable_writes_initial_sync.js @@ -0,0 +1,127 @@ +/** + * Tests that retryable findAndModify data stored in the `config.image_collection` side collection + * do not get populated by nodes doing oplog application while in initial sync. + */ +(function() { + 'use strict'; + + load('jstests/replsets/rslib.js'); + + // A secondary cannot compute retryable images during initial sync. Thus we skip db hash checks + // as + // its expected for config.image_collection to not match. + TestData.skipCheckDBHashes = true; + + // Start a single node replica set. + const rst = new ReplSetTest( + {nodes: 1, nodeOptions: {setParameter: {storeFindAndModifyImagesInSideCollection: true}}}); + rst.startSet(); + rst.initiateWithHighElectionTimeout(); + + const dbName = jsTest.name(); + const primary = rst.getPrimary(); + const primaryDB = primary.getDB(dbName); + const primaryColl = primaryDB['collection']; + + primaryColl.insert({_id: 1}); + + let lsid = UUID(); + let result = assert.commandWorked(primaryDB.runCommand({ + findandmodify: primaryColl.getName(), + lsid: {id: lsid}, + txnNumber: NumberLong(1), + stmtId: NumberInt(1), + query: {_id: 1}, + new: false, + update: {$set: {preInitialSync: true}} + })); + jsTestLog("Pre-initial sync retryable findAndModify: " + tojson(result)); + + jsTestLog("Adding a new voting node (node1) to the replica set."); + const node1 = rst.add({ + rsConfig: {priority: 1, votes: 1}, + setParameter: {'failpoint.initialSyncHangAfterDataCloning': tojson({mode: 'alwaysOn'})} + }); + rst.reInitiate(); + + jsTestLog("Wait for node1 to hang during initial sync."); + checkLog.contains(node1, 'initial sync - initialSyncHangAfterDataCloning fail point enabled.'); + + // Perform a findAndModify update that will not be retryable on the node that's concurrently + // initial syncing. + result = assert.commandWorked(primaryDB.runCommand({ + findandmodify: primaryColl.getName(), + lsid: {id: lsid}, + txnNumber: NumberLong(2), + stmtId: NumberInt(1), + query: {_id: 1}, + new: false, + update: {$set: {duringInitialSync: true}} + })); + jsTestLog("Retryable findAndModify during initial sync" + tojson(result)); + + // With a separate logical session, perform a findAndModify removal that will not be retryable + // on the node that's concurrently initial syncing. + let otherLsid = UUID(); + result = assert.commandWorked(primaryDB.runCommand({ + findandmodify: primaryColl.getName(), + lsid: {id: otherLsid}, + txnNumber: NumberLong(3), + stmtId: NumberInt(1), + query: {_id: 1}, + new: false, + remove: true + })); + jsTestLog("Retryable findAndModify removal during initial sync: " + tojson(result)); + + jsTestLog("Resuming initial sync."); + assert.commandWorked( + node1.adminCommand({configureFailPoint: "initialSyncHangAfterDataCloning", mode: 'off'})); + rst.waitForState(node1, ReplSetTest.State.SECONDARY); + + let initialSyncedNode = rst.getSecondary(); + rst.stepUp(initialSyncedNode); + + result = assert.commandFailedWithCode(initialSyncedNode.getDB(dbName).runCommand({ + findandmodify: primaryColl.getName(), + lsid: {id: lsid}, + txnNumber: NumberLong(2), + stmtId: NumberInt(1), + query: {_id: 1}, + new: false, + update: {$set: {duringInitialSync: true}} + }), + ErrorCodes.IncompleteTransactionHistory); + // Assert that retrying the update fails. + jsTestLog( + "Secondary: " + initialSyncedNode + " Data: " + + tojson(initialSyncedNode.getDB(dbName)['collection'].findOne()) + " Image: " + + tojson(initialSyncedNode.getDB("config")['image_collection'].findOne({"_id.id": lsid})) + + " retried findAndModify against synced node: " + result); + + result = assert.commandFailedWithCode(initialSyncedNode.getDB(dbName).runCommand({ + findandmodify: primaryColl.getName(), + lsid: {id: otherLsid}, + txnNumber: NumberLong(3), + stmtId: NumberInt(1), + query: {_id: 1}, + new: false, + remove: true + }), + ErrorCodes.IncompleteTransactionHistory); + // Assert that retrying the delete fails. + jsTestLog("Secondary: " + initialSyncedNode + " Data: " + + tojson(initialSyncedNode.getDB(dbName)['collection'].findOne()), + " Image: " + tojson(initialSyncedNode.getDB("config")['image_collection'].findOne( + {"_id.id": otherLsid})) + + " retried delete against synced node: " + result); + + // There should be two sessions/image entries on the initial syncing node, and both should be + // flagged as invalidated. + assert.eq(2, initialSyncedNode.getDB('config')['image_collection'].count({invalidated: true})); + assert.eq(2, + initialSyncedNode.getDB('config')['image_collection'].count( + {invalidatedReason: "initial sync"})); + + rst.stopSet(); +}()); |