mirror of https://github.com/mongodb/mongo
136 lines
4.5 KiB
JavaScript
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();
|