Files
mongo/jstests/sharding/txn_two_phase_commit_primary_exit_drain.js
Pierlauro Sciarelli 3a627b048e SERVER-84422 Remove movePrimary calls from tests not needing it (#17774)
GitOrigin-RevId: ba30af34d315a11289855c8e09b7fd2155bb8be1
2023-12-27 13:46:13 +00:00

119 lines
4.4 KiB
JavaScript

/**
* Exercises the coordinator commands logic to test if a primary exits drain mode after the primary
* steps down during a basic two phase commit.
*
* @tags: [uses_transactions, uses_prepare_transaction, uses_multi_shard_transaction,
* multiversion_incompatible]
*/
import {configureFailPoint} from "jstests/libs/fail_point_util.js";
import {
checkDecisionIs,
checkDocumentDeleted
} from "jstests/sharding/libs/txn_two_phase_commit_util.js";
const dbName = "test";
const collName = "foo";
const ns = dbName + "." + collName;
let st = new ShardingTest({shards: 3, causallyConsistent: true});
let coordinator = st.shard0;
let participant1 = st.shard1;
let participant2 = st.shard2;
let lsid = {id: UUID()};
let txnNumber = 0;
const runCommitThroughMongosInParallelShellExpectSuccess = function() {
const runCommitExpectSuccessCode = "assert.commandWorked(db.adminCommand({" +
"commitTransaction: 1," +
"lsid: " + tojson(lsid) + "," +
"txnNumber: NumberLong(" + txnNumber + ")," +
"stmtId: NumberInt(0)," +
"autocommit: false," +
"}));";
return startParallelShell(runCommitExpectSuccessCode, st.s.port);
};
const setUp = function() {
// Create a sharded collection with a chunk on each shard:
// shard0: [-inf, 0)
// shard1: [0, 10)
// shard2: [10, +inf)
assert.commandWorked(
st.s.adminCommand({enableSharding: dbName, primaryShard: coordinator.shardName}));
assert.commandWorked(st.s.adminCommand({shardCollection: ns, key: {_id: 1}}));
assert.commandWorked(st.s.adminCommand({split: ns, middle: {_id: 0}}));
assert.commandWorked(st.s.adminCommand({split: ns, middle: {_id: 10}}));
assert.commandWorked(
st.s.adminCommand({moveChunk: ns, find: {_id: 0}, to: participant1.shardName}));
assert.commandWorked(
st.s.adminCommand({moveChunk: ns, find: {_id: 10}, to: participant2.shardName}));
// Start a new transaction by inserting a document onto each shard.
assert.commandWorked(st.s.getDB(dbName).runCommand({
insert: collName,
documents: [{_id: -5}, {_id: 5}, {_id: 15}],
lsid: lsid,
txnNumber: NumberLong(txnNumber),
stmtId: NumberInt(0),
startTransaction: true,
autocommit: false,
}));
};
const testCommitProtocol = function() {
jsTest.log("Testing two-phase commit");
txnNumber++;
setUp();
const coordinatorPrimary = coordinator.rs.getPrimary();
const hangBeforeWaitingForDecisionWriteConcernFp = configureFailPoint(
coordinatorPrimary, "hangBeforeWaitingForDecisionWriteConcern", {}, "alwaysOn");
let awaitResult = runCommitThroughMongosInParallelShellExpectSuccess();
// Check that the coordinator wrote the decision.
hangBeforeWaitingForDecisionWriteConcernFp.wait();
checkDecisionIs(coordinator, lsid, txnNumber, "commit");
assert.commandWorked(
coordinatorPrimary.adminCommand({replSetStepDown: ReplSetTest.kForeverSecs, force: true}));
// The replSetFreeze command will cause the node to run for primary on its own.
assert.commandWorked(coordinatorPrimary.adminCommand({replSetFreeze: 0}));
// The primary won't be able to exit drain mode while the
// hangBeforeWaitingForDecisionWriteConcern failpoint is active.
coordinator.rs.waitForState(coordinatorPrimary, ReplSetTest.State.PRIMARY);
const helloRes = assert.commandWorked(coordinatorPrimary.adminCommand("hello"));
assert.eq(false, helloRes.isWritablePrimary, helloRes);
hangBeforeWaitingForDecisionWriteConcernFp.off();
// However after the hangBeforeWaitingForDecisionWriteConcern failpoint is disabled the primary
// is expected to exit drain mode.
awaitResult();
// Check that the coordinator deleted its persisted state.
assert.soon(function() {
return checkDocumentDeleted(coordinator, lsid, txnNumber);
});
// Check that the transaction committed as expected.
jsTest.log("Verify that the transaction was committed on all shards.");
// Use assert.soon(), because although coordinateCommitTransaction currently blocks
// until the commit process is fully complete, it will eventually be changed to only
// block until the decision is *written*, so the documents may not be visible
// immediately.
assert.soon(function() {
return 3 === st.s.getDB(dbName).getCollection(collName).find().itcount();
});
};
testCommitProtocol();
st.stop();