diff options
author | Xiangyu Yao <xiangyu.yao@mongodb.com> | 2018-04-03 18:27:56 -0400 |
---|---|---|
committer | Xiangyu Yao <xiangyu.yao@mongodb.com> | 2018-04-17 12:03:10 -0400 |
commit | fcf41ce8ddf70894ed6803420e94a1685cc60903 (patch) | |
tree | 79de3abcf16f4ad6b9029c7ff3a63504963bb338 | |
parent | dc4832736957d840760af6557d65dcf28cd81063 (diff) | |
download | mongo-fcf41ce8ddf70894ed6803420e94a1685cc60903.tar.gz |
SERVER-34094 Change snapshot read tests to use multi-statement transactions
-rw-r--r-- | jstests/noPassthrough/afterClusterTime_committed_reads.js | 2 | ||||
-rw-r--r-- | jstests/noPassthrough/agg_explain_read_concern.js | 2 | ||||
-rw-r--r-- | jstests/noPassthrough/readConcern_snapshot.js | 95 | ||||
-rw-r--r-- | jstests/noPassthrough/read_concern_snapshot_aggregation.js | 26 | ||||
-rw-r--r-- | jstests/noPassthrough/read_concern_snapshot_catalog_invalidation.js | 13 | ||||
-rw-r--r-- | jstests/noPassthrough/read_concern_snapshot_yielding.js | 2 | ||||
-rw-r--r-- | jstests/noPassthrough/read_majority.js | 45 | ||||
-rw-r--r-- | jstests/noPassthrough/snapshot_cursor_integrity.js | 83 | ||||
-rw-r--r-- | jstests/noPassthrough/snapshot_cursor_shutdown_stepdown.js | 11 | ||||
-rw-r--r-- | jstests/noPassthrough/snapshot_reads.js | 83 | ||||
-rw-r--r-- | src/mongo/shell/query.js | 1 |
11 files changed, 188 insertions, 175 deletions
diff --git a/jstests/noPassthrough/afterClusterTime_committed_reads.js b/jstests/noPassthrough/afterClusterTime_committed_reads.js index 3f6843a93cb..b02f748f5d0 100644 --- a/jstests/noPassthrough/afterClusterTime_committed_reads.js +++ b/jstests/noPassthrough/afterClusterTime_committed_reads.js @@ -1,3 +1,5 @@ +// TODO: SERVER-34388 Simplify this test by wrapping all the statements +// in one transaction once a failing command won't abort the transaction // Test that causally consistent majority-committed reads will wait for the majority commit point to // move past 'afterClusterTime'. // @tags: [requires_replication] diff --git a/jstests/noPassthrough/agg_explain_read_concern.js b/jstests/noPassthrough/agg_explain_read_concern.js index c5b7e2b8621..ac379b6efb2 100644 --- a/jstests/noPassthrough/agg_explain_read_concern.js +++ b/jstests/noPassthrough/agg_explain_read_concern.js @@ -1,3 +1,5 @@ +// TODO: SERVER-34388 Simplify this test by wrapping all the statements +// in one transaction once a failing command won't abort the transaction /** * Test that explained aggregation commands behave correctly with the readConcern option. */ diff --git a/jstests/noPassthrough/readConcern_snapshot.js b/jstests/noPassthrough/readConcern_snapshot.js index 8f7187d26c7..e06aac95371 100644 --- a/jstests/noPassthrough/readConcern_snapshot.js +++ b/jstests/noPassthrough/readConcern_snapshot.js @@ -10,6 +10,8 @@ // Configurations. // + // TODO: SERVER-34388 - convert this to txn api when we can do failing + // command in a transaction. // readConcern 'snapshot' should fail on storage engines that do not support it. let rst = new ReplSetTest({nodes: 1}); rst.startSet(); @@ -28,6 +30,8 @@ session.endSession(); rst.stopSet(); + // TODO: SERVER-34388 - convert this to txn api when we can do failing + // command in a transaction. // readConcern 'snapshot' should fail for autocommit:true transactions when test // 'enableTestCommands' is set to false. jsTest.setOption('enableTestCommands', false); @@ -45,6 +49,8 @@ session.endSession(); rst.stopSet(); + // TODO: SERVER-34388 - convert this to txn api when we can do failing + // command in a transaction. // readConcern 'snapshot' is not allowed on a standalone. const conn = MongoRunner.runMongod(); session = conn.startSession({causalConsistency: false}); @@ -61,33 +67,41 @@ rst = new ReplSetTest({nodes: 2}); rst.startSet(); rst.initiate(); + assert.commandWorked(rst.getPrimary().getDB(dbName).runCommand( + {create: collName, writeConcern: {w: "majority"}})); session = rst.getPrimary().getDB(dbName).getMongo().startSession({causalConsistency: false}); sessionDb = session.getDatabase(dbName); - let txnNumber = 0; - assert.commandWorked(sessionDb.coll.insert({}, {writeConcern: {w: "majority"}})); - assert.commandWorked(sessionDb.runCommand( - {find: collName, readConcern: {level: "snapshot"}, txnNumber: NumberLong(txnNumber++)})); + session.startTransaction({writeConcern: {w: "majority"}, readConcern: {level: "snapshot"}}); + assert.commandWorked(sessionDb.coll.insert({})); + assert.commandWorked(sessionDb.runCommand({find: collName})); + session.commitTransaction(); // readConcern 'snapshot' is allowed with 'afterClusterTime'. + session.startTransaction(); let pingRes = assert.commandWorked(rst.getPrimary().adminCommand({ping: 1})); assert(pingRes.hasOwnProperty("$clusterTime"), tojson(pingRes)); assert(pingRes.$clusterTime.hasOwnProperty("clusterTime"), tojson(pingRes)); assert.commandWorked(sessionDb.runCommand({ find: collName, - readConcern: {level: "snapshot", afterClusterTime: pingRes.$clusterTime.clusterTime}, - txnNumber: NumberLong(txnNumber++) + readConcern: {level: "snapshot", afterClusterTime: pingRes.$clusterTime.clusterTime} })); + session.commitTransaction(); // readConcern 'snapshot' is not allowed with 'afterOpTime'. + session.startTransaction(); assert.commandFailedWithCode(sessionDb.runCommand({ find: collName, - readConcern: {level: "snapshot", afterOpTime: {ts: Timestamp(1, 2), t: 1}}, - txnNumber: NumberLong(txnNumber++) + readConcern: {level: "snapshot", afterOpTime: {ts: Timestamp(1, 2), t: 1}} }), ErrorCodes.InvalidOptions); + // TODO: SERVER-34388 - convert this to txn api when we can do failing + // command in a transaction. session.endSession(); + // TODO: SERVER-34388 - convert this to txn api when we can do failing + // command in a transaction. // readConcern 'snapshot' is allowed on a replica set secondary. + let txnNumber = 0; session = rst.getSecondary().getDB(dbName).getMongo().startSession({causalConsistency: false}); sessionDb = session.getDatabase(dbName); assert.commandWorked(sessionDb.runCommand( @@ -124,33 +138,45 @@ session = testDB.getMongo().startSession({causalConsistency: false}); sessionDb = session.getDatabase(dbName); - txnNumber = 0; // readConcern 'snapshot' is supported by find. - assert.commandWorked(sessionDb.runCommand( - {find: collName, readConcern: {level: "snapshot"}, txnNumber: NumberLong(txnNumber++)})); + session.startTransaction({readConcern: {level: "snapshot"}, writeConcern: {w: "majority"}}); + assert.commandWorked(sessionDb.runCommand({find: collName})); // readConcern 'snapshot' is supported by aggregate. - assert.commandWorked(sessionDb.runCommand({ - aggregate: collName, - pipeline: [], - cursor: {}, - readConcern: {level: "snapshot"}, - txnNumber: NumberLong(txnNumber++) - })); + assert.commandWorked(sessionDb.runCommand({aggregate: collName, pipeline: [], cursor: {}})); // readConcern 'snapshot' is supported by count. - assert.commandWorked(sessionDb.runCommand( - {count: collName, readConcern: {level: "snapshot"}, txnNumber: NumberLong(txnNumber++)})); + assert.commandWorked(sessionDb.runCommand({count: collName})); // readConcern 'snapshot' is supported by distinct. + assert.commandWorked(sessionDb.runCommand({distinct: collName, key: "x"})); + + // readConcern 'snapshot' is supported by geoSearch. + assert.commandWorked( + sessionDb.runCommand({geoSearch: collName, near: [0, 0], maxDistance: 1, search: {a: 1}})); + + // readConcern 'snapshot' is not supported by non-CRUD commands. + assert.commandFailedWithCode( + sessionDb.runCommand({createIndexes: collName, indexes: [{key: {a: 1}, name: "a_1"}]}), + 50767); + session.abortTransaction(); + session.endSession(); + + // TODO: SERVER-34113 Remove this test when we completely remove snapshot + // reads since this command is not supported with transaction api. + // readConcern 'snapshot' is supported by group. + session = rst.getPrimary().getDB(dbName).getMongo().startSession({causalConsistency: false}); + sessionDb = session.getDatabase(dbName); + txnNumber = 0; assert.commandWorked(sessionDb.runCommand({ - distinct: collName, - key: "x", + group: {ns: collName, key: {_id: 1}, $reduce: function(curr, result) {}, initial: {}}, readConcern: {level: "snapshot"}, txnNumber: NumberLong(txnNumber++) })); + // TODO: SERVER-34113 Remove this test when we completely remove snapshot + // reads since this command is not supported with transaction api. // readConcern 'snapshot' is supported by geoNear. assert.commandWorked(sessionDb.runCommand({ geoNear: collName, @@ -159,31 +185,6 @@ txnNumber: NumberLong(txnNumber++) })); - // readConcern 'snapshot' is supported by geoSearch. - assert.commandWorked(sessionDb.runCommand({ - geoSearch: collName, - near: [0, 0], - maxDistance: 1, - search: {a: 1}, - readConcern: {level: "snapshot"}, - txnNumber: NumberLong(txnNumber++) - })); - - // readConcern 'snapshot' is supported by group. - assert.commandWorked(sessionDb.runCommand({ - group: {ns: collName, key: {_id: 1}, $reduce: function(curr, result) {}, initial: {}}, - readConcern: {level: "snapshot"}, - txnNumber: NumberLong(txnNumber++) - })); - - // readConcern 'snapshot' is not supported by non-CRUD commands. - assert.commandFailedWithCode(sessionDb.runCommand({ - createIndexes: collName, - indexes: [{key: {a: 1}, name: "a_1"}], - readConcern: {level: "snapshot"} - }), - ErrorCodes.InvalidOptions); - session.endSession(); rst.stopSet(); }()); diff --git a/jstests/noPassthrough/read_concern_snapshot_aggregation.js b/jstests/noPassthrough/read_concern_snapshot_aggregation.js index e10b7228009..891aa7bb256 100644 --- a/jstests/noPassthrough/read_concern_snapshot_aggregation.js +++ b/jstests/noPassthrough/read_concern_snapshot_aggregation.js @@ -33,6 +33,8 @@ let cmdAsSnapshotRead = Object.extend({}, cmd); cmdAsSnapshotRead.txnNumber = NumberLong(++txnNumber); cmdAsSnapshotRead.readConcern = {level: "snapshot"}; + cmdAsSnapshotRead.autocommit = false; + cmdAsSnapshotRead.startTransaction = true; assert.commandFailedWithCode(sessionDB.runCommand(cmdAsSnapshotRead), code); // As a sanity check, also make sure that the command succeeds when run without a txn number @@ -91,7 +93,9 @@ pipeline: pipeline, cursor: {batchSize: 0}, readConcern: {level: "snapshot"}, - txnNumber: NumberLong(++txnNumber) + txnNumber: NumberLong(++txnNumber), + startTransaction: true, + autocommit: false }); assert.commandWorked(cmdRes); assert.neq(0, cmdRes.cursor.id); @@ -103,6 +107,8 @@ new DBCommandCursor(sessionDB, cmdRes, undefined, undefined, NumberLong(txnNumber)) .toArray(); assert.eq(results, expectedResults); + assert.commandWorked(sessionDB.adminCommand( + {commitTransaction: 1, txnNumber: NumberLong(txnNumber), autocommit: false})); } // Test that snapshot isolation works with $lookup using localField/foreignField syntax. @@ -188,6 +194,8 @@ }], txnNumber: NumberLong(++txnNumber), readConcern: {level: "snapshot"}, + autocommit: false, + startTransaction: true, cursor: {batchSize: 0} })); assert(cmdRes.hasOwnProperty("cursor")); @@ -198,8 +206,14 @@ coll.insert({_id: numInitialGeoInsert, geo: {type: "Point", coordinates: [0, 0]}}, {writeConcern: {w: "majority"}})); - cmdRes = assert.commandWorked(sessionDB.runCommand( - {getMore: NumberLong(cursorId), collection: kCollName, txnNumber: NumberLong(txnNumber)})); + cmdRes = assert.commandWorked(sessionDB.runCommand({ + getMore: NumberLong(cursorId), + collection: kCollName, + autocommit: false, + txnNumber: NumberLong(txnNumber) + })); + assert.commandWorked(sessionDB.adminCommand( + {commitTransaction: 1, txnNumber: NumberLong(txnNumber), autocommit: false})); assert(cmdRes.hasOwnProperty("cursor")); assert(cmdRes.cursor.hasOwnProperty("nextBatch")); assert.eq(cmdRes.cursor.nextBatch.length, numInitialGeoInsert); @@ -229,8 +243,12 @@ ], cursor: {}, readConcern: {level: "snapshot"}, - txnNumber: NumberLong(++txnNumber) + txnNumber: NumberLong(++txnNumber), + startTransaction: true, + autocommit: false }); + assert.commandWorked(sessionDB.adminCommand( + {commitTransaction: 1, txnNumber: NumberLong(txnNumber), autocommit: false})); assert.commandWorked(cmdRes); assert.eq(0, cmdRes.cursor.id); assert.eq(cmdRes.cursor.firstBatch, [ diff --git a/jstests/noPassthrough/read_concern_snapshot_catalog_invalidation.js b/jstests/noPassthrough/read_concern_snapshot_catalog_invalidation.js index 1cc7f5078e4..03f9a9adc50 100644 --- a/jstests/noPassthrough/read_concern_snapshot_catalog_invalidation.js +++ b/jstests/noPassthrough/read_concern_snapshot_catalog_invalidation.js @@ -41,15 +41,13 @@ assert.commandWorked(testDB.adminCommand( {configureFailPoint: "hangAfterPreallocateSnapshot", mode: "alwaysOn"})); - TestData.sessionId = assert.commandWorked(testDB.adminCommand({startSession: 1})).id; const awaitCommand = startParallelShell(function() { - const res = db.runCommand({ - find: "coll", - readConcern: {level: "snapshot"}, - lsid: TestData.sessionId, - txnNumber: NumberLong(0) - }); + const session = db.getMongo().startSession(); + const sessionDb = session.getDatabase("test"); + session.startTransaction({readConcern: {level: "snapshot"}}); + const res = sessionDb.runCommand({find: "coll"}); assert.commandFailedWithCode(res, ErrorCodes.SnapshotUnavailable); + session.endSession(); }, rst.ports[0]); waitForOp({"command.find": kCollName, "command.readConcern.level": "snapshot"}); @@ -70,6 +68,5 @@ awaitCommand(); - assert.commandWorked(testDB.adminCommand({endSessions: [TestData.sessionId]})); rst.stopSet(); })(); diff --git a/jstests/noPassthrough/read_concern_snapshot_yielding.js b/jstests/noPassthrough/read_concern_snapshot_yielding.js index 69b302434b1..10fdada1f47 100644 --- a/jstests/noPassthrough/read_concern_snapshot_yielding.js +++ b/jstests/noPassthrough/read_concern_snapshot_yielding.js @@ -259,6 +259,8 @@ assert.eq(res.cursor.firstBatch.length, TestData.numDocs, tojson(res)); }, {"command.pipeline": [{$match: {x: 1}}]}, {"command.pipeline": [{$match: {x: 1}}]}); + // TODO: SERVER-34113 Remove this test when we completely remove snapshot + // reads since this command is not supported with transaction api. // Test geoNear. testCommand(function() { const res = assert.commandWorked(db.runCommand({ diff --git a/jstests/noPassthrough/read_majority.js b/jstests/noPassthrough/read_majority.js index ccce91baf81..2cdf629927a 100644 --- a/jstests/noPassthrough/read_majority.js +++ b/jstests/noPassthrough/read_majority.js @@ -46,41 +46,29 @@ load("jstests/libs/analyze_plan.js"); replTest.getPrimary().getDB("test").getMongo().startSession({causalConsistency: false}); const db = session.getDatabase("test"); const t = db.coll; - let txnNumber = 0; function assertNoSnapshotAvailableForReadConcernLevel() { - var res = t.runCommand('find', { - batchSize: 2, - readConcern: {level: level}, - maxTimeMS: 1000, - txnNumber: NumberLong(txnNumber++) - }); + var res = + t.runCommand('find', {batchSize: 2, readConcern: {level: level}, maxTimeMS: 1000}); assert.commandFailed(res); assert.eq(res.code, ErrorCodes.ExceededTimeLimit); } function getCursorForReadConcernLevel() { - var res = t.runCommand( - 'find', - {batchSize: 2, readConcern: {level: level}, txnNumber: NumberLong(txnNumber)}); + var res = t.runCommand('find', {batchSize: 2, readConcern: {level: level}}); assert.commandWorked(res); - return new DBCommandCursor(db, res, 2, undefined, txnNumber++); + return new DBCommandCursor(db, res, 2, undefined); } function getAggCursorForReadConcernLevel() { - var res = t.runCommand('aggregate', { - pipeline: [], - cursor: {batchSize: 2}, - readConcern: {level: level}, - txnNumber: NumberLong(txnNumber) - }); + var res = t.runCommand( + 'aggregate', {pipeline: [], cursor: {batchSize: 2}, readConcern: {level: level}}); assert.commandWorked(res); - return new DBCommandCursor(db, res, 2, undefined, txnNumber++); + return new DBCommandCursor(db, res, 2, undefined); } function getExplainPlan(query) { - var res = db.runCommand( - {explain: {find: t.getName(), filter: query, txnNumber: NumberLong(txnNumber++)}}); + var res = db.runCommand({explain: {find: t.getName(), filter: query}}); return assert.commandWorked(res).queryPlanner.winningPlan; } @@ -93,7 +81,7 @@ load("jstests/libs/analyze_plan.js"); "const session = db.getMongo().startSession({causalConsistency: false}); " + "const sessionDB = session.getDatabase(db.getName()); " + "sessionDB.coll.runCommand('find', {batchSize: 2, readConcern: {level: \"" + level + - "\"}, txnNumber: NumberLong(" + (txnNumber++) + ")});", + "\"}});", replTest.ports[0]); assert.soon(function() { @@ -223,19 +211,14 @@ load("jstests/libs/analyze_plan.js"); // Commands that only support read concern 'local', (such as ping) must work when it is // explicitly specified and fail for majority-committed read concern levels. assert.commandWorked(db.adminCommand({ping: 1, readConcern: {level: 'local'}})); - var res = assert.commandFailed(db.adminCommand( - {ping: 1, readConcern: {level: level}, txnNumber: NumberLong(txnNumber++)})); + var res = assert.commandFailed(db.adminCommand({ping: 1, readConcern: {level: level}})); assert.eq(res.code, ErrorCodes.InvalidOptions); // Agg $out also doesn't support majority committed reads. assert.commandWorked(t.runCommand( 'aggregate', {pipeline: [{$out: 'out'}], cursor: {}, readConcern: {level: 'local'}})); - var res = assert.commandFailed(t.runCommand('aggregate', { - pipeline: [{$out: 'out'}], - cursor: {}, - readConcern: {level: level}, - txnNumber: NumberLong(txnNumber++) - })); + var res = assert.commandFailed(t.runCommand( + 'aggregate', {pipeline: [{$out: 'out'}], cursor: {}, readConcern: {level: level}})); assert.eq(res.code, ErrorCodes.InvalidOptions); replTest.stopSet(); @@ -254,8 +237,8 @@ load("jstests/libs/analyze_plan.js"); testReadConcernLevel("majority"); } - // TODO SERVER-33218: Test for readConcern level snapshot once itcount() preserves - // txnNumber. Without this, itcount() calls will execute a getMore without txnNumber. + // TODO SERVER-34388: Test snapshot readConcern when failing commands do + // not abort the transaction. /* if (supportsSnapshotReadConcern) { testReadConcernLevel("snapshot"); diff --git a/jstests/noPassthrough/snapshot_cursor_integrity.js b/jstests/noPassthrough/snapshot_cursor_integrity.js index 63d20b0a234..7e99581bc2d 100644 --- a/jstests/noPassthrough/snapshot_cursor_integrity.js +++ b/jstests/noPassthrough/snapshot_cursor_integrity.js @@ -34,6 +34,8 @@ find: collName, readConcern: {level: "snapshot"}, txnNumber: NumberLong(0), + autocommit: false, + startTransaction: true, batchSize: 2 })); assert(res.hasOwnProperty("cursor")); @@ -45,38 +47,66 @@ primaryDB.runCommand({getMore: cursorID, collection: collName, batchSize: 2}), 50737); // The cursor can still be iterated in session1. - assert.commandWorked(sessionDB1.runCommand( - {getMore: cursorID, collection: collName, txnNumber: NumberLong(0), batchSize: 2})); + assert.commandWorked(sessionDB1.runCommand({ + getMore: cursorID, + collection: collName, + autocommit: false, + txnNumber: NumberLong(0), + batchSize: 2 + })); // The cursor may not be iterated in a different session. assert.commandFailedWithCode( - sessionDB2.runCommand( - {getMore: cursorID, collection: collName, txnNumber: NumberLong(0), batchSize: 2}), - 50738); + sessionDB2.runCommand({getMore: cursorID, collection: collName, batchSize: 2}), 50738); // The cursor can still be iterated in session1. - assert.commandWorked(sessionDB1.runCommand( - {getMore: cursorID, collection: collName, txnNumber: NumberLong(0), batchSize: 2})); + assert.commandWorked(sessionDB1.runCommand({ + getMore: cursorID, + collection: collName, + autocommit: false, + txnNumber: NumberLong(0), + batchSize: 2 + })); // The cursor may not be iterated outside of any transaction. assert.commandFailedWithCode( sessionDB1.runCommand({getMore: cursorID, collection: collName, batchSize: 2}), 50740); // The cursor can still be iterated in its transaction in session1. - assert.commandWorked(sessionDB1.runCommand( - {getMore: cursorID, collection: collName, txnNumber: NumberLong(0), batchSize: 2})); + assert.commandWorked(sessionDB1.runCommand({ + getMore: cursorID, + collection: collName, + autocommit: false, + txnNumber: NumberLong(0), + batchSize: 2 + })); // The cursor may not be iterated in a different transaction on session1. - assert.commandFailedWithCode( - sessionDB1.runCommand( - {getMore: cursorID, collection: collName, txnNumber: NumberLong(1), batchSize: 2}), - ErrorCodes.CursorNotFound); + assert.commandWorked(sessionDB1.runCommand({ + find: collName, + txnNumber: NumberLong(1), + autocommit: false, + readConcern: {level: "snapshot"}, + startTransaction: true + })); + assert.commandFailedWithCode(sessionDB1.runCommand({ + getMore: cursorID, + collection: collName, + autocommit: false, + txnNumber: NumberLong(1), + batchSize: 2 + }), + ErrorCodes.CursorNotFound); // The cursor can no longer be iterated because its transaction has ended. - assert.commandFailedWithCode( - sessionDB1.runCommand( - {getMore: cursorID, collection: collName, txnNumber: NumberLong(0), batchSize: 2}), - ErrorCodes.TransactionTooOld); + assert.commandFailedWithCode(sessionDB1.runCommand({ + getMore: cursorID, + collection: collName, + autocommit: false, + txnNumber: NumberLong(0), + batchSize: 2 + }), + ErrorCodes.TransactionTooOld); // Establish a cursor outside of any transaction in session1. res = assert.commandWorked(sessionDB1.runCommand({find: collName, batchSize: 2})); @@ -85,10 +115,21 @@ cursorID = res.cursor.id; // The cursor may not be iterated inside a transaction. - assert.commandFailedWithCode( - sessionDB1.runCommand( - {getMore: cursorID, collection: collName, txnNumber: NumberLong(2), batchSize: 2}), - 50739); + assert.commandWorked(sessionDB1.runCommand({ + find: collName, + txnNumber: NumberLong(2), + autocommit: false, + readConcern: {level: "snapshot"}, + startTransaction: true + })); + assert.commandFailedWithCode(sessionDB1.runCommand({ + getMore: cursorID, + collection: collName, + autocommit: false, + txnNumber: NumberLong(2), + batchSize: 2 + }), + 50739); // The cursor can still be iterated outside of any transaction. Exhaust the cursor. assert.commandWorked(sessionDB1.runCommand({getMore: cursorID, collection: collName})); diff --git a/jstests/noPassthrough/snapshot_cursor_shutdown_stepdown.js b/jstests/noPassthrough/snapshot_cursor_shutdown_stepdown.js index 9316f6dbfa7..338ee4c5983 100644 --- a/jstests/noPassthrough/snapshot_cursor_shutdown_stepdown.js +++ b/jstests/noPassthrough/snapshot_cursor_shutdown_stepdown.js @@ -32,6 +32,8 @@ find: collName, batchSize: 2, readConcern: {level: "snapshot"}, + startTransaction: true, + autocommit: false, txnNumber: NumberLong(0) })); @@ -75,9 +77,18 @@ // Perform a getMore using the previous transaction's open cursorId. We expect to receive // CursorNotFound if the cursor was properly closed on step down. + assert.commandWorked(sessionDB.runCommand({ + find: collName, + readConcern: {level: "snapshot"}, + txnNumber: NumberLong(1), + startTransaction: true, + autocommit: false + })); assert.commandFailedWithCode(sessionDB.runCommand({ getMore: cursorId, collection: collName, + txnNumber: NumberLong(1), + autocommit: false }), ErrorCodes.CursorNotFound); rst.stopSet(); diff --git a/jstests/noPassthrough/snapshot_reads.js b/jstests/noPassthrough/snapshot_reads.js index 87942a43400..a5a0f8f1cd3 100644 --- a/jstests/noPassthrough/snapshot_reads.js +++ b/jstests/noPassthrough/snapshot_reads.js @@ -18,7 +18,6 @@ rst.stopSet(); return; } - const secondaryDB = rst.getSecondary().getDB(dbName); function parseCursor(cmdResult) { if (cmdResult.hasOwnProperty("cursor")) { @@ -34,15 +33,11 @@ tojson(cmdResult)); } - function runTest({useCausalConsistency, readFromSecondary, establishCursorCmd}) { + function runTest({useCausalConsistency, establishCursorCmd}) { primaryDB.coll.drop(); - let readDB = primaryDB; - if (readFromSecondary) { - readDB = secondaryDB; - } - - const session = readDB.getMongo().startSession({causalConsistency: useCausalConsistency}); + const session = + primaryDB.getMongo().startSession({causalConsistency: useCausalConsistency}); const sessionDb = session.getDatabase(dbName); const bulk = primaryDB.coll.initializeUnorderedBulkOp(); @@ -51,20 +46,10 @@ } assert.commandWorked(bulk.execute({w: "majority"})); - if (readFromSecondary) { - rst.awaitLastOpCommitted(); - } - - let txnNumber = 0; - - // Augment the cursor-establishing command with the proper readConcern and transaction - // number. - let cursorCmd = Object.extend({}, establishCursorCmd); - cursorCmd.readConcern = {level: "snapshot"}; - cursorCmd.txnNumber = NumberLong(txnNumber); + session.startTransaction({readConcern: {level: "snapshot"}}); // Establish a snapshot batchSize:0 cursor. - let res = assert.commandWorked(sessionDb.runCommand(cursorCmd)); + let res = assert.commandWorked(sessionDb.runCommand(establishCursorCmd)); let cursor = parseCursor(res); assert(cursor.hasOwnProperty("firstBatch"), tojson(res)); @@ -76,12 +61,8 @@ assert.writeOK(primaryDB.coll.insert({_id: 10}, {writeConcern: {w: "majority"}})); // Fetch the first 5 documents. - res = assert.commandWorked(sessionDb.runCommand({ - getMore: cursor.id, - collection: collName, - batchSize: 5, - txnNumber: NumberLong(txnNumber) - })); + res = assert.commandWorked( + sessionDb.runCommand({getMore: cursor.id, collection: collName, batchSize: 5})); cursor = parseCursor(res); assert.neq(0, cursor.id, tojson(res)); assert(cursor.hasOwnProperty("nextBatch"), tojson(res)); @@ -89,12 +70,9 @@ // Exhaust the cursor, retrieving the remainder of the result set. Performing a second // getMore tests snapshot isolation across multiple getMore invocations. - res = assert.commandWorked(sessionDb.runCommand({ - getMore: cursor.id, - collection: collName, - batchSize: 20, - txnNumber: NumberLong(txnNumber++) - })); + res = assert.commandWorked( + sessionDb.runCommand({getMore: cursor.id, collection: collName, batchSize: 20})); + session.commitTransaction(); // The cursor has been exhausted. cursor = parseCursor(res); @@ -105,18 +83,11 @@ assert(cursor.hasOwnProperty("nextBatch"), tojson(res)); assert.eq(5, cursor.nextBatch.length, tojson(res)); - if (readFromSecondary) { - rst.awaitLastOpCommitted(); - } - // Perform a second snapshot read under a new transaction. - res = assert.commandWorked(sessionDb.runCommand({ - find: collName, - sort: {_id: 1}, - batchSize: 20, - readConcern: {level: "snapshot"}, - txnNumber: NumberLong(txnNumber++) - })); + session.startTransaction({readConcern: {level: "snapshot"}}); + res = assert.commandWorked( + sessionDb.runCommand({find: collName, sort: {_id: 1}, batchSize: 20})); + session.commitTransaction(); // The cursor has been exhausted. cursor = parseCursor(res); @@ -126,34 +97,18 @@ assert(cursor.hasOwnProperty("firstBatch"), tojson(res)); assert.eq(11, cursor.firstBatch.length, tojson(res)); - // Reject snapshot reads without txnNumber. - assert.commandFailed(sessionDb.runCommand( - {find: collName, sort: {_id: 1}, batchSize: 20, readConcern: {level: "snapshot"}})); - - // Reject snapshot reads without session. - assert.commandFailed(readDB.runCommand({ - find: collName, - sort: {_id: 1}, - batchSize: 20, - readConcern: {level: "snapshot"}, - txnNumber: NumberLong(txnNumber++) - })); - session.endSession(); } // Test snapshot reads using find. let findCmd = {find: collName, sort: {_id: 1}, batchSize: 0}; - runTest({useCausalConsistency: false, readFromSecondary: false, establishCursorCmd: findCmd}); - runTest({useCausalConsistency: true, readFromSecondary: false, establishCursorCmd: findCmd}); - runTest({useCausalConsistency: false, readFromSecondary: true, establishCursorCmd: findCmd}); - runTest({useCausalConsistency: true, readFromSecondary: true, establishCursorCmd: findCmd}); + runTest({useCausalConsistency: false, establishCursorCmd: findCmd}); + runTest({useCausalConsistency: true, establishCursorCmd: findCmd}); // Test snapshot reads using aggregate. let aggCmd = {aggregate: collName, pipeline: [{$sort: {_id: 1}}], cursor: {batchSize: 0}}; - runTest({useCausalConsistency: false, readFromSecondary: false, establishCursorCmd: aggCmd}); - runTest({useCausalConsistency: true, readFromSecondary: false, establishCursorCmd: aggCmd}); - runTest({useCausalConsistency: false, readFromSecondary: true, establishCursorCmd: aggCmd}); - runTest({useCausalConsistency: true, readFromSecondary: true, establishCursorCmd: aggCmd}); + runTest({useCausalConsistency: false, establishCursorCmd: aggCmd}); + runTest({useCausalConsistency: true, establishCursorCmd: aggCmd}); + rst.stopSet(); })(); diff --git a/src/mongo/shell/query.js b/src/mongo/shell/query.js index 78e334f0256..e7d7de16605 100644 --- a/src/mongo/shell/query.js +++ b/src/mongo/shell/query.js @@ -781,6 +781,7 @@ DBCommandCursor.prototype._runGetMoreCommand = function() { if (this._txnNumber) { getMoreCmd.txnNumber = NumberLong(this._txnNumber); + getMoreCmd.autocommit = false; } // Deliver the getMore command, and check for errors in the response. |