summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXiangyu Yao <xiangyu.yao@mongodb.com>2018-04-03 18:27:56 -0400
committerXiangyu Yao <xiangyu.yao@mongodb.com>2018-04-17 12:03:10 -0400
commitfcf41ce8ddf70894ed6803420e94a1685cc60903 (patch)
tree79de3abcf16f4ad6b9029c7ff3a63504963bb338
parentdc4832736957d840760af6557d65dcf28cd81063 (diff)
downloadmongo-fcf41ce8ddf70894ed6803420e94a1685cc60903.tar.gz
SERVER-34094 Change snapshot read tests to use multi-statement transactions
-rw-r--r--jstests/noPassthrough/afterClusterTime_committed_reads.js2
-rw-r--r--jstests/noPassthrough/agg_explain_read_concern.js2
-rw-r--r--jstests/noPassthrough/readConcern_snapshot.js95
-rw-r--r--jstests/noPassthrough/read_concern_snapshot_aggregation.js26
-rw-r--r--jstests/noPassthrough/read_concern_snapshot_catalog_invalidation.js13
-rw-r--r--jstests/noPassthrough/read_concern_snapshot_yielding.js2
-rw-r--r--jstests/noPassthrough/read_majority.js45
-rw-r--r--jstests/noPassthrough/snapshot_cursor_integrity.js83
-rw-r--r--jstests/noPassthrough/snapshot_cursor_shutdown_stepdown.js11
-rw-r--r--jstests/noPassthrough/snapshot_reads.js83
-rw-r--r--src/mongo/shell/query.js1
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.