mongo/jstests/replsets/retryable_writes_initial_sy...

134 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]
*/
(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});
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();
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.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": 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();
}());