mirror of https://github.com/mongodb/mongo
76 lines
2.5 KiB
JavaScript
76 lines
2.5 KiB
JavaScript
/**
|
|
* Tests that multi-documment transactions no longer race with stepdown over
|
|
* "setAlwaysInterruptAtStepDownOrUp".
|
|
* @tags: [uses_transactions]
|
|
*/
|
|
|
|
import {configureFailPoint} from "jstests/libs/fail_point_util.js";
|
|
import {ReplSetTest} from "jstests/libs/replsettest.js";
|
|
|
|
const rst = new ReplSetTest({nodes: 1});
|
|
rst.startSet();
|
|
rst.initiate();
|
|
|
|
const dbName = "testdb";
|
|
const collName = "testcoll";
|
|
|
|
const primary = rst.getPrimary();
|
|
const primaryDB = primary.getDB(dbName);
|
|
const primaryColl = primaryDB.getCollection(collName);
|
|
|
|
// Insert a document that we will later modify in a transaction.
|
|
assert.commandWorked(primaryColl.insert({a: 1}));
|
|
|
|
// In the first part of the race, we set the 'setAlwaysInterruptAtStepDownOrUp' too late,
|
|
// after stepDown is already done interrupting operations.
|
|
const txnFpBefore = configureFailPoint(primary, "hangBeforeSettingTxnInterruptFlag");
|
|
|
|
// The second critical part of the race is when the transaction thread has already passed
|
|
// the regular "not primary" checks by the time stepDown has completed and updated
|
|
// writability. (This is the reason we check writability again in the accompanying patch.)
|
|
const txnFpAfter = configureFailPoint(primary, "hangAfterCheckingWritabilityForMultiDocumentTransactions");
|
|
|
|
jsTestLog("Start the transaction in a parallel shell");
|
|
const txn = startParallelShell(() => {
|
|
const session = db.getMongo().startSession();
|
|
const sessionDB = session.getDatabase("testdb");
|
|
const sessionColl = sessionDB.getCollection("testcoll");
|
|
|
|
session.startTransaction();
|
|
assert.commandFailedWithCode(sessionColl.insert({b: 2}), ErrorCodes.NotWritablePrimary);
|
|
}, primary.port);
|
|
|
|
jsTestLog("Wait on the first transaction fail point");
|
|
txnFpBefore.wait();
|
|
|
|
const stepdownFP = configureFailPoint(primary, "stepdownHangAfterGrabbingRSTL");
|
|
|
|
jsTestLog("Issue a stepdown in a parallel shell");
|
|
const stepdown = startParallelShell(() => {
|
|
assert.commandWorked(db.adminCommand({replSetStepDown: 10 * 60, force: true}));
|
|
}, primary.port);
|
|
|
|
jsTestLog("Wait on the stepdown fail point");
|
|
stepdownFP.wait();
|
|
|
|
// The txn will be forced to wait for stepdown to finish.
|
|
jsTestLog("Release the first transaction fail point and wait in the second");
|
|
txnFpBefore.off();
|
|
txnFpAfter.wait();
|
|
|
|
jsTestLog("Let stepdown finish");
|
|
stepdownFP.off();
|
|
stepdown();
|
|
|
|
jsTestLog("Wait on the second transaction fail point");
|
|
txnFpAfter.wait();
|
|
|
|
jsTestLog("Let the transaction attempt finish");
|
|
txnFpAfter.off();
|
|
txn();
|
|
|
|
jsTestLog("Checking that the transaction never succeeded");
|
|
assert.eq(1, primaryColl.find().toArray().length);
|
|
|
|
rst.stopSet();
|