summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Mulrow <jack.mulrow@mongodb.com>2017-06-02 16:37:34 -0400
committerJack Mulrow <jack.mulrow@mongodb.com>2017-06-06 10:29:47 -0400
commit783d11c4ea92784dc6ca0cc0419403c454c9ec9c (patch)
treea396e67154af0d178008fcf33156f4f557854c06
parent6b05afb44da679600b682e0ef3c7061eb7e3403c (diff)
downloadmongo-783d11c4ea92784dc6ca0cc0419403c454c9ec9c.tar.gz
SERVER-29434 Don't accept empty timestamps for readConcern afterClusterTime
-rw-r--r--buildscripts/resmokeconfig/suites/sharding_last_stable_mongos_and_mixed_shards.yml1
-rw-r--r--jstests/sharding/after_cluster_time.js111
-rw-r--r--src/mongo/db/repl/read_concern_args.cpp5
3 files changed, 117 insertions, 0 deletions
diff --git a/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos_and_mixed_shards.yml b/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos_and_mixed_shards.yml
index 1aca6af1d0c..9103cef9bf9 100644
--- a/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos_and_mixed_shards.yml
+++ b/buildscripts/resmokeconfig/suites/sharding_last_stable_mongos_and_mixed_shards.yml
@@ -22,6 +22,7 @@ selector:
# New feature in v3.6 mongos and mongod.
- jstests/sharding/logical_time_api.js
- jstests/sharding/operation_time_api.js
+ - jstests/sharding/after_cluster_time.js
- jstests/sharding/auth_drop_user_while_logged_in.js
# New feature in v3.6 mongo shell.
- jstests/sharding/causal_consistency_shell_support.js
diff --git a/jstests/sharding/after_cluster_time.js b/jstests/sharding/after_cluster_time.js
new file mode 100644
index 00000000000..0b299408512
--- /dev/null
+++ b/jstests/sharding/after_cluster_time.js
@@ -0,0 +1,111 @@
+/**
+ * Tests readConcern: afterClusterTime behavior in a sharded cluster.
+ */
+(function() {
+ "use strict";
+
+ load("jstests/replsets/rslib.js"); // For startSetIfSupportsReadMajority.
+
+ function assertAfterClusterTimeReadFailsWithCode(db, readConcernObj, errorCode) {
+ return assert.commandFailedWithCode(
+ db.runCommand({find: "foo", readConcern: readConcernObj}),
+ errorCode,
+ "expected command with read concern options: " + tojson(readConcernObj) + " to fail");
+ }
+
+ function assertAfterClusterTimeReadSucceeds(db, readConcernObj) {
+ return assert.commandWorked(db.runCommand({find: "foo", readConcern: readConcernObj}),
+ "expected command with read concern options: " +
+ tojson(readConcernObj) + " to succeed");
+ }
+
+ const rst = new ReplSetTest({
+ nodes: 1,
+ nodeOptions: {
+ enableMajorityReadConcern: "",
+ shardsvr: "",
+ }
+ });
+
+ if (!startSetIfSupportsReadMajority(rst)) {
+ jsTestLog("Skipping test since storage engine doesn't support majority read concern.");
+ return;
+ }
+ rst.initiate();
+
+ // Start the sharding test and add the majority read concern enabled replica set.
+ const st = new ShardingTest({
+ manualAddShard: true,
+ });
+ assert.commandWorked(st.s.adminCommand({addShard: rst.getURL()}));
+
+ const testDB = st.s.getDB("test");
+
+ // Insert some data to find later.
+ assert.commandWorked(testDB.runCommand(
+ {insert: "foo", documents: [{_id: 1, x: 1}], writeConcern: {w: "majority"}}));
+
+ // Test the afterClusterTime API without causal consistency enabled on the mongo connection.
+
+ // Reads with afterClusterTime require read concern level majority.
+ assertAfterClusterTimeReadFailsWithCode(
+ testDB, {afterClusterTime: Timestamp(1, 1)}, ErrorCodes.InvalidOptions);
+
+ assertAfterClusterTimeReadFailsWithCode(
+ testDB, {level: "local", afterClusterTime: Timestamp(1, 1)}, ErrorCodes.InvalidOptions);
+
+ // Reads with afterClusterTime require a non-zero timestamp.
+ assertAfterClusterTimeReadFailsWithCode(
+ testDB, {level: "majority", afterClusterTime: {}}, ErrorCodes.TypeMismatch);
+
+ assertAfterClusterTimeReadFailsWithCode(
+ testDB, {level: "majority", afterClusterTime: 10}, ErrorCodes.TypeMismatch);
+
+ assertAfterClusterTimeReadFailsWithCode(
+ testDB, {level: "majority", afterClusterTime: Timestamp()}, ErrorCodes.InvalidOptions);
+
+ assertAfterClusterTimeReadFailsWithCode(
+ testDB, {level: "majority", afterClusterTime: Timestamp(0, 0)}, ErrorCodes.InvalidOptions);
+
+ // Reads with proper afterClusterTime arguments return committed data after the given time.
+ let res = assert.commandWorked(testDB.runCommand(
+ {find: "foo", readConcern: {level: "majority", afterClusterTime: Timestamp(1, 1)}}));
+
+ assert.eq(res.cursor.firstBatch,
+ [{_id: 1, x: 1}],
+ "expected afterClusterTime read to return the committed document");
+
+ // Test the afterClusterTime API with causal consistency enabled on the mongo connection.
+ testDB.getMongo().setCausalConsistency(true);
+
+ // With causal consistency enabled, the shell sets read concern to level "majority" if it is not
+ // specified.
+ assertAfterClusterTimeReadSucceeds(testDB, {afterClusterTime: Timestamp(1, 1)});
+
+ // Read concern levels other than majority are still not accepted.
+ assertAfterClusterTimeReadFailsWithCode(
+ testDB, {level: "local", afterClusterTime: Timestamp(1, 1)}, ErrorCodes.InvalidOptions);
+
+ // Reads with afterClusterTime still require a non-zero timestamp.
+ assertAfterClusterTimeReadFailsWithCode(
+ testDB, {level: "majority", afterClusterTime: {}}, ErrorCodes.TypeMismatch);
+
+ assertAfterClusterTimeReadFailsWithCode(
+ testDB, {level: "majority", afterClusterTime: 10}, ErrorCodes.TypeMismatch);
+
+ assertAfterClusterTimeReadFailsWithCode(
+ testDB, {level: "majority", afterClusterTime: Timestamp()}, ErrorCodes.InvalidOptions);
+
+ assertAfterClusterTimeReadFailsWithCode(
+ testDB, {level: "majority", afterClusterTime: Timestamp(0, 0)}, ErrorCodes.InvalidOptions);
+
+ // Reads with proper afterClusterTime arguments return committed data after the given time.
+ res = assert.commandWorked(testDB.runCommand(
+ {find: "foo", readConcern: {level: "majority", afterClusterTime: Timestamp(1, 1)}}));
+
+ assert.eq(res.cursor.firstBatch,
+ [{_id: 1, x: 1}],
+ "expected afterClusterTime read to return the committed document");
+
+ st.stop();
+})();
diff --git a/src/mongo/db/repl/read_concern_args.cpp b/src/mongo/db/repl/read_concern_args.cpp
index 2352547deb5..fc85048d4b4 100644
--- a/src/mongo/db/repl/read_concern_args.cpp
+++ b/src/mongo/db/repl/read_concern_args.cpp
@@ -172,6 +172,11 @@ Status ReadConcernArgs::initialize(const BSONElement& readConcernElem) {
<< kMajorityReadConcernStr);
}
+ if (_clusterTime && _clusterTime == LogicalTime::kUninitialized) {
+ return Status(ErrorCodes::InvalidOptions,
+ str::stream() << kAfterClusterTimeFieldName << " cannot be a null timestamp");
+ }
+
return Status::OK();
}