summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorJason Chan <jason.chan@10gen.com>2021-05-12 14:58:22 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-05-12 21:19:06 +0000
commite18366d160ee7e44dc3e82e18fb69cf91eda915b (patch)
tree11972be32f05b1270aaa8b39640fe41f1f84758d /jstests
parent70299e858e3f54c01fdb96cdd1c430972500b97f (diff)
downloadmongo-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.js3
-rw-r--r--jstests/replsets/retryable_writes_initial_sync.js127
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();
+}());