diff options
-rw-r--r-- | jstests/core/list_databases.js | 4 | ||||
-rw-r--r-- | jstests/core/views/views_all_commands.js | 2 | ||||
-rw-r--r-- | jstests/sharding/logical_time_api.js | 4 | ||||
-rw-r--r-- | jstests/sharding/logical_time_metadata.js | 6 | ||||
-rw-r--r-- | src/mongo/db/commands.h | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_set_request_votes_args.cpp | 2 | ||||
-rw-r--r-- | src/mongo/rpc/metadata.cpp | 25 | ||||
-rw-r--r-- | src/mongo/rpc/metadata/logical_time_metadata.h | 2 | ||||
-rw-r--r-- | src/mongo/rpc/metadata/logical_time_metadata_test.cpp | 40 | ||||
-rw-r--r-- | src/mongo/shell/mongo.js | 22 |
10 files changed, 86 insertions, 23 deletions
diff --git a/jstests/core/list_databases.js b/jstests/core/list_databases.js index cf6dc7aa9c1..80df62f2d1d 100644 --- a/jstests/core/list_databases.js +++ b/jstests/core/list_databases.js @@ -18,8 +18,8 @@ function verifyNameOnly(listDatabasesOut) { for (let field in listDatabasesOut) { - assert(['databases', 'nameOnly', 'ok', 'operationTime', 'logicalTime'].some((f) => f == - field), + assert(['databases', 'nameOnly', 'ok', 'operationTime', '$logicalTime'].some((f) => f == + field), 'unexpected field ' + field); } listDatabasesOut.databases.forEach((database) => { diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js index 4b3db76e8c6..5e4132eb16b 100644 --- a/jstests/core/views/views_all_commands.js +++ b/jstests/core/views/views_all_commands.js @@ -315,7 +315,7 @@ ok: 1 }; delete res.operationTime; - delete res.logicalTime; + delete res.$logicalTime; assert.eq(expectedRes, res, "unexpected result for: " + tojson(killCursorsCmd)); } }, diff --git a/jstests/sharding/logical_time_api.js b/jstests/sharding/logical_time_api.js index fc8a03ceb35..03eb172d11e 100644 --- a/jstests/sharding/logical_time_api.js +++ b/jstests/sharding/logical_time_api.js @@ -11,7 +11,7 @@ "use strict"; // Returns true if the given object contains a logicalTime BSON object in the following format: - // logicalTime: { + // $logicalTime: { // clusterTime: <Timestamp> // signature: { // hash: <BinData> @@ -23,7 +23,7 @@ return false; } - var logicalTime = obj.logicalTime; + var logicalTime = obj.$logicalTime; return logicalTime && isType(logicalTime, "BSON") && isType(logicalTime.clusterTime, "Timestamp") && isType(logicalTime.signature, "BSON") && isType(logicalTime.signature.hash, "BinData") && diff --git a/jstests/sharding/logical_time_metadata.js b/jstests/sharding/logical_time_metadata.js index efb1fcc785c..d62121d584b 100644 --- a/jstests/sharding/logical_time_metadata.js +++ b/jstests/sharding/logical_time_metadata.js @@ -11,9 +11,9 @@ // insert on one shard and extract the logical time var res = assert.commandWorked(db.runCommand({insert: 'user', documents: [{x: 10}]})); - assert.hasFields(res, ['logicalTime']); + assert.hasFields(res, ['$logicalTime']); - var logicalTimeMetadata = res.logicalTime; + var logicalTimeMetadata = res.$logicalTime; assert.hasFields(logicalTimeMetadata, ['clusterTime', 'signature']); res = st.rs0.getPrimary().adminCommand({replSetGetStatus: 1}); @@ -24,7 +24,7 @@ 'appliedTime: ' + tojson(appliedTime) + ' != clusterTime: ' + tojson(logicalTimeMetadata.clusterTime)); - assert.commandWorked(db.runCommand({ping: 1, logicalTime: logicalTimeMetadata})); + assert.commandWorked(db.runCommand({ping: 1, '$logicalTime': logicalTimeMetadata})); st.stop(); diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index a9bfc682712..e4a4ae30889 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -383,7 +383,7 @@ public: arg == "$queryOptions" || // arg == "$readPreference" || // arg == "$replData" || // - arg == "logicalTime" || // + arg == "$logicalTime" || // arg == "maxTimeMS" || // arg == "readConcern" || // arg == "shardVersion" || // diff --git a/src/mongo/db/repl/repl_set_request_votes_args.cpp b/src/mongo/db/repl/repl_set_request_votes_args.cpp index ee15d31ae7b..f126f9ad7c4 100644 --- a/src/mongo/db/repl/repl_set_request_votes_args.cpp +++ b/src/mongo/db/repl/repl_set_request_votes_args.cpp @@ -69,7 +69,7 @@ const std::string kLegalResponseFieldNames[] = { kVoteGrantedFieldName, kOperationTime, "$gleStats", - "logicalTime", + "$logicalTime", "$configServerState", }; diff --git a/src/mongo/rpc/metadata.cpp b/src/mongo/rpc/metadata.cpp index 77545303ff7..80046bdad58 100644 --- a/src/mongo/rpc/metadata.cpp +++ b/src/mongo/rpc/metadata.cpp @@ -183,17 +183,32 @@ CommandAndMetadata upconvertRequestMetadata(BSONObj legacyCmdObj, int queryFlags uassertStatusOK( AuditMetadata::upconvert(legacyCmdObj, queryFlags, &auditCommandBob, &metadataBob)); - return std::make_tuple(auditCommandBob.obj(), metadataBob.obj()); + BSONObjBuilder logicalTimeCommandBob; + for (auto elem : auditCommandBob.done()) { + if (elem.fieldNameStringData() == LogicalTimeMetadata::fieldName()) { + metadataBob.append(elem); + } else { + logicalTimeCommandBob.append(elem); + } + } + + return std::make_tuple(logicalTimeCommandBob.obj(), metadataBob.obj()); } LegacyCommandAndFlags downconvertRequestMetadata(BSONObj cmdObj, BSONObj metadata) { int legacyQueryFlags = 0; + BSONObjBuilder logicalTimeCommandBob; + logicalTimeCommandBob.appendElements(cmdObj); + if (auto logicalTime = metadata[LogicalTimeMetadata::fieldName()]) { + logicalTimeCommandBob.append(logicalTime); + } + + // Ordering is important here - AuditingMetadata must be downconverted before ReadPreference. BSONObjBuilder auditCommandBob; - // Ordering is important here - AuditingMetadata must be downconverted first, - // then ReadPreference. - uassertStatusOK( - AuditMetadata::downconvert(cmdObj, metadata, &auditCommandBob, &legacyQueryFlags)); + uassertStatusOK(AuditMetadata::downconvert( + logicalTimeCommandBob.done(), metadata, &auditCommandBob, &legacyQueryFlags)); + cmdObj = auditCommandBob.obj(); auto readPref = metadata["$readPreference"]; if (!readPref) diff --git a/src/mongo/rpc/metadata/logical_time_metadata.h b/src/mongo/rpc/metadata/logical_time_metadata.h index 2ec6b7f03b5..f47d27fba8c 100644 --- a/src/mongo/rpc/metadata/logical_time_metadata.h +++ b/src/mongo/rpc/metadata/logical_time_metadata.h @@ -65,7 +65,7 @@ public: const SignedLogicalTime& getSignedTime() const; static StringData fieldName() { - return "logicalTime"; + return "$logicalTime"; } private: diff --git a/src/mongo/rpc/metadata/logical_time_metadata_test.cpp b/src/mongo/rpc/metadata/logical_time_metadata_test.cpp index 73e9ad64208..bcc50a392cc 100644 --- a/src/mongo/rpc/metadata/logical_time_metadata_test.cpp +++ b/src/mongo/rpc/metadata/logical_time_metadata_test.cpp @@ -31,6 +31,7 @@ #include "mongo/platform/basic.h" #include "mongo/db/jsobj.h" +#include "mongo/rpc/metadata.h" #include "mongo/rpc/metadata/logical_time_metadata.h" #include "mongo/unittest/unittest.h" @@ -74,7 +75,7 @@ TEST(LogicalTimeMetadataTest, MissingClusterTimeShouldFailToParse) { long long keyId = 1; BSONObjBuilder builder; - BSONObjBuilder subObjBuilder(builder.subobjStart("logicalTime")); + BSONObjBuilder subObjBuilder(builder.subobjStart("$logicalTime")); BSONObjBuilder signatureObjBuilder(subObjBuilder.subobjStart("signature")); signatureObjBuilder.append("hash", BSONBinData(proof.data(), proof.size(), BinDataGeneral)); signatureObjBuilder.append("keyId", keyId); @@ -90,7 +91,7 @@ TEST(LogicalTimeMetadataTest, MissingSignatureShouldFailToParse) { const auto ts = Timestamp(100, 200); BSONObjBuilder builder; - BSONObjBuilder subObjBuilder(builder.subobjStart("logicalTime")); + BSONObjBuilder subObjBuilder(builder.subobjStart("$logicalTime")); ts.append(subObjBuilder.bb(), "clusterTime"); subObjBuilder.doneFast(); @@ -105,7 +106,7 @@ TEST(LogicalTimeMetadataTest, MissingHashShouldFailToParse) { long long keyId = 1; BSONObjBuilder builder; - BSONObjBuilder subObjBuilder(builder.subobjStart("logicalTime")); + BSONObjBuilder subObjBuilder(builder.subobjStart("$logicalTime")); ts.append(subObjBuilder.bb(), "clusterTime"); BSONObjBuilder signatureObjBuilder(subObjBuilder.subobjStart("signature")); signatureObjBuilder.append("keyId", keyId); @@ -124,7 +125,7 @@ TEST(LogicalTimeMetadataTest, MissingKeyIdShouldFailToParse) { proof.fill(0); BSONObjBuilder builder; - BSONObjBuilder subObjBuilder(builder.subobjStart("logicalTime")); + BSONObjBuilder subObjBuilder(builder.subobjStart("$logicalTime")); ts.append(subObjBuilder.bb(), "clusterTime"); BSONObjBuilder signatureObjBuilder(subObjBuilder.subobjStart("signature")); signatureObjBuilder.append("hash", BSONBinData(proof.data(), proof.size(), BinDataGeneral)); @@ -145,7 +146,7 @@ TEST(LogicalTimeMetadataTest, ProofWithWrongLengthShouldFailToParse) { long long keyId = 1; BSONObjBuilder builder; - BSONObjBuilder subObjBuilder(builder.subobjStart("logicalTime")); + BSONObjBuilder subObjBuilder(builder.subobjStart("$logicalTime")); ts.append(subObjBuilder.bb(), "clusterTime"); BSONObjBuilder signatureObjBuilder(subObjBuilder.subobjStart("signature")); signatureObjBuilder.append("hash", BSONBinData(proof.data(), proof.size(), BinDataGeneral)); @@ -158,6 +159,35 @@ TEST(LogicalTimeMetadataTest, ProofWithWrongLengthShouldFailToParse) { ASSERT_EQ(ErrorCodes::UnsupportedFormat, status); } +TEST(LogicalTimeMetadataTest, UpconvertPass) { + + const auto ts = Timestamp(100, 200); + + std::array<uint8_t, 20> proof; + proof.fill(0); + + long long keyId = 1; + + BSONObjBuilder builder; + builder.append("aaa", 1); + builder.append("bbb", 1); + BSONObjBuilder subObjBuilder(builder.subobjStart("$logicalTime")); + ts.append(subObjBuilder.bb(), "clusterTime"); + BSONObjBuilder signatureObjBuilder(subObjBuilder.subobjStart("signature")); + signatureObjBuilder.append("hash", BSONBinData(proof.data(), proof.size(), BinDataGeneral)); + signatureObjBuilder.append("keyId", keyId); + signatureObjBuilder.doneFast(); + auto logicalTimeMetadata = subObjBuilder.asTempObj(); + subObjBuilder.doneFast(); + + auto commandObj = builder.done(); + BSONObjBuilder metadataBob; + BSONObjBuilder commandBob; + auto converted = upconvertRequestMetadata(commandObj, 0); + ASSERT_BSONOBJ_EQ(BSON("aaa" << 1 << "bbb" << 1), std::get<0>(converted)); + ASSERT_BSONOBJ_EQ(BSON("$logicalTime" << logicalTimeMetadata), std::get<1>(converted)); +} + } // namespace rpc } // namespace mongo } diff --git a/src/mongo/shell/mongo.js b/src/mongo/shell/mongo.js index 834568dc87a..471a0e3285c 100644 --- a/src/mongo/shell/mongo.js +++ b/src/mongo/shell/mongo.js @@ -14,6 +14,9 @@ if (!Mongo.prototype) { (function(original) { Mongo.prototype.find = function find(ns, query, fields, limit, skip, batchSize, options) { const self = this; + if (this._isCausal) { + query = this._gossipLogicalTime(query); + } const res = original.call(this, ns, query, fields, limit, skip, batchSize, options); const origNext = res.next; res.next = function next() { @@ -145,6 +148,15 @@ Mongo.prototype._injectAfterClusterTime = function(cmdObj) { return cmdObj; }; +Mongo.prototype._gossipLogicalTime = function(obj) { + obj = Object.assign({}, obj); + const clusterTime = this.getClusterTime(); + if (clusterTime) { + obj["$logicalTime"] = clusterTime; + } + return obj; +}; + /** * Sets logicalTime and operationTime extracted from command reply. * This is applicable for the protocol starting from version 3.6. @@ -153,8 +165,8 @@ Mongo.prototype._setLogicalTimeFromReply = function(res) { if (res.hasOwnProperty("operationTime")) { this.setOperationTime(res["operationTime"]); } - if (res.hasOwnProperty("logicalTime")) { - this.setClusterTime(res["logicalTime"]); + if (res.hasOwnProperty("$logicalTime")) { + this.setClusterTime(res["$logicalTime"]); } }; @@ -167,6 +179,9 @@ Mongo.prototype._setLogicalTimeFromReply = function(res) { if (this.isCausalConsistencyEnabled(cmdName, cmdObj) && cmdObj) { cmdObj = this._injectAfterClusterTime(cmdObj); } + if (this._isCausal) { + metadata = this._gossipLogicalTime(metadata); + } const res = original.call(this, dbName, cmdName, metadata, cmdObj); this._setLogicalTimeFromReply(res); return res; @@ -183,6 +198,9 @@ Mongo.prototype._setLogicalTimeFromReply = function(res) { if (this.isCausalConsistencyEnabled(cmdName, cmdObj) && cmdObj) { cmdObj = this._injectAfterClusterTime(cmdObj); } + if (this._isCausal) { + cmdObj = this._gossipLogicalTime(cmdObj); + } const res = original.call(this, dbName, cmdObj, options); this._setLogicalTimeFromReply(res); return res; |