SERVER-115594: Skip acquiring tickets when deleting txn coordinator doc (#45383)

GitOrigin-RevId: e2076b84636dca92d2c2486f4ecd6a1f773c4d43
This commit is contained in:
Xuerui Fa 2025-12-19 08:01:37 -05:00 committed by MongoDB Bot
parent 24608b289f
commit 8d25b18e24
3 changed files with 38 additions and 0 deletions

View File

@ -111,6 +111,8 @@ last-continuous:
ticket: SERVER-103955
- test_file: jstests/sharding/query/javascript_heap_limit.js
ticket: SERVER-109200
- test_file: jstests/sharding/coordinate_txn_commit_with_tickets_exhausted.js
ticket: SERVER-115594
suites: null
last-lts:
all:
@ -724,4 +726,6 @@ last-lts:
ticket: SERVER-103955
- test_file: jstests/sharding/query/javascript_heap_limit.js
ticket: SERVER-109200
- test_file: jstests/sharding/coordinate_txn_commit_with_tickets_exhausted.js
ticket: SERVER-115594
suites: null

View File

@ -53,6 +53,27 @@ assert.commandWorked(sourceCollection.insert([{key: 200}, {key: -200}]));
const txnCoordinator = st.rs1.getPrimary();
// Create a thread which leaves the TransactionCoordinator in a state right before it tries to delete the coordinator doc. Set up a failpoint for after deleting the coordinator doc because commitTransaction will return before deleting the coordinator, and we want to ensure that we wait for the deletion to finish before we allow the test to proceed.
const hangBeforeDeletingCoordinatorDocFp = configureFailPoint(txnCoordinator, "hangBeforeDeletingCoordinatorDoc");
const hangAfterDeletingCoordinatorDocFp = configureFailPoint(txnCoordinator, "hangAfterDeletingCoordinatorDoc");
const deleteCoordinatorDocThread = new Thread(
function runTwoPhaseCommitTxn(host, dbName, collName) {
const conn = new Mongo(host);
const session = conn.startSession({causalConsistency: false});
const sessionCollection = session.getDatabase(dbName).getCollection(collName);
session.startTransaction();
assert.commandWorked(sessionCollection.insert({key: 400}));
assert.commandWorked(sessionCollection.insert({key: -400}));
assert.commandWorked(session.commitTransaction_forTesting());
},
st.s.host,
sourceCollection.getDB().getName(),
sourceCollection.getName(),
);
deleteCoordinatorDocThread.start();
hangBeforeDeletingCoordinatorDocFp.wait();
// Create a thread which leaves the TransactionCoordinator in a state where prepareTransaction has
// been run on both participant shards and it is about to write the commit decision locally to the
// config.transaction_coordinators collection.
@ -132,6 +153,15 @@ assert.soon(
() => `Failed to find prepare conflicts in $currentOp output: ${tojson(currentOp())}`,
);
// The commitTransaction command should not wait for the coordinator doc to be deleted.
deleteCoordinatorDocThread.join();
// Allow the deleteCoordinatorDocThread to proceed with deleting the doc. This tests that we skip write ticket acquisition for deleting the doc.
hangBeforeDeletingCoordinatorDocFp.off();
jsTestLog("Waiting for deleteCoordinatorDocThread to successfully delete the coordinator doc");
hangAfterDeletingCoordinatorDocFp.wait();
hangAfterDeletingCoordinatorDocFp.off();
// Allow the commitTxnThread to proceed with preparing the transaction. This tests that we skip
// write ticket acquisition when preparing a transaction.
hangBeforeWritingParticipantListFp.off();

View File

@ -695,6 +695,10 @@ Future<void> deleteCoordinatorDoc(txn::AsyncWorkScheduler& scheduler,
[&scheduler, lsid, txnNumberAndRetryCounter] {
return scheduler.scheduleWork(
[lsid, txnNumberAndRetryCounter](OperationContext* opCtx) {
// Skip ticket acquisition to avoid a bottleneck on deleting the coordinator doc
// in cases of high transaction concurrency.
ScopedAdmissionPriority<ExecutionAdmissionContext> skipTicketAcquisition(
opCtx, AdmissionContext::Priority::kExempt);
getTransactionCoordinatorWorkerCurOpRepository()->set(
opCtx,
lsid,