From 79df037ceb43882726e9484b9ab8b1c23c538034 Mon Sep 17 00:00:00 2001 From: Jason Carey Date: Tue, 12 Sep 2017 17:54:48 -0400 Subject: SERVER-31011 Provide transaction record deletion hook --- jstests/core/views/views_all_commands.js | 1 + jstests/noPassthrough/transaction_reaper.js | 149 +++++++++++++++++++++ .../sharding/safe_secondary_reads_drop_recreate.js | 1 + ...eads_single_migration_suspend_range_deletion.js | 1 + ...condary_reads_single_migration_waitForDelete.js | 1 + 5 files changed, 153 insertions(+) create mode 100644 jstests/noPassthrough/transaction_reaper.js (limited to 'jstests') diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js index f73f5180522..b56d61fe7a7 100644 --- a/jstests/core/views/views_all_commands.js +++ b/jstests/core/views/views_all_commands.js @@ -482,6 +482,7 @@ }, stageDebug: {skip: isAnInternalCommand}, startSession: {skip: isAnInternalCommand}, + reapLogicalSessionCacheNow: {skip: isAnInternalCommand}, refreshLogicalSessionCacheNow: {skip: isAnInternalCommand}, refreshSessions: {skip: isUnrelated}, refreshSessionsInternal: {skip: isAnInternalCommand}, diff --git a/jstests/noPassthrough/transaction_reaper.js b/jstests/noPassthrough/transaction_reaper.js new file mode 100644 index 00000000000..c9a9e992cb2 --- /dev/null +++ b/jstests/noPassthrough/transaction_reaper.js @@ -0,0 +1,149 @@ +(function() { + 'use strict'; + + function Repl(lifetime) { + this.rst = new ReplSetTest({ + nodes: 1, + nodeOptions: {setParameter: {TransactionRecordMinimumLifetimeMinutes: lifetime}}, + }); + this.rst.startSet(); + this.rst.initiate(); + } + + Repl.prototype.stop = function() { + this.rst.stopSet(); + }; + + Repl.prototype.getConn = function() { + return this.rst.getPrimary(); + }; + + Repl.prototype.getTransactionConn = function() { + return this.rst.getPrimary(); + }; + + function Sharding(lifetime) { + this.st = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + other: { + rs: true, + rsOptions: {setParameter: {TransactionRecordMinimumLifetimeMinutes: lifetime}}, + rs0: {nodes: 1}, + }, + }); + + this.st.s0.getDB("admin").runCommand({enableSharding: "test"}); + this.st.s0.getDB("admin").runCommand({shardCollection: "test.test", key: {_id: 1}}); + } + + Sharding.prototype.stop = function() { + this.st.stop(); + }; + + Sharding.prototype.getConn = function() { + return this.st.s0; + }; + + Sharding.prototype.getTransactionConn = function() { + return this.st.rs0.getPrimary(); + }; + + const nSessions = 1500; + + function Fixture(impl) { + this.impl = impl; + this.conn = impl.getConn(); + this.transactionConn = impl.getTransactionConn(); + + this.sessions = []; + + for (var i = 0; i < nSessions; i++) { + // make a session and get it to the collection + var session = this.conn.startSession({retryWrites: 1}); + session.getDatabase("test").test.count({}); + this.sessions.push(session); + } + + this.refresh(); + this.assertOutstandingTransactions(0); + this.assertOutstandingSessions(nSessions); + + for (var i = 0; i < nSessions; i++) { + // make a session and get it to the collection + var session = this.sessions[i]; + session.getDatabase("test").test.save({a: 1}); + } + + // Ensure a write flushes a transaction + this.assertOutstandingTransactions(nSessions); + this.assertOutstandingSessions(nSessions); + + // Ensure a refresh/reap doesn't remove the transaction + this.refresh(); + this.reap(); + this.assertOutstandingTransactions(nSessions); + this.assertOutstandingSessions(nSessions); + } + + Fixture.prototype.assertOutstandingTransactions = function(count) { + assert.eq(count, this.transactionConn.getDB("config").transactions.count()); + }; + + Fixture.prototype.assertOutstandingSessions = function(count) { + assert.eq(count, this.getDB("admin").system.sessions.count()); + }; + + Fixture.prototype.refresh = function() { + assert.commandWorked(this.getDB("admin").runCommand({refreshLogicalSessionCacheNow: 1})); + }; + + Fixture.prototype.reap = function() { + assert.commandWorked( + this.transactionConn.getDB("admin").runCommand({reapLogicalSessionCacheNow: 1})); + }; + + Fixture.prototype.getDB = function(db) { + return this.conn.getDB(db); + }; + + Fixture.prototype.stop = function() { + this.sessions.forEach(function(session) { + session.endSession(); + }); + return this.impl.stop(); + }; + + [Repl, Sharding].forEach(function(Impl) { + { + var fixture = new Fixture(new Impl(-1)); + // Remove a session + fixture.getDB("admin").system.sessions.remove({}); + fixture.assertOutstandingTransactions(nSessions); + fixture.assertOutstandingSessions(0); + + // See the transaction get reaped as a result + fixture.reap(); + fixture.assertOutstandingTransactions(0); + fixture.assertOutstandingSessions(0); + + fixture.stop(); + } + + { + var fixture = new Fixture(new Impl(30)); + // Remove a session + fixture.getDB("admin").system.sessions.remove({}); + fixture.assertOutstandingTransactions(nSessions); + fixture.assertOutstandingSessions(0); + + // See the transaction was not reaped as a result + fixture.reap(); + fixture.assertOutstandingTransactions(nSessions); + fixture.assertOutstandingSessions(0); + + fixture.stop(); + } + }); +})(); diff --git a/jstests/sharding/safe_secondary_reads_drop_recreate.js b/jstests/sharding/safe_secondary_reads_drop_recreate.js index 43f6c8974ba..8410b1652f3 100644 --- a/jstests/sharding/safe_secondary_reads_drop_recreate.js +++ b/jstests/sharding/safe_secondary_reads_drop_recreate.js @@ -256,6 +256,7 @@ planCacheSetFilter: {skip: "does not return user data"}, profile: {skip: "primary only"}, reIndex: {skip: "does not return user data"}, + reapLogicalSessionCacheNow: {skip: "does not return user data"}, refreshLogicalSessionCacheNow: {skip: "does not return user data"}, refreshSessions: {skip: "does not return user data"}, refreshSessionsInternal: {skip: "does not return user data"}, diff --git a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js index f1b036997f4..9e1d7fe6309 100644 --- a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js +++ b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js @@ -293,6 +293,7 @@ planCacheSetFilter: {skip: "does not return user data"}, profile: {skip: "primary only"}, reIndex: {skip: "does not return user data"}, + reapLogicalSessionCacheNow: {skip: "does not return user data"}, refreshLogicalSessionCacheNow: {skip: "does not return user data"}, refreshSessions: {skip: "does not return user data"}, refreshSessionsInternal: {skip: "does not return user data"}, diff --git a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js index 763d95f7bd9..710841c2e36 100644 --- a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js +++ b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js @@ -259,6 +259,7 @@ planCacheListQueryShapes: {skip: "does not return user data"}, planCacheSetFilter: {skip: "does not return user data"}, profile: {skip: "primary only"}, + reapLogicalSessionCacheNow: {skip: "does not return user data"}, refreshLogicalSessionCacheNow: {skip: "does not return user data"}, refreshSessions: {skip: "does not return user data"}, refreshSessionsInternal: {skip: "does not return user data"}, -- cgit v1.2.1