mirror of https://github.com/mongodb/mongo
203 lines
5.6 KiB
JavaScript
203 lines
5.6 KiB
JavaScript
/**
|
|
* Verify the states that a multi-statement transaction can be restarted on at the active
|
|
* transaction number for servers in a sharded cluster.
|
|
*
|
|
* @tags: [requires_sharding, uses_transactions, uses_prepare_transaction]
|
|
*/
|
|
|
|
import {ShardingTest} from "jstests/libs/shardingtest.js";
|
|
|
|
// This test requires running transactions directly against the shard.
|
|
TestData.replicaSetEndpointIncompatible = true;
|
|
|
|
const collName = "restart_transactions";
|
|
|
|
function runTest(routerDB, directDB) {
|
|
// Set up the underlying collection.
|
|
const routerColl = routerDB[collName];
|
|
assert.commandWorked(routerDB.createCollection(routerColl.getName(), {writeConcern: {w: "majority"}}));
|
|
|
|
// Read from the mongoS to ensure the shard has refreshed its filtering information.
|
|
assert.eq(0, routerDB.getCollection(collName).countDocuments({}));
|
|
|
|
//
|
|
// Can restart a transaction that has been aborted.
|
|
//
|
|
|
|
let txnNumber = 0;
|
|
assert.commandWorked(
|
|
directDB.runCommand({
|
|
find: collName,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
startTransaction: true,
|
|
}),
|
|
);
|
|
assert.commandWorked(
|
|
directDB.adminCommand({abortTransaction: 1, txnNumber: NumberLong(txnNumber), autocommit: false}),
|
|
);
|
|
|
|
assert.commandWorked(
|
|
directDB.runCommand({
|
|
find: collName,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
startTransaction: true,
|
|
}),
|
|
);
|
|
|
|
//
|
|
// Cannot restart a transaction that is in progress.
|
|
//
|
|
|
|
txnNumber++;
|
|
assert.commandWorked(
|
|
directDB.runCommand({
|
|
find: collName,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
startTransaction: true,
|
|
}),
|
|
);
|
|
|
|
assert.commandFailedWithCode(
|
|
directDB.runCommand({
|
|
find: collName,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
startTransaction: true,
|
|
}),
|
|
50911,
|
|
);
|
|
|
|
//
|
|
// Cannot restart a transaction that has completed a retryable write.
|
|
//
|
|
|
|
txnNumber++;
|
|
assert.commandWorked(
|
|
directDB.runCommand({insert: collName, documents: [{x: txnNumber}], txnNumber: NumberLong(txnNumber)}),
|
|
);
|
|
|
|
assert.commandFailedWithCode(
|
|
directDB.runCommand({
|
|
find: collName,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
startTransaction: true,
|
|
}),
|
|
50911,
|
|
);
|
|
|
|
//
|
|
// Cannot restart a transaction that has been committed.
|
|
//
|
|
|
|
txnNumber++;
|
|
assert.commandWorked(
|
|
directDB.runCommand({
|
|
find: collName,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
startTransaction: true,
|
|
}),
|
|
);
|
|
assert.commandWorked(
|
|
directDB.adminCommand({
|
|
commitTransaction: 1,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
writeConcern: {w: "majority"},
|
|
}),
|
|
);
|
|
|
|
assert.commandFailedWithCode(
|
|
directDB.runCommand({
|
|
find: collName,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
startTransaction: true,
|
|
}),
|
|
50911,
|
|
);
|
|
|
|
//
|
|
// Cannot restart a transaction that has been prepared.
|
|
//
|
|
|
|
txnNumber++;
|
|
assert.commandWorked(
|
|
directDB.runCommand({
|
|
find: collName,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
startTransaction: true,
|
|
}),
|
|
);
|
|
assert.commandWorked(
|
|
directDB.adminCommand({prepareTransaction: 1, txnNumber: NumberLong(txnNumber), autocommit: false}),
|
|
);
|
|
|
|
assert.commandFailedWithCode(
|
|
directDB.runCommand({
|
|
find: collName,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
startTransaction: true,
|
|
}),
|
|
50911,
|
|
);
|
|
|
|
assert.commandWorked(
|
|
directDB.adminCommand({abortTransaction: 1, txnNumber: NumberLong(txnNumber), autocommit: false}),
|
|
);
|
|
|
|
//
|
|
// Cannot restart a transaction that has been aborted after being prepared.
|
|
//
|
|
|
|
txnNumber++;
|
|
assert.commandWorked(
|
|
directDB.runCommand({
|
|
find: collName,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
startTransaction: true,
|
|
}),
|
|
);
|
|
assert.commandWorked(
|
|
directDB.adminCommand({prepareTransaction: 1, txnNumber: NumberLong(txnNumber), autocommit: false}),
|
|
);
|
|
assert.commandWorked(
|
|
directDB.adminCommand({abortTransaction: 1, txnNumber: NumberLong(txnNumber), autocommit: false}),
|
|
);
|
|
|
|
assert.commandFailedWithCode(
|
|
directDB.runCommand({
|
|
find: collName,
|
|
txnNumber: NumberLong(txnNumber),
|
|
autocommit: false,
|
|
startTransaction: true,
|
|
}),
|
|
50911,
|
|
);
|
|
}
|
|
|
|
const st = new ShardingTest({shards: 1, mongos: 1});
|
|
|
|
// Directly connect to the shard primary to simulate internal retries by mongos.
|
|
const shardDBName = "test";
|
|
const shardSession = st.rs0.getPrimary().startSession({causalConsistency: false});
|
|
const shardDB = shardSession.getDatabase(shardDBName);
|
|
|
|
runTest(st.s.getDB(shardDBName), shardDB);
|
|
|
|
// Directly connect to the config sever primary to simulate internal retries by mongos.
|
|
const configDBName = "config";
|
|
const configSession = st.configRS.getPrimary().startSession({causalConsistency: false});
|
|
const configDB = configSession.getDatabase(configDBName);
|
|
|
|
runTest(st.s.getDB(configDBName), configDB);
|
|
|
|
st.stop();
|