diff options
author | Max Hirschhorn <max.hirschhorn@mongodb.com> | 2017-11-08 19:29:28 -0500 |
---|---|---|
committer | Max Hirschhorn <max.hirschhorn@mongodb.com> | 2017-11-08 19:29:28 -0500 |
commit | 6d8e6b9cce052cdd442e207a27df10e698b2bb00 (patch) | |
tree | 5a7bb7b5cf93902bf00a681dccb0f54adb2f1ab0 /jstests/multiVersion | |
parent | f7756c41c5ed54e8e546461395bc8898d885af0c (diff) | |
download | mongo-6d8e6b9cce052cdd442e207a27df10e698b2bb00.tar.gz |
SERVER-31296 Update sessions, causal, and retryable in the mongo shell.
* Removes the initialClusterTime and initialOperationTime session
options.
* Enables causal consistency by default when using an explicit
session.
* Adds a --retryWrites command line option to the mongo shell for
enabling retryable writes in the mongo shell. The retryWrites
options to SessionOptions is left for convenience with testing.
* Renames setClusterTime() to advanceClusterTime(), and adds a
corresponding advanceOperationTime() method to DriverSession.
* Enables assigning transaction numbers for write commands where
ordered=false.
* Prevents the mongo shell from sending afterClusterTime or assigning
transaction numbers when talking to a stand-alone mongod.
* Prevents the mongo shell from assigning transaction numbers when
using an unacknowledged (w=0) writeConcern.
* Changes DBClientRS to re-discover the current primary of the replica
set when it receives an error code representing "not master" in
addition to an error message representing "not master".
* Adds a shellPrint() pretty-printer for SessionOptions and
DriverSession instances so they no longer print out their entire
object definition.
Diffstat (limited to 'jstests/multiVersion')
-rw-r--r-- | jstests/multiVersion/shell_causal_consistency_downgrade.js | 119 | ||||
-rw-r--r-- | jstests/multiVersion/shell_retryable_writes_downgrade.js | 122 |
2 files changed, 241 insertions, 0 deletions
diff --git a/jstests/multiVersion/shell_causal_consistency_downgrade.js b/jstests/multiVersion/shell_causal_consistency_downgrade.js new file mode 100644 index 00000000000..68a416297c7 --- /dev/null +++ b/jstests/multiVersion/shell_causal_consistency_downgrade.js @@ -0,0 +1,119 @@ +/** + * Tests that the mongo shell doesn't gossip its highest seen clusterTime or inject an + * afterClusterTime into its command requests after downgrading from 3.6 to 3.4. + */ +(function() { + "use strict"; + + load("jstests/replsets/rslib.js"); + + const rst = new ReplSetTest({nodes: 1}); + rst.startSet(); + rst.initiate(); + + const primary = rst.getPrimary(); + primary.setCausalConsistency(); + + const db = primary.getDB("test"); + const coll = db.shell_causal_consistency_downgrade; + + function testCommandCanBeCausallyConsistent(func, { + expectedGossipClusterTime: expectedGossipClusterTime = true, + expectedAfterClusterTime: expectedAfterClusterTime = true + } = {}) { + const mongoRunCommandOriginal = Mongo.prototype.runCommand; + + const sentinel = {}; + let cmdObjSeen = sentinel; + + Mongo.prototype.runCommand = function runCommandSpy(dbName, cmdObj, options) { + cmdObjSeen = cmdObj; + return mongoRunCommandOriginal.apply(this, arguments); + }; + + try { + assert.doesNotThrow(func); + } finally { + Mongo.prototype.runCommand = mongoRunCommandOriginal; + } + + if (cmdObjSeen === sentinel) { + throw new Error("Mongo.prototype.runCommand() was never called: " + func.toString()); + } + + let cmdName = Object.keys(cmdObjSeen)[0]; + + // If the command is in a wrapped form, then we look for the actual command object inside + // the query/$query object. + if (cmdName === "query" || cmdName === "$query") { + cmdObjSeen = cmdObjSeen[cmdName]; + cmdName = Object.keys(cmdObjSeen)[0]; + } + + if (expectedGossipClusterTime) { + assert(cmdObjSeen.hasOwnProperty("$clusterTime"), + "Expected operation " + tojson(cmdObjSeen) + " to have a $clusterTime object: " + + func.toString()); + } else { + assert(!cmdObjSeen.hasOwnProperty("$clusterTime"), + "Expected operation " + tojson(cmdObjSeen) + + " to not have a $clusterTime object: " + func.toString()); + } + + if (expectedAfterClusterTime) { + assert(cmdObjSeen.hasOwnProperty("readConcern"), + "Expected operation " + tojson(cmdObjSeen) + + " to have a readConcern object since it can be causally consistent: " + + func.toString()); + + const readConcern = cmdObjSeen.readConcern; + assert(readConcern.hasOwnProperty("afterClusterTime"), + "Expected operation " + tojson(cmdObjSeen) + + " to specify afterClusterTime since it can be causally consistent: " + + func.toString()); + } else { + assert(!cmdObjSeen.hasOwnProperty("readConcern"), + "Expected operation " + tojson(cmdObjSeen) + " to not have a readConcern" + + " object since it cannot be causally consistent: " + func.toString()); + } + } + + assert.writeOK(coll.insert({})); + + testCommandCanBeCausallyConsistent(function() { + assert.commandWorked(db.runCommand({count: coll.getName()})); + }); + + assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: "3.4"})); + + // The server continues to accept $clusterTime and afterClusterTime while in + // featureCompatibilityVersion=3.4. + testCommandCanBeCausallyConsistent(function() { + assert.commandWorked(db.runCommand({count: coll.getName()})); + }); + + rst.restart(primary, {binVersion: "3.4"}); + rst.waitForMaster(); + reconnect(primary); + + assert(primary.isCausalConsistency(), + "Re-establishing the connection shouldn't change the state of the Mongo object"); + + // After downgrading to MongoDB 3.4, the mongo shell shouldn't gossip its highest seen + // clusterTime or inject an afterClusterTime into its command requests. + testCommandCanBeCausallyConsistent(function() { + assert.commandWorked(db.runCommand({count: coll.getName()})); + }, {expectedGossipClusterTime: false, expectedAfterClusterTime: false}); + + rst.restart(primary, {binVersion: "latest", noReplSet: true}); + rst.waitForMaster(); + reconnect(primary); + + // When upgrading to MongoDB 3.6 but running as a stand-alone server, the mongo shell shouldn't + // gossip its highest seen clusterTime or inject an afterClusterTime into its command requests. + testCommandCanBeCausallyConsistent(function() { + assert.commandWorked(db.runCommand({count: coll.getName()})); + }, {expectedGossipClusterTime: false, expectedAfterClusterTime: false}); + + rst.stopSet(); +})(); diff --git a/jstests/multiVersion/shell_retryable_writes_downgrade.js b/jstests/multiVersion/shell_retryable_writes_downgrade.js new file mode 100644 index 00000000000..652d33c0ddc --- /dev/null +++ b/jstests/multiVersion/shell_retryable_writes_downgrade.js @@ -0,0 +1,122 @@ +/** + * Tests that the mongo shell doesn't attempt to retry its write operations after downgrading from + * 3.6 to 3.4. + */ +(function() { + "use strict"; + + load("jstests/replsets/rslib.js"); + + const rst = new ReplSetTest({nodes: 1}); + rst.startSet(); + rst.initiate(); + + const primary = rst.getPrimary(); + + const db = primary.startSession({retryWrites: true}).getDatabase("test"); + const coll = db.shell_retryable_writes_downgrade; + + function testCommandCanBeRetried(func, { + expectedLogicalSessionId: expectedLogicalSessionId = true, + expectedTransactionNumber: expectedTransactionNumber = true + } = {}) { + const mongoRunCommandOriginal = Mongo.prototype.runCommand; + + const sentinel = {}; + let cmdObjSeen = sentinel; + + Mongo.prototype.runCommand = function runCommandSpy(dbName, cmdObj, options) { + cmdObjSeen = cmdObj; + return mongoRunCommandOriginal.apply(this, arguments); + }; + + try { + assert.doesNotThrow(func); + } finally { + Mongo.prototype.runCommand = mongoRunCommandOriginal; + } + + if (cmdObjSeen === sentinel) { + throw new Error("Mongo.prototype.runCommand() was never called: " + func.toString()); + } + + let cmdName = Object.keys(cmdObjSeen)[0]; + + // If the command is in a wrapped form, then we look for the actual command object inside + // the query/$query object. + if (cmdName === "query" || cmdName === "$query") { + cmdObjSeen = cmdObjSeen[cmdName]; + cmdName = Object.keys(cmdObjSeen)[0]; + } + + if (expectedLogicalSessionId) { + assert(cmdObjSeen.hasOwnProperty("lsid"), + "Expected operation " + tojson(cmdObjSeen) + " to have a logical session id: " + + func.toString()); + } else { + assert(!cmdObjSeen.hasOwnProperty("lsid"), + "Expected operation " + tojson(cmdObjSeen) + + " to not have a logical session id: " + func.toString()); + } + + if (expectedTransactionNumber) { + assert(cmdObjSeen.hasOwnProperty("txnNumber"), + "Expected operation " + tojson(cmdObjSeen) + + " to be assigned a transaction number since it can be retried: " + + func.toString()); + } else { + assert(!cmdObjSeen.hasOwnProperty("txnNumber"), + "Expected operation " + tojson(cmdObjSeen) + + " to not be assigned a transaction number since it cannot be retried: " + + func.toString()); + } + } + + testCommandCanBeRetried(function() { + assert.writeOK(coll.insert({_id: "while fCV=3.6"})); + }); + + assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: "3.4"})); + + // The server continues to accept lsid and txnNumber while in featureCompatibilityVersion=3.4. + // + // TODO SERVER-31777: The server should return an error if an lsid or txnNumber is specified + // while in featureCompatibilityVersion=3.4. + testCommandCanBeRetried(function() { + assert.writeOK(coll.insert({_id: "while fCV=3.4"})); + }); + + rst.restart(primary, {binVersion: "3.4"}); + rst.waitForMaster(); + + assert(db.getSession().getOptions().shouldRetryWrites(), + "Re-establishing the connection shouldn't change the state of the SessionOptions"); + + // After downgrading to MongoDB 3.4, the mongo shell shouldn't attempt to automatically retry + // write operations. + assert.throws(function() { + coll.insert({_id: "while in binVersion=3.4 and disconnected"}); + }); + + // After downgrading to MongoDB 3.4, the mongo shell shouldn't inject an lsid or assign a + // transaction number to its write requests. + testCommandCanBeRetried(function() { + assert.writeOK(coll.insert({_id: "while binVersion=3.4 and reconnected"})); + }, {expectedLogicalSessionId: false, expectedTransactionNumber: false}); + + rst.restart(primary, {binVersion: "latest", noReplSet: true}); + rst.waitForMaster(); + reconnect(primary); + + // When upgrading to MongoDB 3.6 but running as a stand-alone server, the mongo shell should + // still assign a transaction number to its write requests (per the Driver's specification). + // + // TODO SERVER-31777: The server should return an error if an lsid or txnNumber is specified + // while in featureCompatibilityVersion=3.4. + testCommandCanBeRetried(function() { + assert.writeOK(coll.insert({_id: "while binVersion=3.6 as stand-alone and reconnected"})); + }); + + db.getSession().endSession(); + rst.stopSet(); +})(); |