summaryrefslogtreecommitdiff
path: root/jstests/multiVersion/internal_sessions_downgrade.js
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/multiVersion/internal_sessions_downgrade.js')
-rw-r--r--jstests/multiVersion/internal_sessions_downgrade.js283
1 files changed, 283 insertions, 0 deletions
diff --git a/jstests/multiVersion/internal_sessions_downgrade.js b/jstests/multiVersion/internal_sessions_downgrade.js
new file mode 100644
index 00000000000..7b342b9b667
--- /dev/null
+++ b/jstests/multiVersion/internal_sessions_downgrade.js
@@ -0,0 +1,283 @@
+/*
+ * Test that internal sessions documents are properly removed from the config.transactions
+ * collection.
+ *
+ * @tags: [requires_fcv_51, featureFlagInternalTransactions]
+ */
+(function() {
+'use strict';
+
+const kConfigTxnNs = "config.transactions";
+const kDbName = "testDb";
+const kCollName = "testColl";
+
+(() => {
+ jsTest.log(
+ "Test downgrade updates existing parent session document with highest txnNumber of its " +
+ "child sessions");
+
+ const st = new ShardingTest({shards: {rs0: {nodes: 2}}});
+ const shard0Rst = st.rs0;
+ const shard0Primary = shard0Rst.getPrimary();
+
+ const testDB = shard0Primary.getDB(kDbName);
+
+ const sessionUUID = UUID();
+ const parentLsid = {id: sessionUUID};
+ const childLsid0 = {id: sessionUUID, txnNumber: NumberLong(5), txnUUID: UUID()};
+ const childLsid1 = {id: sessionUUID, txnNumber: NumberLong(6), txnUUID: UUID()};
+
+ // Create the parent and child sessions
+ assert.commandWorked(testDB.runCommand(
+ {insert: kCollName, documents: [{x: 0}], lsid: parentLsid, txnNumber: NumberLong(4)}));
+
+ assert.commandWorked(testDB.runCommand({
+ insert: kCollName,
+ documents: [{x: 1}],
+ lsid: childLsid0,
+ txnNumber: NumberLong(0),
+ startTransaction: true,
+ autocommit: false
+ }));
+
+ assert.commandWorked(testDB.adminCommand(
+ {commitTransaction: 1, lsid: childLsid0, txnNumber: NumberLong(0), autocommit: false}));
+
+ assert.commandWorked(testDB.runCommand({
+ insert: kCollName,
+ documents: [{x: 2}],
+ lsid: childLsid1,
+ txnNumber: NumberLong(0),
+ startTransaction: true,
+ autocommit: false
+ }));
+
+ assert.commandWorked(testDB.adminCommand(
+ {commitTransaction: 1, lsid: childLsid1, txnNumber: NumberLong(0), autocommit: false}));
+
+ const parentDocBeforeDowngrade =
+ shard0Primary.getCollection(kConfigTxnNs).findOne({"_id.id": sessionUUID});
+
+ assert.commandWorked(shard0Primary.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+
+ shard0Rst.nodes.forEach(node => {
+ // We expect every document except for the parent session documents to be deleted.
+ const collectionDocCount = node.getCollection(kConfigTxnNs).count();
+ assert.eq(collectionDocCount, 1);
+
+ const doc = node.getCollection(kConfigTxnNs).findOne({"_id.id": sessionUUID});
+ assert.eq(doc.txnNum, NumberLong(6));
+ assert.eq(doc.lastWriteOpTime.ts, Timestamp(1, 0));
+ assert.eq(doc.lastWriteOpTime.t, NumberLong(1));
+ assert.gte(doc.lastWriteDate, parentDocBeforeDowngrade.lastWriteDate);
+ });
+
+ st.stop();
+})();
+
+(() => {
+ jsTest.log(
+ "Test downgrade upserts new transaction document if relevant parent session document " +
+ "does not exist and does not modify unrelated transaction documents.");
+
+ const st = new ShardingTest({shards: {rs0: {nodes: 2}}});
+ const shard0Rst = st.rs0;
+ const shard0Primary = shard0Rst.getPrimary();
+
+ const kDbName = "testDb";
+ const kCollName = "testColl";
+ const testDB = shard0Primary.getDB(kDbName);
+
+ const sessionUUID = UUID();
+ const unrelatedParentLsid = {id: UUID()};
+ const childLsid0 = {id: sessionUUID, txnNumber: NumberLong(7), txnUUID: UUID()};
+ const childLsid1 = {id: sessionUUID, txnNumber: NumberLong(8), txnUUID: UUID()};
+
+ // Start a parent session without related children.
+ assert.commandWorked(testDB.runCommand({
+ insert: kCollName,
+ documents: [{x: 0}],
+ lsid: unrelatedParentLsid,
+ txnNumber: NumberLong(10)
+ }));
+
+ assert.commandWorked(testDB.runCommand({
+ insert: kCollName,
+ documents: [{x: 1}],
+ lsid: childLsid0,
+ txnNumber: NumberLong(0),
+ startTransaction: true,
+ autocommit: false
+ }));
+
+ assert.commandWorked(testDB.adminCommand(
+ {commitTransaction: 1, lsid: childLsid0, txnNumber: NumberLong(0), autocommit: false}));
+
+ assert.commandWorked(testDB.runCommand({
+ insert: kCollName,
+ documents: [{x: 2}],
+ lsid: childLsid1,
+ txnNumber: NumberLong(0),
+ startTransaction: true,
+ autocommit: false
+ }));
+
+ assert.commandWorked(testDB.adminCommand(
+ {commitTransaction: 1, lsid: childLsid1, txnNumber: NumberLong(0), autocommit: false}));
+
+ const unrelatedParentDocBeforeDowngrade =
+ shard0Primary.getCollection(kConfigTxnNs).findOne({"_id.id": unrelatedParentLsid.id});
+
+ assert.commandWorked(shard0Primary.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+
+ shard0Rst.nodes.forEach(node => {
+ // We expect every document except for the parent session documents to be deleted.
+ const collectionDocCount = node.getCollection(kConfigTxnNs).count();
+ assert.eq(collectionDocCount, 2);
+
+ const upsertedDoc = node.getCollection(kConfigTxnNs).findOne({"_id.id": sessionUUID});
+ assert.eq(upsertedDoc.txnNum, NumberLong(8));
+ assert.eq(upsertedDoc.lastWriteOpTime.ts, Timestamp(1, 0));
+ assert.eq(upsertedDoc.lastWriteOpTime.t, NumberLong(1));
+
+ const unrelatedParentDocAfterDowngrade =
+ node.getCollection(kConfigTxnNs).findOne({"_id.id": unrelatedParentLsid.id});
+ assert.eq(unrelatedParentDocAfterDowngrade, unrelatedParentDocBeforeDowngrade);
+
+ // For newly upserted session documents, we use the current wall clock time as the
+ // lastWriteDate, thus we expect it to be farther ahead than the unchanged session document.
+ assert.gte(upsertedDoc.lastWriteDate, unrelatedParentDocAfterDowngrade.lastWriteDate);
+ });
+
+ st.stop();
+})();
+
+(() => {
+ jsTest.log(
+ "Test downgrade does not modify a parent session document if it has a higher txnNumber " +
+ "than its children.");
+
+ const st = new ShardingTest({shards: {rs0: {nodes: 2}}});
+ const shard0Rst = st.rs0;
+ const shard0Primary = shard0Rst.getPrimary();
+
+ const kDbName = "testDb";
+ const kCollName = "testColl";
+ const testDB = shard0Primary.getDB(kDbName);
+
+ const sessionUUID = UUID();
+ const parentLsid = {id: sessionUUID};
+ const childLsid0 = {id: sessionUUID, txnNumber: NumberLong(11), txnUUID: UUID()};
+ const childLsid1 = {id: sessionUUID, txnNumber: NumberLong(12), txnUUID: UUID()};
+
+ // Start a parent session without related children.
+ assert.commandWorked(testDB.runCommand(
+ {insert: kCollName, documents: [{x: 0}], lsid: parentLsid, txnNumber: NumberLong(13)}));
+
+ assert.commandWorked(testDB.runCommand({
+ insert: kCollName,
+ documents: [{x: 1}],
+ lsid: childLsid0,
+ txnNumber: NumberLong(0),
+ startTransaction: true,
+ autocommit: false
+ }));
+
+ assert.commandWorked(testDB.adminCommand(
+ {commitTransaction: 1, lsid: childLsid0, txnNumber: NumberLong(0), autocommit: false}));
+
+ assert.commandWorked(testDB.runCommand({
+ insert: kCollName,
+ documents: [{x: 2}],
+ lsid: childLsid1,
+ txnNumber: NumberLong(0),
+ startTransaction: true,
+ autocommit: false
+ }));
+
+ const parentDocBeforeDowngrade =
+ shard0Primary.getCollection(kConfigTxnNs).findOne({"_id.id": sessionUUID});
+
+ assert.commandWorked(testDB.adminCommand(
+ {commitTransaction: 1, lsid: childLsid1, txnNumber: NumberLong(0), autocommit: false}));
+
+ assert.commandWorked(shard0Primary.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+
+ shard0Rst.nodes.forEach(node => {
+ // We expect every document except for the parent session documents to be deleted.
+ const collectionDocCount = node.getCollection(kConfigTxnNs).count();
+ assert.eq(collectionDocCount, 1);
+
+ const parentDocAfterDowngrade =
+ shard0Primary.getCollection(kConfigTxnNs).findOne({"_id.id": sessionUUID});
+ assert.eq(parentDocAfterDowngrade, parentDocBeforeDowngrade);
+ });
+
+ st.stop();
+})();
+
+(() => {
+ jsTest.log("Test downgrade modifies a parent session document if it has a txnNumber equal to " +
+ " the highest txnNumber of its children.");
+
+ const st = new ShardingTest({shards: {rs0: {nodes: 2}}});
+ const shard0Rst = st.rs0;
+ const shard0Primary = shard0Rst.getPrimary();
+
+ const kDbName = "testDb";
+ const kCollName = "testColl";
+ const testDB = shard0Primary.getDB(kDbName);
+
+ const sessionUUID = UUID();
+ const parentLsid = {id: sessionUUID};
+ const childLsid0 = {id: sessionUUID, txnNumber: NumberLong(13), txnUUID: UUID()};
+ const childLsid1 = {id: sessionUUID, txnNumber: NumberLong(14), txnUUID: UUID()};
+
+ // Start a parent session without related children.
+ assert.commandWorked(testDB.runCommand(
+ {insert: kCollName, documents: [{x: 0}], lsid: parentLsid, txnNumber: NumberLong(14)}));
+
+ assert.commandWorked(testDB.runCommand({
+ insert: kCollName,
+ documents: [{x: 1}],
+ lsid: childLsid0,
+ txnNumber: NumberLong(0),
+ startTransaction: true,
+ autocommit: false
+ }));
+
+ assert.commandWorked(testDB.adminCommand(
+ {commitTransaction: 1, lsid: childLsid0, txnNumber: NumberLong(0), autocommit: false}));
+
+ assert.commandWorked(testDB.runCommand({
+ insert: kCollName,
+ documents: [{x: 2}],
+ lsid: childLsid1,
+ txnNumber: NumberLong(0),
+ startTransaction: true,
+ autocommit: false
+ }));
+
+ assert.commandWorked(testDB.adminCommand(
+ {commitTransaction: 1, lsid: childLsid1, txnNumber: NumberLong(0), autocommit: false}));
+
+ const parentDocBeforeDowngrade =
+ shard0Primary.getCollection(kConfigTxnNs).findOne({"_id.id": sessionUUID});
+
+ assert.commandWorked(shard0Primary.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+
+ shard0Rst.nodes.forEach(node => {
+ // We expect every document except for the parent session documents to be deleted.
+ const collectionDocCount = node.getCollection(kConfigTxnNs).count();
+ assert.eq(collectionDocCount, 1);
+
+ const doc = node.getCollection(kConfigTxnNs).findOne({"_id.id": sessionUUID});
+ assert.eq(doc.txnNum, NumberLong(14));
+ assert.eq(doc.lastWriteOpTime.ts, Timestamp(1, 0));
+ assert.eq(doc.lastWriteOpTime.t, NumberLong(1));
+ assert.gte(doc.lastWriteDate, parentDocBeforeDowngrade.lastWriteDate);
+ });
+
+ st.stop();
+})();
+})();