summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorA. Jesse Jiryu Davis <jesse@mongodb.com>2020-06-11 15:52:54 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-06-11 20:17:46 +0000
commite485c1a8011d85682cb8dafa87ab92b9c23daa66 (patch)
tree6f81bf10da29be6451f073af361b5f8e94252bc5 /src
parent5c7cdc392c2ea058d7ec93609203fcc5bb74bb99 (diff)
downloadmongo-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.cpp2
-rw-r--r--src/mongo/db/repl/read_concern_args.cpp36
-rw-r--r--src/mongo/db/repl/read_concern_args.h28
-rw-r--r--src/mongo/s/commands/cluster_command_test_fixture.cpp191
-rw-r--r--src/mongo/s/commands/cluster_command_test_fixture.h71
-rw-r--r--src/mongo/s/commands/cluster_delete_test.cpp4
-rw-r--r--src/mongo/s/commands/cluster_distinct_test.cpp6
-rw-r--r--src/mongo/s/commands/cluster_find_and_modify_test.cpp4
-rw-r--r--src/mongo/s/commands/cluster_find_test.cpp55
-rw-r--r--src/mongo/s/commands/cluster_insert_test.cpp4
-rw-r--r--src/mongo/s/commands/cluster_update_test.cpp4
-rw-r--r--src/mongo/s/commands/strategy.cpp5
-rw-r--r--src/mongo/s/query/cluster_aggregate_test.cpp7
-rw-r--r--src/mongo/s/query/cluster_find.cpp26
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.