mongo/jstests/sharding/transactions_expiration.js

80 lines
2.8 KiB
JavaScript

// Tests that a transaction expires and is then aborted by the server. Uses the server parameter
// 'transactionLifetimeLimitSeconds' to lower the transaction lifetime for quicker transaction
// expiration. This is the mongos version for: jstests/core/txns/abort_expired_transaction.js.
//
// @tags: [uses_transactions, uses_multi_shard_transaction]
import {withRetryOnTransientTxnError} from "jstests/libs/auto_retry_transaction_in_sharding.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
let st = new ShardingTest({shards: 2});
assert.commandWorked(st.s.adminCommand({enableSharding: "test", primaryShard: st.shard0.name}));
assert.commandWorked(st.s.adminCommand({shardCollection: "test.user", key: {x: 1}}));
assert.commandWorked(st.s.adminCommand({split: "test.user", middle: {x: 0}}));
assert.commandWorked(st.s.adminCommand({moveChunk: "test.user", find: {x: 0}, to: st.shard1.name}));
let lowerTxnTimeout = (conn) => {
assert.commandWorked(conn.getDB("admin").runCommand({setParameter: 1, transactionLifetimeLimitSeconds: 1}));
};
st.rs0.nodes.forEach(lowerTxnTimeout);
st.rs1.nodes.forEach(lowerTxnTimeout);
let testDB = st.s.getDB("test");
// Create the collections in the shards outside the transactions.
assert.commandWorked(testDB.runCommand({insert: "user", documents: [{x: -1}, {x: 1}], writeConcern: {w: "majority"}}));
const session = st.s.startSession();
const sessionDb = session.getDatabase("test");
let txnNumber = 0;
withRetryOnTransientTxnError(() => {
txnNumber++;
assert.commandWorked(
sessionDb.runCommand({
insert: "user",
documents: [{x: -10}, {x: 10}],
txnNumber: NumberLong(txnNumber),
startTransaction: true,
autocommit: false,
}),
);
});
// We can deterministically wait for the transaction to be aborted by waiting for currentOp
// to cease reporting the inactive transaction: the transaction should disappear from the
// currentOp results once aborted.
assert.soon(function () {
const sessionFilter = {
active: false,
opid: {$exists: false},
desc: "inactive transaction",
"transaction.parameters.txnNumber": NumberLong(txnNumber),
"lsid.id": session.getSessionId().id,
};
const priConn = st.rs0.getPrimary();
const res = priConn
.getDB("admin")
.aggregate([{$currentOp: {allUsers: true, idleSessions: true}}, {$match: sessionFilter}]);
return res.itcount() == 0;
}, "currentOp reports that the idle transaction still exists, it has not been " + "aborted as expected.");
assert.commandFailedWithCode(
sessionDb.runCommand({
insert: "user",
documents: [{x: -100}, {x: 100}],
txnNumber: NumberLong(txnNumber),
autocommit: false,
}),
ErrorCodes.NoSuchTransaction,
);
session.endSession();
st.stop();