diff options
author | A. Jesse Jiryu Davis <jesse@mongodb.com> | 2020-06-11 15:52:54 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-06-11 20:17:46 +0000 |
commit | e485c1a8011d85682cb8dafa87ab92b9c23daa66 (patch) | |
tree | 6f81bf10da29be6451f073af361b5f8e94252bc5 /src | |
parent | 5c7cdc392c2ea058d7ec93609203fcc5bb74bb99 (diff) | |
download | mongo-e485c1a8011d85682cb8dafa87ab92b9c23daa66.tar.gz |
Revert "SERVER-47952 Shard selects timestamp for one-shard snapshot find"
This reverts commit 219dadadf97345a4cceab50f04e87b361a749c6c.
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/read_concern_mongod.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/read_concern_args.cpp | 36 | ||||
-rw-r--r-- | src/mongo/db/repl/read_concern_args.h | 28 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_command_test_fixture.cpp | 191 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_command_test_fixture.h | 71 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_delete_test.cpp | 4 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_distinct_test.cpp | 6 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_find_and_modify_test.cpp | 4 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_find_test.cpp | 55 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_insert_test.cpp | 4 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_update_test.cpp | 4 | ||||
-rw-r--r-- | src/mongo/s/commands/strategy.cpp | 5 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_aggregate_test.cpp | 7 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_find.cpp | 26 |
14 files changed, 117 insertions, 326 deletions
diff --git a/src/mongo/db/read_concern_mongod.cpp b/src/mongo/db/read_concern_mongod.cpp index 5d8027b3f71..3663b9cdcc5 100644 --- a/src/mongo/db/read_concern_mongod.cpp +++ b/src/mongo/db/read_concern_mongod.cpp @@ -374,7 +374,7 @@ Status waitForReadConcernImpl(OperationContext* opCtx, "No committed OpTime for snapshot read", !opTime.isNull()); ru->setTimestampReadSource(RecoveryUnit::ReadSource::kProvided, opTime.getTimestamp()); - repl::ReadConcernArgs::get(opCtx).setArgsAtClusterTime(opTime.getTimestamp()); + repl::ReadConcernArgs::get(opCtx).setArgsAtClusterTimeForSnapshot(opTime.getTimestamp()); } else if (readConcernArgs.getLevel() == repl::ReadConcernLevel::kMajorityReadConcern && replCoord->getReplicationMode() == repl::ReplicationCoordinator::Mode::modeReplSet) { // This block is not used for kSnapshotReadConcern because snapshots are always speculative; diff --git a/src/mongo/db/repl/read_concern_args.cpp b/src/mongo/db/repl/read_concern_args.cpp index 9de1dd105d8..d1067a0ff2e 100644 --- a/src/mongo/db/repl/read_concern_args.cpp +++ b/src/mongo/db/repl/read_concern_args.cpp @@ -73,11 +73,9 @@ ReadConcernArgs::ReadConcernArgs(boost::optional<OpTime> opTime, ReadConcernArgs::ReadConcernArgs(boost::optional<LogicalTime> clusterTime, boost::optional<ReadConcernLevel> level) - : _clientAfterClusterTime(std::move(clusterTime)), + : _afterClusterTime(std::move(clusterTime)), _level(std::move(level)), - _specified(_clientAfterClusterTime || _level) { - _computedAfterClusterTime = _clientAfterClusterTime; -} + _specified(_afterClusterTime || _level) {} std::string ReadConcernArgs::toString() const { return toBSON().toString(); @@ -96,7 +94,7 @@ BSONObj ReadConcernArgs::toBSONInner() const { } bool ReadConcernArgs::isEmpty() const { - return !_computedAfterClusterTime && !_opTime && !_computedAtClusterTime && !_level; + return !_afterClusterTime && !_opTime && !_atClusterTime && !_level; } bool ReadConcernArgs::isSpecified() const { @@ -116,11 +114,11 @@ boost::optional<OpTime> ReadConcernArgs::getArgsOpTime() const { } boost::optional<LogicalTime> ReadConcernArgs::getArgsAfterClusterTime() const { - return _computedAfterClusterTime; + return _afterClusterTime; } boost::optional<LogicalTime> ReadConcernArgs::getArgsAtClusterTime() const { - return _computedAtClusterTime; + return _atClusterTime; } Status ReadConcernArgs::initialize(const BSONElement& readConcernElem) { @@ -160,7 +158,7 @@ Status ReadConcernArgs::parse(const BSONObj& readConcernObj) { if (!afterClusterTimeStatus.isOK()) { return afterClusterTimeStatus; } - _computedAfterClusterTime = _clientAfterClusterTime = LogicalTime(afterClusterTime); + _afterClusterTime = LogicalTime(afterClusterTime); } else if (fieldName == kAtClusterTimeFieldName) { Timestamp atClusterTime; auto atClusterTimeStatus = @@ -168,7 +166,7 @@ Status ReadConcernArgs::parse(const BSONObj& readConcernObj) { if (!atClusterTimeStatus.isOK()) { return atClusterTimeStatus; } - _computedAtClusterTime = _clientAtClusterTime = LogicalTime(atClusterTime); + _atClusterTime = LogicalTime(atClusterTime); } else if (fieldName == kLevelFieldName) { std::string levelString; // TODO pass field in rather than scanning again. @@ -203,13 +201,13 @@ Status ReadConcernArgs::parse(const BSONObj& readConcernObj) { } } - if (_clientAfterClusterTime && _opTime) { + if (_afterClusterTime && _opTime) { return Status(ErrorCodes::InvalidOptions, str::stream() << "Can not specify both " << kAfterClusterTimeFieldName << " and " << kAfterOpTimeFieldName); } - if (_clientAfterClusterTime && _clientAtClusterTime) { + if (_afterClusterTime && _atClusterTime) { return Status(ErrorCodes::InvalidOptions, "Specifying a timestamp for readConcern snapshot in a causally consistent " "session is not allowed. See " @@ -220,7 +218,7 @@ Status ReadConcernArgs::parse(const BSONObj& readConcernObj) { // Note: 'available' should not be used with after cluster time, as cluster time can wait for // replication whereas the premise of 'available' is to avoid waiting. 'linearizable' should not // be used with after cluster time, since linearizable reads are inherently causally consistent. - if (_clientAfterClusterTime && getLevel() != ReadConcernLevel::kMajorityReadConcern && + if (_afterClusterTime && getLevel() != ReadConcernLevel::kMajorityReadConcern && getLevel() != ReadConcernLevel::kLocalReadConcern && getLevel() != ReadConcernLevel::kSnapshotReadConcern) { return Status(ErrorCodes::InvalidOptions, @@ -238,7 +236,7 @@ Status ReadConcernArgs::parse(const BSONObj& readConcernObj) { << " is equal to " << readConcernLevels::kSnapshotName); } - if (_clientAtClusterTime && getLevel() != ReadConcernLevel::kSnapshotReadConcern) { + if (_atClusterTime && getLevel() != ReadConcernLevel::kSnapshotReadConcern) { return Status(ErrorCodes::InvalidOptions, str::stream() << kAtClusterTimeFieldName << " field can be set only if " << kLevelFieldName << " is equal to " @@ -246,14 +244,14 @@ Status ReadConcernArgs::parse(const BSONObj& readConcernObj) { } // Make sure that atClusterTime wasn't specified with zero seconds. - if (_clientAtClusterTime && _clientAtClusterTime->asTimestamp().isNull()) { + if (_atClusterTime && _atClusterTime->asTimestamp().isNull()) { return Status(ErrorCodes::InvalidOptions, str::stream() << kAtClusterTimeFieldName << " cannot be a null timestamp"); } // It's okay for afterClusterTime to be specified with zero seconds, but not an uninitialized // timestamp. - if (_clientAfterClusterTime && _clientAfterClusterTime == LogicalTime::kUninitialized) { + if (_afterClusterTime && _afterClusterTime == LogicalTime::kUninitialized) { return Status(ErrorCodes::InvalidOptions, str::stream() << kAfterClusterTimeFieldName << " cannot be a null timestamp"); } @@ -292,12 +290,12 @@ void ReadConcernArgs::_appendInfoInner(BSONObjBuilder* builder) const { _opTime->append(builder, kAfterOpTimeFieldName.toString()); } - if (_computedAfterClusterTime) { - builder->append(kAfterClusterTimeFieldName, _computedAfterClusterTime->asTimestamp()); + if (_afterClusterTime) { + builder->append(kAfterClusterTimeFieldName, _afterClusterTime->asTimestamp()); } - if (_computedAtClusterTime) { - builder->append(kAtClusterTimeFieldName, _computedAtClusterTime->asTimestamp()); + if (_atClusterTime) { + builder->append(kAtClusterTimeFieldName, _atClusterTime->asTimestamp()); } _provenance.serialize(builder); diff --git a/src/mongo/db/repl/read_concern_args.h b/src/mongo/db/repl/read_concern_args.h index 2c7aca60282..ba6004d13bf 100644 --- a/src/mongo/db/repl/read_concern_args.h +++ b/src/mongo/db/repl/read_concern_args.h @@ -182,21 +182,13 @@ public: * Set atClusterTime, clear afterClusterTime. The BSON representation becomes * {level: "snapshot", atClusterTime: <ts>}. */ - void setArgsAtClusterTime(Timestamp ts) { + void setArgsAtClusterTimeForSnapshot(Timestamp ts) { invariant(_level && _level == ReadConcernLevel::kSnapshotReadConcern); // Only overwrite a server-selected atClusterTime, not user-supplied. - invariant(!_clientAtClusterTime); - _computedAfterClusterTime = boost::none; - _computedAtClusterTime = LogicalTime(ts); - } - - /** - * If we have selected an atClusterTime for non-transaction snapshot reads, clear it and restore - * the atClusterTime and afterClusterTime passed by the client. - */ - void clearArgsAtClusterTime() { - _computedAfterClusterTime = _clientAfterClusterTime; - _computedAtClusterTime = _clientAtClusterTime; + invariant(_atClusterTime.is_initialized() == _atClusterTimeSelected); + _afterClusterTime = boost::none; + _atClusterTime = LogicalTime(ts); + _atClusterTimeSelected = true; } /** @@ -204,7 +196,7 @@ public: * function returns false if the atClusterTime was specified by the client. */ bool wasAtClusterTimeSelected() const { - return _computedAtClusterTime && _computedAtClusterTime != _clientAtClusterTime; + return _atClusterTimeSelected; } private: @@ -221,13 +213,11 @@ private: /** * Read data after cluster-wide cluster time. */ - boost::optional<LogicalTime> _clientAfterClusterTime; - boost::optional<LogicalTime> _computedAfterClusterTime; + boost::optional<LogicalTime> _afterClusterTime; /** * Read data at a particular cluster time. */ - boost::optional<LogicalTime> _clientAtClusterTime; - boost::optional<LogicalTime> _computedAtClusterTime; + boost::optional<LogicalTime> _atClusterTime; boost::optional<ReadConcernLevel> _level; /** @@ -243,6 +233,8 @@ private: bool _specified; ReadWriteConcernProvenance _provenance; + + bool _atClusterTimeSelected = false; }; } // namespace repl diff --git a/src/mongo/s/commands/cluster_command_test_fixture.cpp b/src/mongo/s/commands/cluster_command_test_fixture.cpp index 2b76854de31..31bee683dbf 100644 --- a/src/mongo/s/commands/cluster_command_test_fixture.cpp +++ b/src/mongo/s/commands/cluster_command_test_fixture.cpp @@ -42,19 +42,12 @@ #include "mongo/db/logical_time_validator.h" #include "mongo/db/vector_clock.h" #include "mongo/s/cluster_last_error_info.h" -#include "mongo/s/query/cluster_cursor_manager.h" #include "mongo/util/fail_point.h" #include "mongo/util/options_parser/startup_option_init.h" #include "mongo/util/tick_source_mock.h" namespace mongo { -const Timestamp ClusterCommandTestFixture::kAfterClusterTime(50, 2); - -const Timestamp ClusterCommandTestFixture::kShardClusterTime(51, 3); - -const CursorId ClusterCommandTestFixture::kCursorId(123); - void ClusterCommandTestFixture::setUp() { CatalogCacheTestFixture::setUp(); CatalogCacheTestFixture::setupNShards(numShards); @@ -86,24 +79,13 @@ void ClusterCommandTestFixture::setUp() { "enableStaleVersionAndSnapshotRetriesWithinTransactions"); } -void ClusterCommandTestFixture::tearDown() { - // Delete any cursors left behind by tests, to avoid invariant in ~ClusterCursorManager. - auto opCtx = operationContext(); - auto cursorManager = Grid::get(opCtx)->getCursorManager(); - cursorManager->killAllCursors(opCtx); -} - -BSONObj ClusterCommandTestFixture::_makeCmd(BSONObj cmdObj, - bool startTransaction, - bool includeAfterClusterTime) { +BSONObj ClusterCommandTestFixture::_makeCmd(BSONObj cmdObj, bool includeAfterClusterTime) { BSONObjBuilder bob(cmdObj); // Each command runs in a new session. bob.append("lsid", makeLogicalSessionIdForTest().toBSON()); - if (startTransaction) { - bob.append("txnNumber", TxnNumber(1)); - bob.append("autocommit", false); - bob.append("startTransaction", true); - } + bob.append("txnNumber", TxnNumber(1)); + bob.append("autocommit", false); + bob.append("startTransaction", true); BSONObjBuilder readConcernBob = bob.subobjStart(repl::ReadConcernArgs::kReadConcernFieldName); readConcernBob.append("level", "snapshot"); @@ -115,14 +97,6 @@ BSONObj ClusterCommandTestFixture::_makeCmd(BSONObj cmdObj, return bob.obj(); } -BSONObj ClusterCommandTestFixture::_makeTxnCmd(BSONObj cmdObj, bool includeAfterClusterTime) { - return _makeCmd(cmdObj, true, includeAfterClusterTime); -} - -BSONObj ClusterCommandTestFixture::_makeNonTxnCmd(BSONObj cmdObj, bool includeAfterClusterTime) { - return _makeCmd(cmdObj, false, includeAfterClusterTime); -} - void ClusterCommandTestFixture::expectReturnsError(ErrorCodes::Error code) { onCommandForPoolExecutor([code](const executor::RemoteCommandRequest& request) { BSONObjBuilder resBob; @@ -252,108 +226,80 @@ void ClusterCommandTestFixture::runTxnCommandMaxErrors(BSONObj cmd, } void ClusterCommandTestFixture::testNoErrors(BSONObj targetedCmd, BSONObj scatterGatherCmd) { + // Target one shard. - runCommandSuccessful(_makeTxnCmd(targetedCmd), true); + runCommandSuccessful(_makeCmd(targetedCmd), true); // Target all shards. if (!scatterGatherCmd.isEmpty()) { - runCommandSuccessful(_makeTxnCmd(scatterGatherCmd), false); + runCommandSuccessful(_makeCmd(scatterGatherCmd), false); } } void ClusterCommandTestFixture::testRetryOnSnapshotError(BSONObj targetedCmd, BSONObj scatterGatherCmd) { // Target one shard. - runTxnCommandOneError(_makeTxnCmd(targetedCmd), ErrorCodes::SnapshotUnavailable, true); - runTxnCommandOneError(_makeTxnCmd(targetedCmd), ErrorCodes::SnapshotTooOld, true); + runTxnCommandOneError(_makeCmd(targetedCmd), ErrorCodes::SnapshotUnavailable, true); + runTxnCommandOneError(_makeCmd(targetedCmd), ErrorCodes::SnapshotTooOld, true); // Target all shards if (!scatterGatherCmd.isEmpty()) { - runTxnCommandOneError( - _makeTxnCmd(scatterGatherCmd), ErrorCodes::SnapshotUnavailable, false); - runTxnCommandOneError(_makeTxnCmd(scatterGatherCmd), ErrorCodes::SnapshotTooOld, false); + runTxnCommandOneError(_makeCmd(scatterGatherCmd), ErrorCodes::SnapshotUnavailable, false); + runTxnCommandOneError(_makeCmd(scatterGatherCmd), ErrorCodes::SnapshotTooOld, false); } } void ClusterCommandTestFixture::testMaxRetriesSnapshotErrors(BSONObj targetedCmd, BSONObj scatterGatherCmd) { // Target one shard. - runTxnCommandMaxErrors(_makeTxnCmd(targetedCmd), ErrorCodes::SnapshotUnavailable, true); - runTxnCommandMaxErrors(_makeTxnCmd(targetedCmd), ErrorCodes::SnapshotTooOld, true); + runTxnCommandMaxErrors(_makeCmd(targetedCmd), ErrorCodes::SnapshotUnavailable, true); + runTxnCommandMaxErrors(_makeCmd(targetedCmd), ErrorCodes::SnapshotTooOld, true); // Target all shards if (!scatterGatherCmd.isEmpty()) { - runTxnCommandMaxErrors( - _makeTxnCmd(scatterGatherCmd), ErrorCodes::SnapshotUnavailable, false); - runTxnCommandMaxErrors(_makeTxnCmd(scatterGatherCmd), ErrorCodes::SnapshotTooOld, false); + runTxnCommandMaxErrors(_makeCmd(scatterGatherCmd), ErrorCodes::SnapshotUnavailable, false); + runTxnCommandMaxErrors(_makeCmd(scatterGatherCmd), ErrorCodes::SnapshotTooOld, false); } } -void ClusterCommandTestFixture::testAttachesAtClusterTimeForTxnSnapshotReadConcern( - BSONObj targetedCmd, BSONObj scatterGatherCmd, bool createsCursor) { - - // Target one shard. - runCommandInspectRequests(_makeTxnCmd(targetedCmd), _containsAtClusterTimeOnly, true); - if (createsCursor) - _assertCursorReadConcern(true, boost::none); - - // Target all shards. - if (!scatterGatherCmd.isEmpty()) { - runCommandInspectRequests(_makeTxnCmd(scatterGatherCmd), _containsAtClusterTimeOnly, false); - if (createsCursor) - _assertCursorReadConcern(false, boost::none); - } -} +void ClusterCommandTestFixture::testAttachesAtClusterTimeForSnapshotReadConcern( + BSONObj targetedCmd, BSONObj scatterGatherCmd) { -void ClusterCommandTestFixture::testTxnSnapshotReadConcernWithAfterClusterTime( - BSONObj targetedCmd, BSONObj scatterGatherCmd, bool createsCursor) { + auto containsAtClusterTime = [](const executor::RemoteCommandRequest& request) { + ASSERT(!request.cmdObj["readConcern"]["atClusterTime"].eoo()); + }; // Target one shard. - runCommandInspectRequests(_makeTxnCmd(targetedCmd, true), _containsAtClusterTimeOnly, true); - if (createsCursor) - _assertCursorReadConcern(true, boost::none); + runCommandInspectRequests(_makeCmd(targetedCmd), containsAtClusterTime, true); // Target all shards. if (!scatterGatherCmd.isEmpty()) { - runCommandInspectRequests( - _makeTxnCmd(scatterGatherCmd, true), _containsAtClusterTimeOnly, false); - if (createsCursor) - _assertCursorReadConcern(false, boost::none); + runCommandInspectRequests(_makeCmd(scatterGatherCmd), containsAtClusterTime, false); } } -void ClusterCommandTestFixture::testAttachesAtClusterTimeForNonTxnSnapshotReadConcern( - BSONObj targetedCmd, BSONObj scatterGatherCmd, bool createsCursor) { - - // Target one shard. - runCommandInspectRequests(_makeNonTxnCmd(targetedCmd), _omitsClusterTime, true); - if (createsCursor) - _assertCursorReadConcern(true, kShardClusterTime); +void ClusterCommandTestFixture::testSnapshotReadConcernWithAfterClusterTime( + BSONObj targetedCmd, BSONObj scatterGatherCmd) { - // Target all shards. - if (!scatterGatherCmd.isEmpty()) { - runCommandInspectRequests( - _makeNonTxnCmd(scatterGatherCmd), _containsAtClusterTimeOnly, false); - if (createsCursor) - _assertCursorReadConcern(false, kInMemoryLogicalTime.asTimestamp()); - } -} + auto containsAtClusterTimeNoAfterClusterTime = + [&](const executor::RemoteCommandRequest& request) { + ASSERT(!request.cmdObj["readConcern"]["atClusterTime"].eoo()); + ASSERT(request.cmdObj["readConcern"]["afterClusterTime"].eoo()); -void ClusterCommandTestFixture::testNonTxnSnapshotReadConcernWithAfterClusterTime( - BSONObj targetedCmd, BSONObj scatterGatherCmd, bool createsCursor) { + // The chosen atClusterTime should be greater than or equal to the request's + // afterClusterTime. + ASSERT_GTE(LogicalTime(request.cmdObj["readConcern"]["atClusterTime"].timestamp()), + LogicalTime(kAfterClusterTime)); + }; // Target one shard. runCommandInspectRequests( - _makeNonTxnCmd(targetedCmd, true), _containsAfterClusterTimeOnly, true); - if (createsCursor) - _assertCursorReadConcern(true, kShardClusterTime); + _makeCmd(targetedCmd, true), containsAtClusterTimeNoAfterClusterTime, true); // Target all shards. if (!scatterGatherCmd.isEmpty()) { runCommandInspectRequests( - _makeNonTxnCmd(scatterGatherCmd, true), _containsAtClusterTimeOnly, false); - if (createsCursor) - _assertCursorReadConcern(false, kAfterClusterTime); + _makeCmd(scatterGatherCmd, true), containsAtClusterTimeNoAfterClusterTime, false); } } @@ -363,73 +309,6 @@ void ClusterCommandTestFixture::appendTxnResponseMetadata(BSONObjBuilder& bob) { txnResponseMetadata.serialize(&bob); } -void ClusterCommandTestFixture::_assertCursorReadConcern( - bool isTargeted, boost::optional<Timestamp> expectedAtClusterTime) { - auto opCtx = operationContext(); - auto cursorManager = Grid::get(opCtx)->getCursorManager(); - auto cursors = - cursorManager->getIdleCursors(opCtx, MongoProcessInterface::CurrentOpUserMode::kIncludeAll); - ASSERT_EQUALS(cursors.size(), 1); - auto cursorId = *cursors[0].getCursorId(); - auto pinnedCursor = cursorManager->checkOutCursor( - kNss, cursorId, opCtx, [](UserNameIterator) { return Status::OK(); }); - - ASSERT_OK(pinnedCursor.getStatus()); - auto readConcern = pinnedCursor.getValue()->getReadConcern(); - auto nRemotes = pinnedCursor.getValue()->getNumRemotes(); - ASSERT_EQUALS(nRemotes, isTargeted ? 1 : 2); - - // User supplies no atClusterTime. If not isTargeted then mongos selected a timestamp and called - // setArgsAtClusterTime. Else mongos let the shard select atClusterTime. The shard returned it - // to mongos, and mongos called setArgsAtClusterTime. - if (expectedAtClusterTime) { - ASSERT_EQUALS(readConcern->getArgsAtClusterTime()->asTimestamp(), *expectedAtClusterTime); - ASSERT_TRUE(readConcern->wasAtClusterTimeSelected()); - } else { - ASSERT_FALSE(readConcern->getArgsAtClusterTime()); - ASSERT_FALSE(readConcern->wasAtClusterTimeSelected()); - } - - // Kill cursor on shard(s) and remove from ClusterCursorManager, to ensure we have exactly 1 - // idle cursor next time this method is called. (Otherwise this test would need a complex - // method for determining which cursor to examine.) - pinnedCursor.getValue().returnCursor(ClusterCursorManager::CursorState::Exhausted); - for (std::size_t i = 0; i < nRemotes; ++i) { - onCommandForPoolExecutor([&](const executor::RemoteCommandRequest& request) { - ASSERT_EQUALS("killCursors"_sd, request.cmdObj.firstElement().fieldNameStringData()); - ASSERT_EQUALS(kNss.coll(), request.cmdObj.firstElement().valueStringData()); - return BSON("ok" << 1); - }); - } -} - -void ClusterCommandTestFixture::_containsSelectedAtClusterTime( - const executor::RemoteCommandRequest& request) { - ASSERT(!request.cmdObj["readConcern"]["atClusterTime"].eoo()); - ASSERT(request.cmdObj["readConcern"]["afterClusterTime"].eoo()); - - // The chosen atClusterTime should be greater than or equal to the request's afterClusterTime. - ASSERT_GTE(LogicalTime(request.cmdObj["readConcern"]["atClusterTime"].timestamp()), - LogicalTime(kAfterClusterTime)); -} - -void ClusterCommandTestFixture::_containsAtClusterTimeOnly( - const executor::RemoteCommandRequest& request) { - ASSERT(!request.cmdObj["readConcern"]["atClusterTime"].eoo()); - ASSERT(request.cmdObj["readConcern"]["afterClusterTime"].eoo()); -} - -void ClusterCommandTestFixture::_containsAfterClusterTimeOnly( - const executor::RemoteCommandRequest& request) { - ASSERT(request.cmdObj["readConcern"]["atClusterTime"].eoo()); - ASSERT(!request.cmdObj["readConcern"]["afterClusterTime"].eoo()); -} - -void ClusterCommandTestFixture::_omitsClusterTime(const executor::RemoteCommandRequest& request) { - ASSERT(request.cmdObj["readConcern"]["atClusterTime"].eoo()); - ASSERT(request.cmdObj["readConcern"]["afterClusterTime"].eoo()); -} - // Satisfies dependency from StoreSASLOPtions. MONGO_STARTUP_OPTIONS_STORE(CoreOptions)(InitializerContext*) { return Status::OK(); diff --git a/src/mongo/s/commands/cluster_command_test_fixture.h b/src/mongo/s/commands/cluster_command_test_fixture.h index 9c0f3f4d5b7..9c5406c073b 100644 --- a/src/mongo/s/commands/cluster_command_test_fixture.h +++ b/src/mongo/s/commands/cluster_command_test_fixture.h @@ -31,7 +31,6 @@ #include "mongo/platform/basic.h" -#include "mongo/db/cursor_id.h" #include "mongo/s/catalog_cache_test_fixture.h" #include "mongo/s/commands/strategy.h" @@ -47,16 +46,10 @@ protected: const LogicalTime kInMemoryLogicalTime = LogicalTime(Timestamp(10, 1)); - static const Timestamp kAfterClusterTime; - - static const Timestamp kShardClusterTime; - - static const CursorId kCursorId; + const Timestamp kAfterClusterTime = Timestamp(50, 2); void setUp() override; - void tearDown() override; - virtual void expectInspectRequest(int shardIndex, InspectionCallback cb) = 0; virtual void expectReturnsSuccess(int shardIndex) = 0; @@ -92,34 +85,17 @@ protected: void testMaxRetriesSnapshotErrors(BSONObj targetedCmd, BSONObj scatterGatherCmd = BSONObj()); /** - * Verifies that atClusterTime is attached to the given commands in a transaction. + * Verifies that atClusterTime is attached to the given commands. */ - void testAttachesAtClusterTimeForTxnSnapshotReadConcern(BSONObj targetedCmd, - BSONObj scatterGatherCmd = BSONObj(), - bool createsCursor = false); + void testAttachesAtClusterTimeForSnapshotReadConcern(BSONObj targetedCmd, + BSONObj scatterGatherCmd = BSONObj()); /** * Verifies that the chosen atClusterTime is greater than or equal to each command's - * afterClusterTime in a transaction. - */ - void testTxnSnapshotReadConcernWithAfterClusterTime(BSONObj targetedCmd, - BSONObj scatterGatherCmd = BSONObj(), - bool createsCursor = false); - - /** - * Verifies that atClusterTime is attached to the given non-transaction snapshot commands. + * afterClusterTime. */ - void testAttachesAtClusterTimeForNonTxnSnapshotReadConcern(BSONObj targetedCmd, - BSONObj scatterGatherCmd = BSONObj(), - bool createsCursor = false); - - /** - * Verifies that the chosen atClusterTime is greater than or equal to each non-transaction - * snapshot command's afterClusterTime. - */ - void testNonTxnSnapshotReadConcernWithAfterClusterTime(BSONObj targetedCmd, - BSONObj scatterGatherCmd = BSONObj(), - bool createsCursor = false); + void testSnapshotReadConcernWithAfterClusterTime(BSONObj targetedCmd, + BSONObj scatterGatherCmd = BSONObj()); /** * Appends the metadata shards return on responses to transaction statements, such as the @@ -129,36 +105,11 @@ protected: private: /** - * Makes a new command object from the one given by appending read concern snapshot and the - * appropriate transaction options. If includeAfterClusterTime is true, also appends - * afterClusterTime to the read concern. + * Makes a new command object from the one given by apppending read concern + * snapshot and the appropriate transaction options. If includeAfterClusterTime + * is true, also appends afterClusterTime to the read concern. */ - BSONObj _makeTxnCmd(BSONObj cmdObj, bool includeAfterClusterTime = false); - - /** - * Makes a new command object from the one given by appending read concern snapshot. If - * includeAfterClusterTime is true, also appends afterClusterTime to the read concern. - */ - BSONObj _makeNonTxnCmd(BSONObj cmdObj, bool includeAfterClusterTime = false); - - /** - * Helper method. - */ - BSONObj _makeCmd(BSONObj cmdObj, bool startTransaction, bool includeAfterClusterTime); - - /* - * Check that the ClusterCursorManager contains an idle cursor with proper readConcern set. - */ - void _assertCursorReadConcern(bool isTargeted, - boost::optional<Timestamp> expectedAtClusterTime); - - static void _containsSelectedAtClusterTime(const executor::RemoteCommandRequest& request); - - static void _containsAtClusterTimeOnly(const executor::RemoteCommandRequest& request); - - static void _containsAfterClusterTimeOnly(const executor::RemoteCommandRequest& request); - - static void _omitsClusterTime(const executor::RemoteCommandRequest& request); + BSONObj _makeCmd(BSONObj cmdObj, bool includeAfterClusterTime = false); // Enables the transaction router to retry within a transaction on stale version and snapshot // errors for the duration of each test. diff --git a/src/mongo/s/commands/cluster_delete_test.cpp b/src/mongo/s/commands/cluster_delete_test.cpp index f0fae5cbeb2..407ce5e78e2 100644 --- a/src/mongo/s/commands/cluster_delete_test.cpp +++ b/src/mongo/s/commands/cluster_delete_test.cpp @@ -73,11 +73,11 @@ TEST_F(ClusterDeleteTest, NoErrors) { } TEST_F(ClusterDeleteTest, AttachesAtClusterTimeForSnapshotReadConcern) { - testAttachesAtClusterTimeForTxnSnapshotReadConcern(kDeleteCmdTargeted, kDeleteCmdScatterGather); + testAttachesAtClusterTimeForSnapshotReadConcern(kDeleteCmdTargeted, kDeleteCmdScatterGather); } TEST_F(ClusterDeleteTest, SnapshotReadConcernWithAfterClusterTime) { - testTxnSnapshotReadConcernWithAfterClusterTime(kDeleteCmdTargeted, kDeleteCmdScatterGather); + testSnapshotReadConcernWithAfterClusterTime(kDeleteCmdTargeted, kDeleteCmdScatterGather); } } // namespace diff --git a/src/mongo/s/commands/cluster_distinct_test.cpp b/src/mongo/s/commands/cluster_distinct_test.cpp index d8513f36dc5..40f0226e820 100644 --- a/src/mongo/s/commands/cluster_distinct_test.cpp +++ b/src/mongo/s/commands/cluster_distinct_test.cpp @@ -80,12 +80,12 @@ TEST_F(ClusterDistinctTest, MaxRetriesSnapshotErrors) { } TEST_F(ClusterDistinctTest, AttachesAtClusterTimeForSnapshotReadConcern) { - testAttachesAtClusterTimeForTxnSnapshotReadConcern(kDistinctCmdTargeted, - kDistinctCmdScatterGather); + testAttachesAtClusterTimeForSnapshotReadConcern(kDistinctCmdTargeted, + kDistinctCmdScatterGather); } TEST_F(ClusterDistinctTest, SnapshotReadConcernWithAfterClusterTime) { - testTxnSnapshotReadConcernWithAfterClusterTime(kDistinctCmdTargeted, kDistinctCmdScatterGather); + testSnapshotReadConcernWithAfterClusterTime(kDistinctCmdTargeted, kDistinctCmdScatterGather); } } // namespace diff --git a/src/mongo/s/commands/cluster_find_and_modify_test.cpp b/src/mongo/s/commands/cluster_find_and_modify_test.cpp index 8f126039fd3..f0a44494591 100644 --- a/src/mongo/s/commands/cluster_find_and_modify_test.cpp +++ b/src/mongo/s/commands/cluster_find_and_modify_test.cpp @@ -78,11 +78,11 @@ TEST_F(ClusterFindAndModifyTest, MaxRetriesSnapshotErrors) { } TEST_F(ClusterFindAndModifyTest, AttachesAtClusterTimeForSnapshotReadConcern) { - testAttachesAtClusterTimeForTxnSnapshotReadConcern(kFindAndModifyCmdTargeted); + testAttachesAtClusterTimeForSnapshotReadConcern(kFindAndModifyCmdTargeted); } TEST_F(ClusterFindAndModifyTest, SnapshotReadConcernWithAfterClusterTime) { - testTxnSnapshotReadConcernWithAfterClusterTime(kFindAndModifyCmdTargeted); + testSnapshotReadConcernWithAfterClusterTime(kFindAndModifyCmdTargeted); } } // namespace diff --git a/src/mongo/s/commands/cluster_find_test.cpp b/src/mongo/s/commands/cluster_find_test.cpp index 7d9e219961d..8d0dc6792d4 100644 --- a/src/mongo/s/commands/cluster_find_test.cpp +++ b/src/mongo/s/commands/cluster_find_test.cpp @@ -31,23 +31,34 @@ #include "mongo/db/query/cursor_response.h" #include "mongo/s/commands/cluster_command_test_fixture.h" -#include "mongo/s/query/cluster_cursor_manager.h" namespace mongo { namespace { class ClusterFindTest : public ClusterCommandTestFixture { protected: - // Batch size 1, so when expectInspectRequest returns one doc, mongos doesn't wait for more. - const BSONObj kFindCmdScatterGather = BSON("find" << kNss.coll() << "batchSize" << 1); - const BSONObj kFindCmdTargeted = - BSON("find" << kNss.coll() << "filter" << BSON("_id" << 0) << "batchSize" << 1); + const BSONObj kFindCmdScatterGather = BSON("find" + << "coll"); + const BSONObj kFindCmdTargeted = BSON("find" + << "coll" + << "filter" << BSON("_id" << 0)); // The index of the shard expected to receive the response is used to prevent different shards // from returning documents with the same shard key. This is expected to be 0 for queries // targeting one shard. void expectReturnsSuccess(int shardIndex) override { - expectInspectRequest(shardIndex, [](const executor::RemoteCommandRequest&) {}); + onCommandForPoolExecutor([&](const executor::RemoteCommandRequest& request) { + ASSERT_EQ(kNss.coll(), request.cmdObj.firstElement().valueStringData()); + + std::vector<BSONObj> batch = {BSON("_id" << shardIndex)}; + CursorResponse cursorResponse(kNss, CursorId(0), batch); + + BSONObjBuilder bob; + bob.appendElementsUnique( + cursorResponse.toBSON(CursorResponse::ResponseType::InitialResponse)); + appendTxnResponseMetadata(bob); + return bob.obj(); + }); } void expectInspectRequest(int shardIndex, InspectionCallback cb) override { @@ -57,17 +68,8 @@ protected: cb(request); std::vector<BSONObj> batch = {BSON("_id" << shardIndex)}; - // User supplies no atClusterTime. For single-shard non-transaction snapshot reads, - // mongos lets the shard (which this function simulates) select a read timestamp. - boost::optional<Timestamp> atClusterTime; - if (request.cmdObj["txnNumber"].eoo() && !request.cmdObj["readConcern"].eoo()) { - auto rc = request.cmdObj["readConcern"].Obj(); - if (rc["level"].String() == "snapshot" && rc["atClusterTime"].eoo()) { - atClusterTime = kShardClusterTime; - } - } - - CursorResponse cursorResponse(kNss, kCursorId, batch, atClusterTime); + CursorResponse cursorResponse(kNss, CursorId(0), batch); + BSONObjBuilder bob; bob.appendElementsUnique( cursorResponse.toBSON(CursorResponse::ResponseType::InitialResponse)); @@ -89,23 +91,12 @@ TEST_F(ClusterFindTest, MaxRetriesSnapshotErrors) { testMaxRetriesSnapshotErrors(kFindCmdTargeted, kFindCmdScatterGather); } -TEST_F(ClusterFindTest, AttachesAtClusterTimeForTransactionSnapshotReadConcern) { - testAttachesAtClusterTimeForTxnSnapshotReadConcern( - kFindCmdTargeted, kFindCmdScatterGather, true); -} - -TEST_F(ClusterFindTest, TransactionSnapshotReadConcernWithAfterClusterTime) { - testTxnSnapshotReadConcernWithAfterClusterTime(kFindCmdTargeted, kFindCmdScatterGather, true); -} - -TEST_F(ClusterFindTest, AttachesAtClusterTimeForNonTransactionSnapshotReadConcern) { - testAttachesAtClusterTimeForNonTxnSnapshotReadConcern( - kFindCmdTargeted, kFindCmdScatterGather, true); +TEST_F(ClusterFindTest, AttachesAtClusterTimeForSnapshotReadConcern) { + testAttachesAtClusterTimeForSnapshotReadConcern(kFindCmdTargeted, kFindCmdScatterGather); } -TEST_F(ClusterFindTest, NonTransactionSnapshotReadConcernWithAfterClusterTime) { - testNonTxnSnapshotReadConcernWithAfterClusterTime( - kFindCmdTargeted, kFindCmdScatterGather, true); +TEST_F(ClusterFindTest, SnapshotReadConcernWithAfterClusterTime) { + testSnapshotReadConcernWithAfterClusterTime(kFindCmdTargeted, kFindCmdScatterGather); } } // namespace diff --git a/src/mongo/s/commands/cluster_insert_test.cpp b/src/mongo/s/commands/cluster_insert_test.cpp index 24544eeb8d4..ff5fb075486 100644 --- a/src/mongo/s/commands/cluster_insert_test.cpp +++ b/src/mongo/s/commands/cluster_insert_test.cpp @@ -73,11 +73,11 @@ TEST_F(ClusterInsertTest, NoErrors) { } TEST_F(ClusterInsertTest, AttachesAtClusterTimeForSnapshotReadConcern) { - testAttachesAtClusterTimeForTxnSnapshotReadConcern(kInsertCmdTargeted, kInsertCmdScatterGather); + testAttachesAtClusterTimeForSnapshotReadConcern(kInsertCmdTargeted, kInsertCmdScatterGather); } TEST_F(ClusterInsertTest, SnapshotReadConcernWithAfterClusterTime) { - testTxnSnapshotReadConcernWithAfterClusterTime(kInsertCmdTargeted, kInsertCmdScatterGather); + testSnapshotReadConcernWithAfterClusterTime(kInsertCmdTargeted, kInsertCmdScatterGather); } } // namespace diff --git a/src/mongo/s/commands/cluster_update_test.cpp b/src/mongo/s/commands/cluster_update_test.cpp index 9ee788c2a1e..53aee707522 100644 --- a/src/mongo/s/commands/cluster_update_test.cpp +++ b/src/mongo/s/commands/cluster_update_test.cpp @@ -77,11 +77,11 @@ TEST_F(ClusterUpdateTest, NoErrors) { } TEST_F(ClusterUpdateTest, AttachesAtClusterTimeForSnapshotReadConcern) { - testAttachesAtClusterTimeForTxnSnapshotReadConcern(kUpdateCmdTargeted, kUpdateCmdScatterGather); + testAttachesAtClusterTimeForSnapshotReadConcern(kUpdateCmdTargeted, kUpdateCmdScatterGather); } TEST_F(ClusterUpdateTest, SnapshotReadConcernWithAfterClusterTime) { - testTxnSnapshotReadConcernWithAfterClusterTime(kUpdateCmdTargeted, kUpdateCmdScatterGather); + testSnapshotReadConcernWithAfterClusterTime(kUpdateCmdTargeted, kUpdateCmdScatterGather); } } // namespace diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp index 12325e975a9..26658c8b514 100644 --- a/src/mongo/s/commands/strategy.cpp +++ b/src/mongo/s/commands/strategy.cpp @@ -631,7 +631,7 @@ void runCommand(OperationContext* opCtx, } return latestKnownClusterTime.asTimestamp(); }(); - readConcernArgs.setArgsAtClusterTime(atClusterTime); + readConcernArgs.setArgsAtClusterTimeForSnapshot(atClusterTime); } replyBuilder->reset(); @@ -821,8 +821,7 @@ void runCommand(OperationContext* opCtx, abortGuard.dismiss(); continue; - } else if (auto rc = ReadConcernArgs::get(opCtx); - rc.getArgsAtClusterTime() && !rc.wasAtClusterTimeSelected()) { + } else if (!ReadConcernArgs::get(opCtx).wasAtClusterTimeSelected()) { // Non-transaction snapshot read. The client sent readConcern: {level: // "snapshot", atClusterTime: T}, where T is older than // minSnapshotHistoryWindowInSeconds, retrying won't succeed. diff --git a/src/mongo/s/query/cluster_aggregate_test.cpp b/src/mongo/s/query/cluster_aggregate_test.cpp index 3bb16f7fb0d..08bcc8081e9 100644 --- a/src/mongo/s/query/cluster_aggregate_test.cpp +++ b/src/mongo/s/query/cluster_aggregate_test.cpp @@ -121,13 +121,12 @@ TEST_F(ClusterAggregateTest, MaxRetriesSnapshotErrors) { } TEST_F(ClusterAggregateTest, AttachesAtClusterTimeForSnapshotReadConcern) { - testAttachesAtClusterTimeForTxnSnapshotReadConcern(kAggregateCmdTargeted, - kAggregateCmdScatterGather); + testAttachesAtClusterTimeForSnapshotReadConcern(kAggregateCmdTargeted, + kAggregateCmdScatterGather); } TEST_F(ClusterAggregateTest, SnapshotReadConcernWithAfterClusterTime) { - testTxnSnapshotReadConcernWithAfterClusterTime(kAggregateCmdTargeted, - kAggregateCmdScatterGather); + testSnapshotReadConcernWithAfterClusterTime(kAggregateCmdTargeted, kAggregateCmdScatterGather); } TEST_F(ClusterAggregateTest, ShouldFailWhenFromMongosIsTrue) { diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp index a352223d298..cb6c4f394ef 100644 --- a/src/mongo/s/query/cluster_find.cpp +++ b/src/mongo/s/query/cluster_find.cpp @@ -188,9 +188,8 @@ std::vector<std::pair<ShardId, BSONObj>> constructRequestsForShards( } auto& readConcernArgs = repl::ReadConcernArgs::get(opCtx); - // mongos selects atClusterTime for multi-shard snapshot reads. For a single-shard read, let the - // shard select it. - if (readConcernArgs.wasAtClusterTimeSelected() && shardIds.size() > 1) { + if (readConcernArgs.wasAtClusterTimeSelected()) { + // If mongos selected atClusterTime or received it from client, transmit it to shard. qrToForward->setReadConcern(readConcernArgs.toBSONInner()); } @@ -247,11 +246,9 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, query.getQueryRequest().getFilter(), query.getQueryRequest().getCollation()); - auto& readConcern = ReadConcernArgs::get(opCtx); - // Construct the query and parameters. Defer setting skip and limit here until // we determine if the query is targeting multi-shards or a single shard below. - ClusterClientCursorParams params(query.nss(), readPref, readConcern); + ClusterClientCursorParams params(query.nss(), readPref, ReadConcernArgs::get(opCtx)); params.originatingCommandObj = CurOp::get(opCtx)->opDescription().getOwned(); params.batchSize = query.getQueryRequest().getEffectiveBatchSize(); params.tailableMode = query.getQueryRequest().getTailableMode(); @@ -265,12 +262,6 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, params.isAutoCommit = false; } - // For single-shard non-transaction snapshot reads, we pass readConcern level "snapshot" to - // the shard. It selects "atClusterTime" and replies with it. Store it on the mongos cursor. - if (shardIds.size() == 1 && readConcern.wasAtClusterTimeSelected()) { - params.readConcern->clearArgsAtClusterTime(); - } - // This is the batchSize passed to each subsequent getMore command issued by the cursor. We // usually use the batchSize associated with the initial find, but as it is illegal to send a // getMore with a batchSize of 0, we set it to use the default batchSize logic. @@ -332,22 +323,13 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, : ClusterCursorManager::CursorType::SingleTarget; // Only set skip, limit and sort to be applied to on the router for the multi-shard case. For - // the single-shard case skip/limit as well as sorts are applied on mongod. + // the single-shard case skip/limit as well as sorts are appled on mongod. if (cursorType == ClusterCursorManager::CursorType::MultiTarget) { const auto qr = query.getQueryRequest(); params.skipToApplyOnRouter = qr.getSkip(); params.limit = qr.getLimit(); params.sortToApplyOnRouter = sortComparatorObj; params.compareWholeSortKeyOnRouter = compareWholeSortKeyOnRouter; - } else if (!params.remotes.empty()) { - // For single-shard non-transaction snapshot reads, we pass readConcern level "snapshot" to - // the shard. It selects "atClusterTime" and replies with it. Store it on the mongos cursor - // and opCtx readConcern, whence it is returned to the caller in our reply's atClusterTime. - auto clusterTime = params.remotes[0].getCursorResponse().getAtClusterTime(); - if (clusterTime && !params.readConcern->getArgsAtClusterTime()) { - params.readConcern->setArgsAtClusterTime(*clusterTime); - readConcern.setArgsAtClusterTime(*clusterTime); - } } // Transfer the established cursors to a ClusterClientCursor. |