Files
mongo/jstests/core/txns/create_indexes_parallel.js

196 lines
9.4 KiB
JavaScript

/**
* Tests parallel transactions with createIndexes.
*
* @tags: [
* uses_transactions,
* ]
*/
(function() {
"use strict";
load("jstests/libs/auto_retry_transaction_in_sharding.js");
load("jstests/libs/create_index_txn_helpers.js");
let doParallelCreateIndexesTest = function(explicitCollectionCreate, multikeyIndex) {
const dbName = 'test_txns_create_indexes_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];
let secondSessionColl = secondSessionDB[collName];
sessionColl.drop({writeConcern: {w: "majority"}});
secondSessionColl.drop({writeConcern: {w: "majority"}});
let distinctSessionColl = sessionDB[distinctCollName];
distinctSessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log("Testing duplicate sequential createIndexes, both succeed");
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
retryOnceOnTransientAndRestartTxnOnMongos(session, () => {
createIndexAndCRUDInTxn(sessionDB, collName, explicitCollectionCreate, multikeyIndex);
}, {writeConcern: {w: "majority"}});
jsTest.log("Committing transaction 1");
session.commitTransaction();
assert.eq(sessionColl.find({}).itcount(), 1);
assert.eq(sessionColl.getIndexes().length, 2);
// Ensuring existing index succeeds.
assert.commandWorked(
secondSessionColl.runCommand({createIndexes: collName, indexes: [indexSpecs]}));
secondSession.commitTransaction();
assert.eq(sessionColl.find({}).itcount(), 1);
assert.eq(sessionColl.getIndexes().length, 2);
sessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log("Testing conflicting sequential createIndexes, second fails");
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
retryOnceOnTransientAndRestartTxnOnMongos(secondSession, () => {
createIndexAndCRUDInTxn(secondSessionDB, collName, explicitCollectionCreate, multikeyIndex);
}, {writeConcern: {w: "majority"}});
jsTest.log("Committing transaction 2");
secondSession.commitTransaction();
assert.eq(secondSessionColl.find({}).itcount(), 1);
assert.eq(secondSessionColl.getIndexes().length, 2);
assert.commandFailedWithCode(
sessionColl.runCommand({createIndexes: collName, indexes: [conflictingIndexSpecs]}),
ErrorCodes.IndexKeySpecsConflict);
assert.commandFailedWithCode(session.abortTransaction_forTesting(),
ErrorCodes.NoSuchTransaction);
assert.eq(sessionColl.find({}).itcount(), 1);
assert.eq(sessionColl.getIndexes().length, 2);
distinctSessionColl.drop({writeConcern: {w: "majority"}});
sessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log("Testing conflicting sequential createIndexes, where failing createIndexes " +
"performs a successful index creation earlier in the transaction.");
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
retryOnceOnTransientAndRestartTxnOnMongos(session, () => {
createIndexAndCRUDInTxn(
sessionDB, distinctCollName, explicitCollectionCreate, multikeyIndex);
}, {writeConcern: {w: "majority"}});
retryOnceOnTransientAndRestartTxnOnMongos(secondSession, () => {
createIndexAndCRUDInTxn(secondSessionDB, collName, explicitCollectionCreate, multikeyIndex);
}, {writeConcern: {w: "majority"}});
jsTest.log("Committing transaction 2");
secondSession.commitTransaction();
assert.eq(secondSessionColl.find({}).itcount(), 1);
assert.eq(secondSessionColl.getIndexes().length, 2);
// createIndexes takes minimum visible snapshots of new collections into consideration when
// checking for existing indexes.
assert.commandFailedWithCode(
sessionColl.runCommand({createIndexes: collName, indexes: [conflictingIndexSpecs]}),
ErrorCodes.SnapshotUnavailable);
assert.commandFailedWithCode(session.abortTransaction_forTesting(),
ErrorCodes.NoSuchTransaction);
assert.eq(sessionColl.find({}).itcount(), 1);
assert.eq(sessionColl.getIndexes().length, 2);
assert.eq(distinctSessionColl.find({}).itcount(), 0);
assert.eq(distinctSessionColl.getIndexes().length, 0);
distinctSessionColl.drop({writeConcern: {w: "majority"}});
sessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log(
"Testing duplicate createIndexes in parallel, both attempt to commit, second to commit fails");
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
retryOnceOnTransientAndRestartTxnOnMongos(secondSession, () => {
createIndexAndCRUDInTxn(secondSessionDB, collName, explicitCollectionCreate, multikeyIndex);
}, {writeConcern: {w: "majority"}});
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
retryOnceOnTransientAndRestartTxnOnMongos(session, () => {
createIndexAndCRUDInTxn(sessionDB, collName, explicitCollectionCreate, multikeyIndex);
}, {writeConcern: {w: "majority"}});
jsTest.log("Committing transaction 2");
secondSession.commitTransaction();
jsTest.log("Committing transaction 1 (SHOULD FAIL)");
// WriteConflict occurs here because in all test cases (i.e., explicitCollectionCreate is true
// versus false), we must create a collection as part of each transaction. The conflicting
// collection creation causes the WriteConflict.
assert.commandFailedWithCode(session.commitTransaction_forTesting(), ErrorCodes.WriteConflict);
assert.eq(sessionColl.find({}).itcount(), 1);
assert.eq(sessionColl.getIndexes().length, 2);
sessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log("Testing createIndexes inside txn and createCollection on conflicting collection " +
"in parallel.");
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
retryOnceOnTransientAndRestartTxnOnMongos(session, () => {
createIndexAndCRUDInTxn(sessionDB, collName, explicitCollectionCreate, multikeyIndex);
}, {writeConcern: {w: "majority"}});
assert.commandWorked(secondSessionDB.createCollection(collName));
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);
assert.eq(sessionColl.getIndexes().length, 1);
assert.commandWorked(sessionDB.dropDatabase());
jsTest.log("Testing duplicate createIndexes which implicitly create a database in parallel" +
", both attempt to commit, second to commit fails");
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
retryOnceOnTransientAndRestartTxnOnMongos(secondSession, () => {
createIndexAndCRUDInTxn(secondSessionDB, collName, explicitCollectionCreate, multikeyIndex);
}, {writeConcern: {w: "majority"}});
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
retryOnceOnTransientAndRestartTxnOnMongos(session, () => {
createIndexAndCRUDInTxn(sessionDB, collName, explicitCollectionCreate, multikeyIndex);
}, {writeConcern: {w: "majority"}});
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(sessionColl.getIndexes().length, 2);
sessionColl.drop({writeConcern: {w: "majority"}});
secondSessionColl.drop({writeConcern: {w: "majority"}});
distinctSessionColl.drop({writeConcern: {w: "majority"}});
jsTest.log("Testing distinct createIndexes in parallel, both successfully commit.");
session.startTransaction({writeConcern: {w: "majority"}}); // txn 1
retryOnceOnTransientAndRestartTxnOnMongos(session, () => {
createIndexAndCRUDInTxn(sessionDB, collName, explicitCollectionCreate, multikeyIndex);
}, {writeConcern: {w: "majority"}});
secondSession.startTransaction({writeConcern: {w: "majority"}}); // txn 2
retryOnceOnTransientAndRestartTxnOnMongos(secondSession, () => {
createIndexAndCRUDInTxn(
secondSessionDB, distinctCollName, explicitCollectionCreate, multikeyIndex);
}, {writeConcern: {w: "majority"}});
session.commitTransaction();
secondSession.commitTransaction();
secondSession.endSession();
session.endSession();
};
doParallelCreateIndexesTest(false /*explicitCollectionCreate*/, false /*multikeyIndex*/);
doParallelCreateIndexesTest(true /*explicitCollectionCreate*/, false /*multikeyIndex*/);
doParallelCreateIndexesTest(false /*explicitCollectionCreate*/, true /*multikeyIndex*/);
doParallelCreateIndexesTest(true /*explicitCollectionCreate*/, true /*multikeyIndex*/);
}());