Files
mongo/jstests/core/txns/create_collection_parallel.js
Damian Wasilewicz 7c21b298e0 SERVER-100525: Audit unowned files for StorEx ownership (#34306)
GitOrigin-RevId: 617c7c11b17462c3ae24a23d22a9e2374cf191e6
2025-04-10 04:44:12 +00:00

244 lines
11 KiB
JavaScript

/**
* Tests parallel transactions with createCollections.
*
* @tags: [
* # The test runs commands that are not allowed with security token: endSession.
* not_allowed_with_signed_security_token,
* uses_transactions,
* ]
*/
import {withRetryOnTransientTxnError} from "jstests/libs/auto_retry_transaction_in_sharding.js";
import {FeatureFlagUtil} from "jstests/libs/feature_flag_util.js";
import {createCollAndCRUDInTxn} from "jstests/libs/txns/create_collection_txn_helpers.js";
const dbName = 'test_txns_create_collection_parallel';
function runParallelCollectionCreateTest(command, explicitCreate) {
const dbName = 'test_txns_create_collection_parallel';
const collName = "create_new_collection";
const distinctCollName = collName + "_second";
const session = db.getMongo().getDB(dbName).getMongo().startSession();
const secondSession = db.getMongo().getDB(dbName).getMongo().startSession();
let sessionDB = session.getDatabase(dbName);
let secondSessionDB = secondSession.getDatabase(dbName);
let sessionColl = sessionDB[collName];
sessionColl.drop({writeConcern: {w: "majority"}});
let distinctSessionColl = sessionDB[distinctCollName];
distinctSessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log("Testing duplicate createCollections, second createCollection fails");
withRetryOnTransientTxnError(
() => {
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
createCollAndCRUDInTxn(sessionDB, collName, command, explicitCreate);
jsTest.log("Committing transaction 1");
session.commitTransaction();
assert.eq(sessionColl.find({}).itcount(), 1);
assert.commandFailedWithCode(secondSessionDB.runCommand({create: collName}),
ErrorCodes.NamespaceExists);
assert.commandFailedWithCode(secondSession.abortTransaction_forTesting(),
ErrorCodes.NoSuchTransaction);
},
() => {
session.abortTransaction();
secondSession.abortTransaction();
sessionColl.drop({writeConcern: {w: "majority"}});
});
sessionColl.drop({writeConcern: {w: "majority"}});
distinctSessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log("Testing duplicate createCollections, where failing createCollection performs a " +
"successful operation earlier in the transaction.");
withRetryOnTransientTxnError(
() => {
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
createCollAndCRUDInTxn(secondSessionDB, distinctCollName, command, explicitCreate);
createCollAndCRUDInTxn(sessionDB, collName, command, explicitCreate);
jsTest.log("Committing transaction 1");
session.commitTransaction();
assert.eq(sessionColl.find({}).itcount(), 1);
// create cannot observe the collection created in the other transaction so the command
// will succeed and we will instead throw WCE when trying to commit the transaction.
assert.commandWorked(secondSessionDB.runCommand({create: collName}));
assert.commandFailedWithCode(secondSession.commitTransaction_forTesting(),
ErrorCodes.WriteConflict);
},
() => {
session.abortTransaction();
secondSession.abortTransaction();
sessionColl.drop({writeConcern: {w: "majority"}});
distinctSessionColl.drop({writeConcern: {w: "majority"}});
});
assert.eq(distinctSessionColl.find({}).itcount(), 0);
sessionColl.drop({writeConcern: {w: "majority"}});
distinctSessionColl.drop({writeConcern: {w: "majority"}});
// Prevent this test case in case of implicit tracking of collections. The DDL lock taken by the
// transaction won't be release until commit. This will cause the creation outside of a
// transaction (which will attempt to take the ddl lock as well) to wait indefinitely.
if (!TestData.implicitlyTrackUnshardedCollectionOnCreation) {
jsTest.log("Testing duplicate createCollections, one inside and one outside a txn");
withRetryOnTransientTxnError(
() => {
session.startTransaction({writeConcern: {w: "majority"}});
createCollAndCRUDInTxn(sessionDB, collName, command, explicitCreate);
assert.commandWorked(
secondSessionDB.runCommand({create: collName})); // outside txn
assert.commandWorked(secondSessionDB.getCollection(collName).insert({a: 1}));
jsTest.log("Committing transaction (SHOULD FAIL)");
assert.commandFailedWithCode(session.commitTransaction_forTesting(),
ErrorCodes.WriteConflict);
assert.eq(sessionColl.find({}).itcount(), 1);
},
() => {
session.abortTransaction();
sessionColl.drop({writeConcern: {w: "majority"}});
});
}
sessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log(
"Testing duplicate createCollections in parallel, both attempt to commit, second to commit fails");
withRetryOnTransientTxnError(
() => {
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
createCollAndCRUDInTxn(
secondSession.getDatabase(dbName), collName, command, explicitCreate);
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
createCollAndCRUDInTxn(sessionDB, collName, command, explicitCreate);
jsTest.log("Committing transaction 2");
secondSession.commitTransaction();
jsTest.log("Committing transaction 1 (SHOULD FAIL)");
assert.commandFailedWithCode(session.commitTransaction_forTesting(),
ErrorCodes.WriteConflict);
assert.eq(sessionColl.find({}).itcount(), 1);
},
() => {
try {
secondSession.abortTransaction();
session.abortTransaction();
} catch (e) {
// ignore
}
sessionColl.drop({writeConcern: {w: "majority"}});
});
sessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log("Testing duplicate createCollections which implicitly create databases in parallel" +
", both attempt to commit, second to commit fails");
assert.commandWorked(sessionDB.dropDatabase());
withRetryOnTransientTxnError(
() => {
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
createCollAndCRUDInTxn(
secondSession.getDatabase(dbName), collName, command, explicitCreate);
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
createCollAndCRUDInTxn(sessionDB, collName, command, explicitCreate);
jsTest.log("Committing transaction 2");
secondSession.commitTransaction();
jsTest.log("Committing transaction 1 (SHOULD FAIL)");
assert.commandFailedWithCode(session.commitTransaction_forTesting(),
ErrorCodes.WriteConflict);
assert.eq(sessionColl.find({}).itcount(), 1);
},
() => {
try {
secondSession.abortTransaction();
session.abortTransaction();
} catch (e) {
// ignore
}
sessionDB.dropDatabase();
});
sessionColl.drop({writeConcern: {w: "majority"}});
distinctSessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log("Testing createCollection conflict during commit, where the conflict rolls back a " +
"previously committed collection.");
withRetryOnTransientTxnError(
() => {
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
createCollAndCRUDInTxn(
secondSession.getDatabase(dbName), collName, command, explicitCreate);
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
createCollAndCRUDInTxn(
sessionDB, distinctCollName, command, explicitCreate); // does not conflict
createCollAndCRUDInTxn(sessionDB, collName, command, explicitCreate); // conflicts
jsTest.log("Committing transaction 2");
secondSession.commitTransaction();
jsTest.log("Committing transaction 1 (SHOULD FAIL)");
assert.commandFailedWithCode(session.commitTransaction_forTesting(),
ErrorCodes.WriteConflict);
assert.eq(sessionColl.find({}).itcount(), 1);
assert.eq(distinctSessionColl.find({}).itcount(), 0);
},
() => {
try {
secondSession.abortTransaction();
session.abortTransaction();
} catch (e) {
// ignore
}
sessionColl.drop({writeConcern: {w: "majority"}});
distinctSessionColl.drop({writeConcern: {w: "majority"}});
});
sessionColl.drop({writeConcern: {w: "majority"}});
distinctSessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log("Testing distinct createCollections in parallel, both successfully commit.");
withRetryOnTransientTxnError(
() => {
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
createCollAndCRUDInTxn(sessionDB, collName, command, explicitCreate);
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
createCollAndCRUDInTxn(secondSessionDB, distinctCollName, command, explicitCreate);
session.commitTransaction();
secondSession.commitTransaction();
},
() => {
try {
session.abortTransaction();
secondSession.abortTransaction();
} catch (e) {
// ignore
}
sessionColl.drop({writeConcern: {w: "majority"}});
distinctSessionColl.drop({writeConcern: {w: "majority"}});
});
secondSession.endSession();
session.endSession();
}
runParallelCollectionCreateTest("insert", true /*explicitCreate*/);
runParallelCollectionCreateTest("insert", false /*explicitCreate*/);
runParallelCollectionCreateTest("update", true /*explicitCreate*/);
runParallelCollectionCreateTest("update", false /*explicitCreate*/);
runParallelCollectionCreateTest("findAndModify", true /*explicitCreate*/);
runParallelCollectionCreateTest("findAndModify", false /*explicitCreate*/);