diff options
Diffstat (limited to 'jstests/replsets/inmemory_preserves_active_txns.js')
-rw-r--r-- | jstests/replsets/inmemory_preserves_active_txns.js | 196 |
1 files changed, 97 insertions, 99 deletions
diff --git a/jstests/replsets/inmemory_preserves_active_txns.js b/jstests/replsets/inmemory_preserves_active_txns.js index 2a5791b35ae..c05c24fb711 100644 --- a/jstests/replsets/inmemory_preserves_active_txns.js +++ b/jstests/replsets/inmemory_preserves_active_txns.js @@ -11,106 +11,104 @@ */ (function() { - "use strict"; - load("jstests/core/txns/libs/prepare_helpers.js"); - - // If the test runner passed --storageEngine=inMemory then we know inMemory is compiled into the - // server. We'll actually use both inMemory and wiredTiger storage engines. - const storageEngine = jsTest.options().storageEngine; - if (storageEngine !== 'inMemory') { - jsTestLog(`Skip test: storageEngine == "${storageEngine}", not "inMemory"`); - return; +"use strict"; +load("jstests/core/txns/libs/prepare_helpers.js"); + +// If the test runner passed --storageEngine=inMemory then we know inMemory is compiled into the +// server. We'll actually use both inMemory and wiredTiger storage engines. +const storageEngine = jsTest.options().storageEngine; +if (storageEngine !== 'inMemory') { + jsTestLog(`Skip test: storageEngine == "${storageEngine}", not "inMemory"`); + return; +} + +// A new replica set for both the commit and abort tests to ensure the same clean state. +function doTest(commitOrAbort) { + const replSet = new ReplSetTest({ + // Oplog can be truncated each "sync" cycle. Increase its frequency to once per second. + nodeOptions: {syncdelay: 1, setParameter: {logComponentVerbosity: tojson({storage: 1})}}, + nodes: [ + {storageEngine: "wiredTiger"}, + // inMemory node must not be a voter, otherwise lastCommitted never advances + {storageEngine: "inMemory", rsConfig: {priority: 0, votes: 0}}, + ], + waitForKeys: false + }); + + replSet.startSet(PrepareHelpers.replSetStartSetOptions); + replSet.initiateWithAnyNodeAsPrimary( + null, "replSetInitiate", {doNotWaitForStableRecoveryTimestamp: true}); + + const primary = replSet.getPrimary(); + const secondary = replSet.getSecondary(); + const primaryOplog = primary.getDB("local").oplog.rs; + assert.lte(primaryOplog.dataSize(), PrepareHelpers.oplogSizeBytes); + const secondaryOplog = secondary.getDB("local").oplog.rs; + assert.lte(secondaryOplog.dataSize(), PrepareHelpers.oplogSizeBytes); + + const coll = primary.getDB("test").test; + assert.commandWorked(coll.insert({})); + + jsTestLog("Prepare a transaction"); + + const session = primary.startSession(); + session.startTransaction(); + assert.commandWorked(session.getDatabase("test").test.insert({myTransaction: 1})); + const prepareTimestamp = PrepareHelpers.prepareTransaction(session); + + const oldestRequiredTimestampForCrashRecovery = + PrepareHelpers.getOldestRequiredTimestampForCrashRecovery(primary.getDB("test")); + assert.lte(oldestRequiredTimestampForCrashRecovery, prepareTimestamp); + + jsTestLog("Get transaction entry from config.transactions"); + + const txnEntry = primary.getDB("config").transactions.findOne(); + // The prepare oplog entry may or may not be the first oplog entry depending on packing. + assert.lte(txnEntry.startOpTime.ts, prepareTimestamp, tojson(txnEntry)); + + assert.soonNoExcept(() => { + const secondaryTxnEntry = secondary.getDB("config").transactions.findOne(); + assert(secondaryTxnEntry); + assert.eq(secondaryTxnEntry, txnEntry, tojson(secondaryTxnEntry)); + return true; + }); + + jsTestLog("Find prepare oplog entry"); + + const oplogEntry = PrepareHelpers.findPrepareEntry(primaryOplog); + assert.eq(oplogEntry.ts, prepareTimestamp, tojson(oplogEntry)); + // Must already be written on secondary, since the config.transactions entry is. + const secondaryOplogEntry = PrepareHelpers.findPrepareEntry(secondaryOplog); + assert.eq(secondaryOplogEntry.ts, prepareTimestamp, tojson(secondaryOplogEntry)); + + jsTestLog("Insert documents until oplog exceeds oplogSize"); + + // Oplog with prepared txn grows indefinitely - let it reach twice its supposed max size. + PrepareHelpers.growOplogPastMaxSize(replSet); + + jsTestLog(`Oplog dataSize = ${primaryOplog.dataSize()}, check the prepare entry still exists`); + + assert.eq(oplogEntry, PrepareHelpers.findPrepareEntry(primaryOplog)); + assert.soon(() => { + return secondaryOplog.dataSize() > PrepareHelpers.oplogSizeBytes; + }); + assert.eq(oplogEntry, PrepareHelpers.findPrepareEntry(secondaryOplog)); + + if (commitOrAbort === "commit") { + jsTestLog("Commit prepared transaction and wait for oplog to shrink to max oplogSize"); + PrepareHelpers.commitTransaction(session, prepareTimestamp); + } else if (commitOrAbort === "abort") { + jsTestLog("Abort prepared transaction and wait for oplog to shrink to max oplogSize"); + assert.commandWorked(session.abortTransaction_forTesting()); + } else { + throw new Error(`Unrecognized value for commitOrAbort: ${commitOrAbort}`); } - // A new replica set for both the commit and abort tests to ensure the same clean state. - function doTest(commitOrAbort) { - const replSet = new ReplSetTest({ - // Oplog can be truncated each "sync" cycle. Increase its frequency to once per second. - nodeOptions: - {syncdelay: 1, setParameter: {logComponentVerbosity: tojson({storage: 1})}}, - nodes: [ - {storageEngine: "wiredTiger"}, - // inMemory node must not be a voter, otherwise lastCommitted never advances - {storageEngine: "inMemory", rsConfig: {priority: 0, votes: 0}}, - ], - waitForKeys: false - }); - - replSet.startSet(PrepareHelpers.replSetStartSetOptions); - replSet.initiateWithAnyNodeAsPrimary( - null, "replSetInitiate", {doNotWaitForStableRecoveryTimestamp: true}); - - const primary = replSet.getPrimary(); - const secondary = replSet.getSecondary(); - const primaryOplog = primary.getDB("local").oplog.rs; - assert.lte(primaryOplog.dataSize(), PrepareHelpers.oplogSizeBytes); - const secondaryOplog = secondary.getDB("local").oplog.rs; - assert.lte(secondaryOplog.dataSize(), PrepareHelpers.oplogSizeBytes); - - const coll = primary.getDB("test").test; - assert.commandWorked(coll.insert({})); - - jsTestLog("Prepare a transaction"); - - const session = primary.startSession(); - session.startTransaction(); - assert.commandWorked(session.getDatabase("test").test.insert({myTransaction: 1})); - const prepareTimestamp = PrepareHelpers.prepareTransaction(session); - - const oldestRequiredTimestampForCrashRecovery = - PrepareHelpers.getOldestRequiredTimestampForCrashRecovery(primary.getDB("test")); - assert.lte(oldestRequiredTimestampForCrashRecovery, prepareTimestamp); - - jsTestLog("Get transaction entry from config.transactions"); - - const txnEntry = primary.getDB("config").transactions.findOne(); - // The prepare oplog entry may or may not be the first oplog entry depending on packing. - assert.lte(txnEntry.startOpTime.ts, prepareTimestamp, tojson(txnEntry)); - - assert.soonNoExcept(() => { - const secondaryTxnEntry = secondary.getDB("config").transactions.findOne(); - assert(secondaryTxnEntry); - assert.eq(secondaryTxnEntry, txnEntry, tojson(secondaryTxnEntry)); - return true; - }); - - jsTestLog("Find prepare oplog entry"); - - const oplogEntry = PrepareHelpers.findPrepareEntry(primaryOplog); - assert.eq(oplogEntry.ts, prepareTimestamp, tojson(oplogEntry)); - // Must already be written on secondary, since the config.transactions entry is. - const secondaryOplogEntry = PrepareHelpers.findPrepareEntry(secondaryOplog); - assert.eq(secondaryOplogEntry.ts, prepareTimestamp, tojson(secondaryOplogEntry)); - - jsTestLog("Insert documents until oplog exceeds oplogSize"); - - // Oplog with prepared txn grows indefinitely - let it reach twice its supposed max size. - PrepareHelpers.growOplogPastMaxSize(replSet); - - jsTestLog( - `Oplog dataSize = ${primaryOplog.dataSize()}, check the prepare entry still exists`); - - assert.eq(oplogEntry, PrepareHelpers.findPrepareEntry(primaryOplog)); - assert.soon(() => { - return secondaryOplog.dataSize() > PrepareHelpers.oplogSizeBytes; - }); - assert.eq(oplogEntry, PrepareHelpers.findPrepareEntry(secondaryOplog)); - - if (commitOrAbort === "commit") { - jsTestLog("Commit prepared transaction and wait for oplog to shrink to max oplogSize"); - PrepareHelpers.commitTransaction(session, prepareTimestamp); - } else if (commitOrAbort === "abort") { - jsTestLog("Abort prepared transaction and wait for oplog to shrink to max oplogSize"); - assert.commandWorked(session.abortTransaction_forTesting()); - } else { - throw new Error(`Unrecognized value for commitOrAbort: ${commitOrAbort}`); - } - - PrepareHelpers.awaitOplogTruncation(replSet); - - replSet.stopSet(); - } + PrepareHelpers.awaitOplogTruncation(replSet); + + replSet.stopSet(); +} - doTest("commit"); - doTest("abort"); +doTest("commit"); +doTest("abort"); })(); |