jstests/sharding/internal_txns/retryable_writes_retry_conflict.js
/*
 * Runs a write statement inside a retryable internal transaction and then runs 'retryFunc' to
 * resend the write statement while the transaction is still open. Verifies that the retry is
 * blocked until the transaction commits or aborts and does not cause the write statement to execute
 * more than once.
 */
Runs a write statement inside a retryable internal transaction and then runs 'retryFunc' to
resend the write statement while the transaction is still open. Verifies that the retry is
blocked until the transaction commits or aborts and does not cause the write statement to execute
more than once.
Runs a write statement inside a retryable internal transaction and then runs ' retryFunc ' to resend the write statement while the transaction is still open . Verifies that the retry is blocked until the transaction commits or aborts and does not cause the write statement to execute more than once .
function testBlockingRetry(retryFunc, testOpts = {
    prepareBeforeRetry,
    abortAfterBlockingRetry,
    stepDownPrimaryAfterBlockingRetry
}) {
    jsTest.log("Test blocking retry with test options " + tojson(testOpts));
    const parentTxnNumber = currentParentTxnNumber++;
    const docToInsert = {x: 1};
    const stmtId = 1;
    const childLsid = {id: parentLsid.id, txnNumber: NumberLong(parentTxnNumber), txnUUID: UUID()};
    const childTxnNumber = NumberLong(0);
    const originalWriteCmdObj = {
        insert: kCollName,
        documents: [docToInsert],
        lsid: childLsid,
        txnNumber: NumberLong(childTxnNumber),
        startTransaction: true,
        autocommit: false,
        stmtId: NumberInt(stmtId),
    };
    const prepareCmdObj = makePrepareTransactionCmdObj(childLsid, childTxnNumber);
    const commitCmdObj = makeCommitTransactionCmdObj(childLsid, childTxnNumber);
    const abortCmdObj = makeAbortTransactionCmdObj(childLsid, childTxnNumber);
    assert.commandWorked(shard0TestDB.runCommand(originalWriteCmdObj));
    if (testOpts.prepareBeforeRetry) {
        const preparedTxnRes = assert.commandWorked(shard0Primary.adminCommand(prepareCmdObj));
        commitCmdObj.commitTimestamp = preparedTxnRes.prepareTimestamp;
    }
    const fp = configureFailPoint(
        shard0Primary, "waitAfterNewStatementBlocksBehindOpenInternalTransactionForRetryableWrite");
    const retryThread = new Thread(retryFunc, {
        shard0RstArgs: createRstArgs(st.rs0),
        parentSessionUUIDString: extractUUIDFromObject(parentLsid.id),
        parentTxnNumber,
        docToInsert,
        stmtId,
        dbName: kDbName,
        collName: kCollName,
        stepDownPrimaryAfterBlockingRetry: testOpts.stepDownPrimaryAfterBlockingRetry
    });
    retryThread.start();
    fp.wait();
    fp.off();
    if (testOpts.stepDownPrimaryAfterBlockingRetry) {
        stepDownShard0Primary();
    }
    assert.commandWorked(
        shard0TestDB.adminCommand(testOpts.abortAfterBlockingRetry ? abortCmdObj : commitCmdObj));
    retryThread.join();
    assert.eq(shard0TestColl.count(docToInsert), 1);
    assert.commandWorked(mongosTestColl.remove({}));
}
function testBlockingRetry ( retryFunc , testOpts = { prepareBeforeRetry , abortAfterBlockingRetry , stepDownPrimaryAfterBlockingRetry } ) { jsTest . log ( "Test blocking retry with test options " + tojson ( testOpts ) ) ; const parentTxnNumber = currentParentTxnNumber ++ ; const docToInsert = { x : 1 } ; const stmtId = 1 ; const childLsid = { id : parentLsid . id , txnNumber : NumberLong ( parentTxnNumber ) , txnUUID : UUID ( ) } ; const childTxnNumber = NumberLong ( 0 ) ; const originalWriteCmdObj = { insert : kCollName , documents : [ docToInsert ] , lsid : childLsid , txnNumber : NumberLong ( childTxnNumber ) , startTransaction : true , autocommit : false , stmtId : NumberInt ( stmtId ) , } ; const prepareCmdObj = makePrepareTransactionCmdObj ( childLsid , childTxnNumber ) ; const commitCmdObj = makeCommitTransactionCmdObj ( childLsid , childTxnNumber ) ; const abortCmdObj = makeAbortTransactionCmdObj ( childLsid , childTxnNumber ) ; assert . commandWorked ( shard0TestDB . runCommand ( originalWriteCmdObj ) ) ; if ( testOpts . prepareBeforeRetry ) { const preparedTxnRes = assert . commandWorked ( shard0Primary . adminCommand ( prepareCmdObj ) ) ; commitCmdObj . commitTimestamp = preparedTxnRes . prepareTimestamp ; } const fp = configureFailPoint ( shard0Primary , "waitAfterNewStatementBlocksBehindOpenInternalTransactionForRetryableWrite" ) ; const retryThread = new Thread ( retryFunc , { shard0RstArgs : createRstArgs ( st . rs0 ) , parentSessionUUIDString : extractUUIDFromObject ( parentLsid . id ) , parentTxnNumber , docToInsert , stmtId , dbName : kDbName , collName : kCollName , stepDownPrimaryAfterBlockingRetry : testOpts . stepDownPrimaryAfterBlockingRetry } ) ; retryThread . start ( ) ; fp . wait ( ) ; fp . off ( ) ; if ( testOpts . stepDownPrimaryAfterBlockingRetry ) { stepDownShard0Primary ( ) ; } assert . commandWorked ( shard0TestDB . adminCommand ( testOpts . abortAfterBlockingRetry ? abortCmdObj : commitCmdObj ) ) ; retryThread . join ( ) ; assert . eq ( shard0TestColl . count ( docToInsert ) , 1 ) ; assert . commandWorked ( mongosTestColl . remove ( { } ) ) ; }
Runs a write statement inside a retryable internal transaction and then runs 'retryFunc' to
 resend the write statement while the transaction is still open.
Runs a write statement inside a retryable internal transaction and then runs ' retryFunc ' to resend the write statement while the transaction is still open .
// Start a retryable internal transaction. // Retry and wait for it to block behind the internal transaction above. // Commit or abort the internal transaction, and verify that the write statement executed // exactly once despite the concurrent retry.