diff options
author | Lingzhi Deng <lingzhi.deng@mongodb.com> | 2020-06-15 13:52:06 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-06-15 21:17:51 +0000 |
commit | 1261db4a593fe06c5139fc0c9877c406d76b5bb4 (patch) | |
tree | c01de597d19ddc99496c8c5557ca04e9ae4d8cf3 | |
parent | 97631cdd42360d4a2d07941ae989a0047707914e (diff) | |
download | mongo-1261db4a593fe06c5139fc0c9877c406d76b5bb4.tar.gz |
SERVER-48557: Omit cursor.atClusterTime field from read replies in transactions
-rw-r--r-- | jstests/noPassthrough/readConcern_snapshot.js | 33 | ||||
-rw-r--r-- | jstests/noPassthrough/readConcern_snapshot_mongos.js | 38 | ||||
-rw-r--r-- | src/mongo/db/commands/distinct.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/commands/find_cmd.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/getmore_cmd.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/run_aggregate.cpp | 4 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_distinct_cmd.cpp | 3 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_find_cmd.cpp | 5 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_aggregation_planner.cpp | 4 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_find.cpp | 4 |
10 files changed, 76 insertions, 26 deletions
diff --git a/jstests/noPassthrough/readConcern_snapshot.js b/jstests/noPassthrough/readConcern_snapshot.js index 2e2a7779415..a4d335af6b4 100644 --- a/jstests/noPassthrough/readConcern_snapshot.js +++ b/jstests/noPassthrough/readConcern_snapshot.js @@ -1,4 +1,5 @@ -// Test parsing of readConcern level 'snapshot'. +// Test parsing of readConcern level 'snapshot' and the presence of the 'atClusterTime' field in +// snapshot cursor responses. // @tags: [requires_majority_read_concern, requires_replication, uses_transactions] (function() { "use strict"; @@ -113,17 +114,25 @@ sessionDb = session.getDatabase(dbName); // readConcern 'snapshot' is supported by find in a transaction. session.startTransaction({readConcern: {level: "snapshot"}, writeConcern: {w: "majority"}}); -assert.commandWorked(sessionDb.runCommand({find: collName})); +let res = assert.commandWorked(sessionDb.runCommand({find: collName, batchSize: 0})); +assert(!res.cursor.hasOwnProperty("atClusterTime"), tojson(res)); + +// readConcern 'snapshot' is supported by getMore in a transaction. +res = assert.commandWorked(sessionDb.runCommand({getMore: res.cursor.id, collection: collName})); +assert(!res.cursor.hasOwnProperty("atClusterTime"), tojson(res)); // readConcern 'snapshot' is supported by aggregate in a transaction. -assert.commandWorked(sessionDb.runCommand({aggregate: collName, pipeline: [], cursor: {}})); +res = assert.commandWorked(sessionDb.runCommand({aggregate: collName, pipeline: [], cursor: {}})); +assert(!res.cursor.hasOwnProperty("atClusterTime"), tojson(res)); // readConcern 'snapshot' is supported by distinct in a transaction. -assert.commandWorked(sessionDb.runCommand({distinct: collName, key: "x"})); +res = assert.commandWorked(sessionDb.runCommand({distinct: collName, key: "x"})); +assert(!res.hasOwnProperty("atClusterTime"), tojson(res)); // readConcern 'snapshot' is supported by geoSearch in a transaction. -assert.commandWorked( +res = assert.commandWorked( sessionDb.runCommand({geoSearch: collName, near: [0, 0], maxDistance: 1, search: {a: 1}})); +assert(!res.hasOwnProperty("atClusterTime"), tojson(res)); // readConcern 'snapshot' is not supported by non-CRUD commands in a transaction. assert.commandFailedWithCode(sessionDb.runCommand({dropIndexes: collName, index: "a_1"}), @@ -136,15 +145,23 @@ const snapshotReadConcern = { level: "snapshot" }; // readConcern 'snapshot' is supported by find outside of transactions. -assert.commandWorked(testDB.runCommand({find: collName, readConcern: snapshotReadConcern})); +res = assert.commandWorked( + testDB.runCommand({find: collName, batchSize: 0, readConcern: snapshotReadConcern})); +assert(res.cursor.hasOwnProperty("atClusterTime"), tojson(res)); + +// readConcern 'snapshot' is supported by getMore outside of a transaction. +res = assert.commandWorked(testDB.runCommand({getMore: res.cursor.id, collection: collName})); +assert(res.cursor.hasOwnProperty("atClusterTime"), tojson(res)); // readConcern 'snapshot' is supported by aggregate outside of transactions. -assert.commandWorked(testDB.runCommand( +res = assert.commandWorked(testDB.runCommand( {aggregate: collName, pipeline: [], cursor: {}, readConcern: snapshotReadConcern})); +assert(res.cursor.hasOwnProperty("atClusterTime"), tojson(res)); // readConcern 'snapshot' is supported by distinct outside of transactions. -assert.commandWorked( +res = assert.commandWorked( testDB.runCommand({distinct: collName, key: "x", readConcern: snapshotReadConcern})); +assert(res.hasOwnProperty("atClusterTime"), tojson(res)); // readConcern 'snapshot' is not supported by geoSearch outside of transactions. assert.commandFailedWithCode(testDB.runCommand({ diff --git a/jstests/noPassthrough/readConcern_snapshot_mongos.js b/jstests/noPassthrough/readConcern_snapshot_mongos.js index c1be784e73a..ee61cb86e8d 100644 --- a/jstests/noPassthrough/readConcern_snapshot_mongos.js +++ b/jstests/noPassthrough/readConcern_snapshot_mongos.js @@ -1,4 +1,5 @@ -// Test parsing of readConcern level 'snapshot' on mongos. +// Test parsing of readConcern level 'snapshot' and the presence of the 'atClusterTime' field in +// snapshot cursor responses on mongos. // @tags: [requires_replication,requires_sharding, uses_transactions, uses_atclustertime] (function() { "use strict"; @@ -9,7 +10,13 @@ load("jstests/sharding/libs/sharded_transactions_helpers.js"); // success. function expectSuccessInTxnThenAbort(session, sessionConn, cmdObj) { session.startTransaction(); - assert.commandWorked(sessionConn.runCommand(cmdObj)); + let res = assert.commandWorked(sessionConn.runCommand(cmdObj)); + // Transaction reads should not have 'atClusterTime' field in responses. + if (res.hasOwnProperty("cursor")) { + assert(!res.cursor.hasOwnProperty("atClusterTime"), tojson(res)); + } else { + assert(!res.hasOwnProperty("atClusterTime"), tojson(res)); + } assert.commandWorked(session.abortTransaction_forTesting()); } @@ -65,11 +72,14 @@ expectSuccessInTxnThenAbort(session, sessionDb, { readConcern: {level: "snapshot"}, }); -// readConcern 'snapshot' is supported by find on mongos in a transaction. -expectSuccessInTxnThenAbort(session, sessionDb, { - find: collName, - readConcern: {level: "snapshot"}, -}); +// readConcern 'snapshot' is supported by find and getMore on mongos in a transaction. +session.startTransaction(); +let res = assert.commandWorked( + sessionDb.runCommand({find: collName, batchSize: 0, readConcern: {level: "snapshot"}})); +assert(!res.cursor.hasOwnProperty("atClusterTime")); +res = assert.commandWorked(sessionDb.runCommand({getMore: res.cursor.id, collection: collName})); +assert(!res.cursor.hasOwnProperty("atClusterTime")); +assert.commandWorked(session.abortTransaction_forTesting()); // readConcern 'snapshot' is supported by distinct on mongos in a transaction. expectSuccessInTxnThenAbort(session, sessionDb, { @@ -101,15 +111,23 @@ const snapshotReadConcern = { level: "snapshot" }; // readConcern 'snapshot' is supported by find outside of transactions on mongos. -assert.commandWorked(testDB.runCommand({find: collName, readConcern: snapshotReadConcern})); +res = assert.commandWorked( + testDB.runCommand({find: collName, batchSize: 0, readConcern: snapshotReadConcern})); +assert(res.cursor.hasOwnProperty("atClusterTime"), tojson(res)); + +// readConcern 'snapshot' is supported by getMore outside of transactions on mongos. +res = assert.commandWorked(testDB.runCommand({getMore: res.cursor.id, collection: collName})); +assert(res.cursor.hasOwnProperty("atClusterTime"), tojson(res)); // readConcern 'snapshot' is supported by aggregate outside of transactions on mongos. -assert.commandWorked(testDB.runCommand( +res = assert.commandWorked(testDB.runCommand( {aggregate: collName, pipeline: [], cursor: {}, readConcern: snapshotReadConcern})); +assert(res.cursor.hasOwnProperty("atClusterTime"), tojson(res)); // readConcern 'snapshot' is supported by distinct outside of transactions on mongos. -assert.commandWorked( +res = assert.commandWorked( testDB.runCommand({distinct: collName, key: "x", readConcern: snapshotReadConcern})); +assert(res.hasOwnProperty("atClusterTime"), tojson(res)); // readConcern 'snapshot' is not supported by count on mongos. assert.commandFailedWithCode(testDB.runCommand({count: collName, readConcern: snapshotReadConcern}), diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp index 3ef8faf0bfa..d43ab866f4f 100644 --- a/src/mongo/db/commands/distinct.cpp +++ b/src/mongo/db/commands/distinct.cpp @@ -315,7 +315,8 @@ public: } valueListBuilder.doneFast(); - if (repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime()) { + if (!opCtx->inMultiDocumentTransaction() && + repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime()) { result.append("atClusterTime"_sd, repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime()->asTimestamp()); } diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index 8eeb6f8d45b..33585aa5596 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -526,7 +526,9 @@ public: // Stream query results, adding them to a BSONArray as we go. CursorResponseBuilder::Options options; options.isInitialResponse = true; - options.atClusterTime = repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime(); + if (!opCtx->inMultiDocumentTransaction()) { + options.atClusterTime = repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime(); + } CursorResponseBuilder firstBatch(result, options); Document doc; PlanExecutor::ExecState state = PlanExecutor::ADVANCED; diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp index 6ed119df16d..70ef0d0f706 100644 --- a/src/mongo/db/commands/getmore_cmd.cpp +++ b/src/mongo/db/commands/getmore_cmd.cpp @@ -573,7 +573,9 @@ public: CursorId respondWithId = 0; CursorResponseBuilder::Options options; - options.atClusterTime = repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime(); + if (!opCtx->inMultiDocumentTransaction()) { + options.atClusterTime = repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime(); + } CursorResponseBuilder nextBatch(reply, options); BSONObj obj; std::uint64_t numResults = 0; diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp index 330d74db102..38e9b713853 100644 --- a/src/mongo/db/commands/run_aggregate.cpp +++ b/src/mongo/db/commands/run_aggregate.cpp @@ -153,7 +153,9 @@ bool handleCursorCommand(OperationContext* opCtx, CursorResponseBuilder::Options options; options.isInitialResponse = true; - options.atClusterTime = repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime(); + if (!opCtx->inMultiDocumentTransaction()) { + options.atClusterTime = repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime(); + } CursorResponseBuilder responseBuilder(result, options); auto curOp = CurOp::get(opCtx); diff --git a/src/mongo/s/commands/cluster_distinct_cmd.cpp b/src/mongo/s/commands/cluster_distinct_cmd.cpp index 2f98bfbf195..7359c79e910 100644 --- a/src/mongo/s/commands/cluster_distinct_cmd.cpp +++ b/src/mongo/s/commands/cluster_distinct_cmd.cpp @@ -259,7 +259,8 @@ public: result.appendArray("values", b.obj()); // If mongos selected atClusterTime or received it from client, transmit it back. - if (repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime()) { + if (!opCtx->inMultiDocumentTransaction() && + repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime()) { result.append("atClusterTime"_sd, repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime()->asTimestamp()); } diff --git a/src/mongo/s/commands/cluster_find_cmd.cpp b/src/mongo/s/commands/cluster_find_cmd.cpp index 7ebab369391..51d6272400b 100644 --- a/src/mongo/s/commands/cluster_find_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_cmd.cpp @@ -230,7 +230,10 @@ public: // Build the response document. CursorResponseBuilder::Options options; options.isInitialResponse = true; - options.atClusterTime = repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime(); + if (!opCtx->inMultiDocumentTransaction()) { + options.atClusterTime = + repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime(); + } CursorResponseBuilder firstBatch(result, options); for (const auto& obj : batch) { firstBatch.append(obj); diff --git a/src/mongo/s/query/cluster_aggregation_planner.cpp b/src/mongo/s/query/cluster_aggregation_planner.cpp index 5b7ea00286f..79aff1295c6 100644 --- a/src/mongo/s/query/cluster_aggregation_planner.cpp +++ b/src/mongo/s/query/cluster_aggregation_planner.cpp @@ -269,7 +269,9 @@ BSONObj establishMergingMongosCursor(OperationContext* opCtx, rpc::OpMsgReplyBuilder replyBuilder; CursorResponseBuilder::Options options; options.isInitialResponse = true; - options.atClusterTime = repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime(); + if (!opCtx->inMultiDocumentTransaction()) { + options.atClusterTime = repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime(); + } CursorResponseBuilder responseBuilder(&replyBuilder, options); bool stashedResult = false; diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp index cb6c4f394ef..6f374202b8f 100644 --- a/src/mongo/s/query/cluster_find.cpp +++ b/src/mongo/s/query/cluster_find.cpp @@ -848,7 +848,9 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, "waitBeforeUnpinningOrDeletingCursorAfterGetMoreBatch"); } - auto atClusterTime = repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime(); + auto atClusterTime = !opCtx->inMultiDocumentTransaction() + ? repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime() + : boost::none; return CursorResponse(request.nss, idToReturn, std::move(batch), |