mongo/jstests/replsets/retryable_writes_initial_sy...

136 lines
4.5 KiB
JavaScript

/**
* 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.
*
* This setParameter behavior does not yet exist on earlier versions.
* @tags: [multiversion_incompatible]
*/
import {ReplSetTest} from "jstests/libs/replsettest.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});
rst.startSet();
rst.initiate();
const dbName = jsTest.name();
const primary = rst.getPrimary();
const primaryDB = primary.getDB(dbName);
const primaryColl = primaryDB["collection"];
primaryColl.insert({_id: 1});
let lsid = UUID();
jsTestLog({
"Pre-initial sync retryable findAndModify": 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("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.containsJson(node1, 21184);
// Perform a findAndModify update that will not be retryable on the node that's concurrently initial
// syncing.
let 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": 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();
jsTestLog({
"Retryable findAndModify removal during initial sync": assert.commandWorked(
primaryDB.runCommand({
findandmodify: primaryColl.getName(),
lsid: {id: otherLsid},
txnNumber: NumberLong(3),
stmtId: NumberInt(1),
query: {_id: 1},
new: false,
remove: true,
}),
),
});
jsTestLog("Resuming initial sync.");
assert.commandWorked(node1.adminCommand({configureFailPoint: "initialSyncHangAfterDataCloning", mode: "off"}));
rst.awaitSecondaryNodes(null, [node1]);
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": initialSyncedNode.getDB(dbName)["collection"].findOne(),
"Image": 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": initialSyncedNode.getDB(dbName)["collection"].findOne(),
"Image": 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();