summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2022-04-11 12:21:14 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-04-11 15:18:20 +0000
commit481cdc722a1516d094743f58d2fbf61575668e3c (patch)
treeff8960633132ba7b30ffdeed63440a3ca5cb6480 /src/mongo
parent327a61632913d0f943ab0062611714b6552dbc0b (diff)
downloadmongo-481cdc722a1516d094743f58d2fbf61575668e3c.tar.gz
SERVER-65204 Add Timestamp (in addition to Epoch) on the complete split path
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/s/SConscript6
-rw-r--r--src/mongo/db/s/balancer/balancer.cpp6
-rw-r--r--src/mongo/db/s/balancer/balancer_commands_scheduler_impl.cpp1
-rw-r--r--src/mongo/db/s/balancer/balancer_commands_scheduler_impl.h2
-rw-r--r--src/mongo/db/s/chunk_splitter.cpp19
-rw-r--r--src/mongo/db/s/config/configsvr_split_chunk_command.cpp3
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager.h1
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_chunk_operations.cpp5
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_split_chunk_test.cpp18
-rw-r--r--src/mongo/db/s/shardsvr_split_chunk_command.cpp8
-rw-r--r--src/mongo/db/s/split_chunk.cpp34
-rw-r--r--src/mongo/db/s/split_chunk.h27
-rw-r--r--src/mongo/db/s/split_chunk_request_test.cpp (renamed from src/mongo/s/request_types/split_chunk_request_test.cpp)6
-rw-r--r--src/mongo/db/s/split_chunk_request_type.cpp (renamed from src/mongo/s/request_types/split_chunk_request_type.cpp)39
-rw-r--r--src/mongo/db/s/split_chunk_request_type.h (renamed from src/mongo/s/request_types/split_chunk_request_type.h)5
-rw-r--r--src/mongo/db/s/split_chunk_test.cpp698
-rw-r--r--src/mongo/s/SConscript3
-rw-r--r--src/mongo/s/chunk_version.cpp4
-rw-r--r--src/mongo/s/chunk_version_test.cpp39
-rw-r--r--src/mongo/s/commands/cluster_move_chunk_cmd.cpp1
-rw-r--r--src/mongo/s/commands/cluster_split_cmd.cpp1
-rw-r--r--src/mongo/s/config_server_client.cpp64
-rw-r--r--src/mongo/s/config_server_client.h54
-rw-r--r--src/mongo/s/request_types/balance_chunk_request_type.cpp31
-rw-r--r--src/mongo/s/request_types/balance_chunk_request_type.h12
-rw-r--r--src/mongo/s/shard_util.cpp2
-rw-r--r--src/mongo/s/shard_util.h1
-rw-r--r--src/mongo/s/stale_exception.cpp37
-rw-r--r--src/mongo/s/stale_exception.h15
-rw-r--r--src/mongo/s/stale_exception_test.cpp29
30 files changed, 177 insertions, 994 deletions
diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript
index bf63a589862..892a2fee04c 100644
--- a/src/mongo/db/s/SConscript
+++ b/src/mongo/db/s/SConscript
@@ -268,6 +268,7 @@ env.Library(
'sharding_config_server_parameters.idl',
'sharding_ddl_util.cpp',
'sharding_util.cpp',
+ 'split_chunk_request_type.cpp',
'type_lockpings.cpp',
'type_locks.cpp',
'type_shard_identity.cpp',
@@ -550,6 +551,7 @@ env.CppUnitTest(
'migration_util_test.cpp',
'namespace_metadata_change_notifications_test.cpp',
'op_observer_sharding_test.cpp',
+ 'operation_sharding_state_test.cpp',
'persistent_task_queue_test.cpp',
'range_deletion_util_test.cpp',
'resharding/resharding_agg_test.cpp',
@@ -573,8 +575,8 @@ env.CppUnitTest(
'resharding/resharding_txn_cloner_test.cpp',
'session_catalog_migration_destination_test.cpp',
'session_catalog_migration_source_test.cpp',
- 'shard_local_test.cpp',
'shard_key_index_util_test.cpp',
+ 'shard_local_test.cpp',
'shard_metadata_util_test.cpp',
'shard_server_catalog_cache_loader_test.cpp',
'sharding_data_transform_cumulative_metrics_test.cpp',
@@ -582,6 +584,7 @@ env.CppUnitTest(
'sharding_initialization_mongod_test.cpp',
'sharding_initialization_op_observer_test.cpp',
'sharding_logging_test.cpp',
+ 'split_chunk_request_test.cpp',
'split_vector_test.cpp',
'start_chunk_clone_request_test.cpp',
'transaction_coordinator_catalog_test.cpp',
@@ -592,7 +595,6 @@ env.CppUnitTest(
'transaction_coordinator_test.cpp',
'type_shard_collection_test.cpp',
'type_shard_identity_test.cpp',
- 'operation_sharding_state_test.cpp',
'vector_clock_shard_server_test.cpp',
],
LIBDEPS=[
diff --git a/src/mongo/db/s/balancer/balancer.cpp b/src/mongo/db/s/balancer/balancer.cpp
index 423faed4c89..7b06396d010 100644
--- a/src/mongo/db/s/balancer/balancer.cpp
+++ b/src/mongo/db/s/balancer/balancer.cpp
@@ -29,8 +29,6 @@
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kSharding
-#include "mongo/platform/basic.h"
-
#include "mongo/db/s/balancer/balancer.h"
#include <algorithm>
@@ -201,7 +199,6 @@ Status processManualMigrationOutcome(OperationContext* opCtx,
return outcome;
}
-
uint64_t getMaxChunkSizeBytes(OperationContext* opCtx, const CollectionType& coll) {
const auto balancerConfig = Grid::get(opCtx)->getBalancerConfiguration();
uassertStatusOK(balancerConfig->refreshAndCheck(opCtx));
@@ -210,7 +207,7 @@ uint64_t getMaxChunkSizeBytes(OperationContext* opCtx, const CollectionType& col
const int64_t getMaxChunkSizeMB(OperationContext* opCtx, const CollectionType& coll) {
return getMaxChunkSizeBytes(opCtx, coll) / (1024 * 1024);
-};
+}
const auto _balancerDecoration = ServiceContext::declareDecoration<Balancer>();
@@ -885,6 +882,7 @@ Status Balancer::_splitChunksIfNeeded(OperationContext* opCtx) {
splitInfo.nss,
cm.getShardKeyPattern(),
splitInfo.collectionVersion.epoch(),
+ splitInfo.collectionVersion.getTimestamp(),
ChunkVersion::IGNORED() /*shardVersion*/,
ChunkRange(splitInfo.minKey, splitInfo.maxKey),
splitInfo.splitKeys);
diff --git a/src/mongo/db/s/balancer/balancer_commands_scheduler_impl.cpp b/src/mongo/db/s/balancer/balancer_commands_scheduler_impl.cpp
index c05eb954132..797d4c00bbc 100644
--- a/src/mongo/db/s/balancer/balancer_commands_scheduler_impl.cpp
+++ b/src/mongo/db/s/balancer/balancer_commands_scheduler_impl.cpp
@@ -160,6 +160,7 @@ const std::string SplitChunkCommandInfo::kKeyPattern = "keyPattern";
const std::string SplitChunkCommandInfo::kLowerBound = "min";
const std::string SplitChunkCommandInfo::kUpperBound = "max";
const std::string SplitChunkCommandInfo::kEpoch = "epoch";
+const std::string SplitChunkCommandInfo::kTimestamp = "timestamp";
const std::string SplitChunkCommandInfo::kSplitKeys = "splitKeys";
BalancerCommandsSchedulerImpl::BalancerCommandsSchedulerImpl() {}
diff --git a/src/mongo/db/s/balancer/balancer_commands_scheduler_impl.h b/src/mongo/db/s/balancer/balancer_commands_scheduler_impl.h
index 2139ce3f9d5..ba85ee9a6e3 100644
--- a/src/mongo/db/s/balancer/balancer_commands_scheduler_impl.h
+++ b/src/mongo/db/s/balancer/balancer_commands_scheduler_impl.h
@@ -393,6 +393,7 @@ public:
.append(kShardName, getTarget().toString())
.append(kKeyPattern, _shardKeyPattern)
.append(kEpoch, _version.epoch())
+ .append(kTimestamp, _version.getTimestamp())
.append(kLowerBound, _lowerBoundKey)
.append(kUpperBound, _upperBoundKey)
.append(kSplitKeys, _splitPoints);
@@ -412,6 +413,7 @@ private:
static const std::string kLowerBound;
static const std::string kUpperBound;
static const std::string kEpoch;
+ static const std::string kTimestamp;
static const std::string kSplitKeys;
};
diff --git a/src/mongo/db/s/chunk_splitter.cpp b/src/mongo/db/s/chunk_splitter.cpp
index 751e15141c1..d27798fdd44 100644
--- a/src/mongo/db/s/chunk_splitter.cpp
+++ b/src/mongo/db/s/chunk_splitter.cpp
@@ -29,8 +29,6 @@
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kSharding
-#include "mongo/platform/basic.h"
-
#include "mongo/db/s/chunk_splitter.h"
#include "mongo/client/dbclient_cursor.h"
@@ -49,8 +47,8 @@
#include "mongo/s/catalog/type_chunk.h"
#include "mongo/s/catalog_cache.h"
#include "mongo/s/chunk_manager.h"
-#include "mongo/s/config_server_client.h"
#include "mongo/s/grid.h"
+#include "mongo/s/request_types/balance_chunk_request_type.h"
#include "mongo/s/shard_key_pattern.h"
#include "mongo/s/shard_util.h"
#include "mongo/util/assert_util.h"
@@ -104,11 +102,24 @@ Status splitChunkAtMultiplePoints(OperationContext* opCtx,
std::move(splitPoints),
shardId.toString(),
collectionVersion.epoch(),
+ collectionVersion.getTimestamp(),
true /* fromChunkSplitter */)
.getStatus()
.withContext("split failed");
}
+void rebalanceChunk(OperationContext* opCtx, const NamespaceString& nss, const ChunkType& chunk) {
+ auto shardRegistry = Grid::get(opCtx)->shardRegistry();
+ auto shard = shardRegistry->getConfigShard();
+ auto response = uassertStatusOK(shard->runCommandWithFixedRetryAttempts(
+ opCtx,
+ ReadPreferenceSetting{ReadPreference::PrimaryOnly},
+ "admin",
+ BalanceChunkRequest::serializeToRebalanceCommandForConfig(nss, chunk),
+ Shard::RetryPolicy::kNotIdempotent));
+ uassertStatusOK(response.commandStatus);
+}
+
/**
* Attempts to move the chunk specified by minKey away from its current shard.
*/
@@ -130,7 +141,7 @@ void moveChunk(OperationContext* opCtx, const NamespaceString& nss, const BSONOb
chunkToMove.setMax(suggestedChunk.getMax());
chunkToMove.setVersion(suggestedChunk.getLastmod());
- uassertStatusOK(configsvr_client::rebalanceChunk(opCtx, nss, chunkToMove));
+ rebalanceChunk(opCtx, nss, chunkToMove);
}
/**
diff --git a/src/mongo/db/s/config/configsvr_split_chunk_command.cpp b/src/mongo/db/s/config/configsvr_split_chunk_command.cpp
index 336198ab5b0..831f9ca6eb5 100644
--- a/src/mongo/db/s/config/configsvr_split_chunk_command.cpp
+++ b/src/mongo/db/s/config/configsvr_split_chunk_command.cpp
@@ -39,8 +39,8 @@
#include "mongo/db/operation_context.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/db/s/config/sharding_catalog_manager.h"
+#include "mongo/db/s/split_chunk_request_type.h"
#include "mongo/s/grid.h"
-#include "mongo/s/request_types/split_chunk_request_type.h"
#include "mongo/util/str.h"
namespace mongo {
@@ -122,6 +122,7 @@ public:
opCtx,
parsedRequest.getNamespace(),
parsedRequest.getEpoch(),
+ parsedRequest.getTimestamp(),
parsedRequest.getChunkRange(),
parsedRequest.getSplitPoints(),
parsedRequest.getShardName(),
diff --git a/src/mongo/db/s/config/sharding_catalog_manager.h b/src/mongo/db/s/config/sharding_catalog_manager.h
index 08a1c9143dc..0cb11bfc7dd 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager.h
+++ b/src/mongo/db/s/config/sharding_catalog_manager.h
@@ -249,6 +249,7 @@ public:
StatusWith<BSONObj> commitChunkSplit(OperationContext* opCtx,
const NamespaceString& nss,
const OID& requestEpoch,
+ const boost::optional<Timestamp>& requestTimestamp,
const ChunkRange& range,
const std::vector<BSONObj>& splitPoints,
const std::string& shardName,
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_chunk_operations.cpp b/src/mongo/db/s/config/sharding_catalog_manager_chunk_operations.cpp
index d2b7fe9f9f5..2843dae8e4d 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_chunk_operations.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_chunk_operations.cpp
@@ -565,6 +565,7 @@ StatusWith<BSONObj> ShardingCatalogManager::commitChunkSplit(
OperationContext* opCtx,
const NamespaceString& nss,
const OID& requestEpoch,
+ const boost::optional<Timestamp>& requestTimestamp,
const ChunkRange& range,
const std::vector<BSONObj>& splitPoints,
const std::string& shardName,
@@ -605,7 +606,8 @@ StatusWith<BSONObj> ShardingCatalogManager::commitChunkSplit(
auto collVersion = swCollVersion.getValue();
// Return an error if collection epoch does not match epoch of request.
- if (coll.getEpoch() != requestEpoch) {
+ if (coll.getEpoch() != requestEpoch ||
+ (requestTimestamp && coll.getTimestamp() != requestTimestamp)) {
return {ErrorCodes::StaleEpoch,
str::stream() << "splitChunk cannot split chunk " << range.toString()
<< ". Epoch of collection '" << nss.ns() << "' has changed."
@@ -1794,6 +1796,7 @@ void ShardingCatalogManager::splitOrMarkJumbo(OperationContext* opCtx,
nss,
cm.getShardKeyPattern(),
cm.getVersion().epoch(),
+ cm.getVersion().getTimestamp(),
ChunkVersion::IGNORED() /*shardVersion*/,
ChunkRange(chunk.getMin(), chunk.getMax()),
splitPoints));
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_split_chunk_test.cpp b/src/mongo/db/s/config/sharding_catalog_manager_split_chunk_test.cpp
index d6aadf88c49..cd7f46ebfda 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_split_chunk_test.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_split_chunk_test.cpp
@@ -27,8 +27,6 @@
* it in the license file.
*/
-#include "mongo/platform/basic.h"
-
#include "mongo/client/read_preference.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/namespace_string.h"
@@ -86,6 +84,7 @@ TEST_F(SplitChunkTest, SplitExistingChunkCorrectlyShouldSucceed) {
->commitChunkSplit(operationContext(),
nss,
collEpoch,
+ collTimestamp,
ChunkRange(chunkMin, chunkMax),
splitPoints,
"shard0000",
@@ -170,6 +169,7 @@ TEST_F(SplitChunkTest, MultipleSplitsOnExistingChunkShouldSucceed) {
->commitChunkSplit(operationContext(),
nss,
collEpoch,
+ collTimestamp,
ChunkRange(chunkMin, chunkMax),
splitPoints,
"shard0000",
@@ -266,6 +266,7 @@ TEST_F(SplitChunkTest, NewSplitShouldClaimHighestVersion) {
->commitChunkSplit(operationContext(),
nss,
collEpoch,
+ collTimestamp,
ChunkRange(chunkMin, chunkMax),
splitPoints,
"shard0000",
@@ -326,6 +327,7 @@ TEST_F(SplitChunkTest, PreConditionFailErrors) {
->commitChunkSplit(operationContext(),
nss,
collEpoch,
+ collTimestamp,
ChunkRange(chunkMin, BSON("a" << 7)),
splitPoints,
"shard0000",
@@ -360,6 +362,7 @@ TEST_F(SplitChunkTest, NonExisingNamespaceErrors) {
->commitChunkSplit(operationContext(),
NamespaceString("TestDB.NonExistingColl"),
collEpoch,
+ Timestamp{50, 0},
ChunkRange(chunkMin, chunkMax),
splitPoints,
"shard0000",
@@ -395,6 +398,7 @@ TEST_F(SplitChunkTest, NonMatchingEpochsOfChunkAndRequestErrors) {
->commitChunkSplit(operationContext(),
nss,
OID::gen(),
+ Timestamp{50, 0},
ChunkRange(chunkMin, chunkMax),
splitPoints,
"shard0000",
@@ -430,6 +434,7 @@ TEST_F(SplitChunkTest, SplitPointsOutOfOrderShouldFail) {
->commitChunkSplit(operationContext(),
nss,
collEpoch,
+ collTimestamp,
ChunkRange(chunkMin, chunkMax),
splitPoints,
"shard0000",
@@ -464,6 +469,7 @@ TEST_F(SplitChunkTest, SplitPointsOutOfRangeAtMinShouldFail) {
->commitChunkSplit(operationContext(),
nss,
collEpoch,
+ collTimestamp,
ChunkRange(chunkMin, chunkMax),
splitPoints,
"shard0000",
@@ -499,6 +505,7 @@ TEST_F(SplitChunkTest, SplitPointsOutOfRangeAtMaxShouldFail) {
->commitChunkSplit(operationContext(),
nss,
collEpoch,
+ collTimestamp,
ChunkRange(chunkMin, chunkMax),
splitPoints,
"shard0000",
@@ -530,6 +537,7 @@ TEST_F(SplitChunkTest, SplitPointsWithDollarPrefixShouldFail) {
->commitChunkSplit(operationContext(),
nss,
collEpoch,
+ collTimestamp,
ChunkRange(chunkMin, chunkMax),
{BSON("a" << BSON("$minKey" << 1))},
"shard0000",
@@ -538,6 +546,7 @@ TEST_F(SplitChunkTest, SplitPointsWithDollarPrefixShouldFail) {
->commitChunkSplit(operationContext(),
nss,
collEpoch,
+ collTimestamp,
ChunkRange(chunkMin, chunkMax),
{BSON("a" << BSON("$maxKey" << 1))},
"shard0000",
@@ -550,13 +559,14 @@ TEST_F(SplitChunkTest, SplitPointsWithDollarPrefixShouldFail) {
TEST_F(SplitChunkTest, CantCommitSplitFromChunkSplitterDuringDefragmentation) {
const auto& nss = _nss2;
const auto collEpoch = OID::gen();
+ const Timestamp collTimestamp{1, 0};
const auto collUuid = UUID::gen();
ChunkType chunk;
chunk.setName(OID::gen());
chunk.setCollectionUUID(collUuid);
- auto version = ChunkVersion(1, 0, collEpoch, Timestamp(42));
+ auto version = ChunkVersion(1, 0, collEpoch, collTimestamp);
chunk.setVersion(version);
chunk.setShard(ShardId(_shardName));
@@ -587,6 +597,7 @@ TEST_F(SplitChunkTest, CantCommitSplitFromChunkSplitterDuringDefragmentation) {
->commitChunkSplit(operationContext(),
nss,
collEpoch,
+ collTimestamp,
ChunkRange(chunkMin, chunkMax),
splitPoints,
"shard0000",
@@ -599,6 +610,7 @@ TEST_F(SplitChunkTest, CantCommitSplitFromChunkSplitterDuringDefragmentation) {
->commitChunkSplit(operationContext(),
nss,
collEpoch,
+ collTimestamp,
ChunkRange(chunkMin, chunkMax),
splitPoints,
"shard0000",
diff --git a/src/mongo/db/s/shardsvr_split_chunk_command.cpp b/src/mongo/db/s/shardsvr_split_chunk_command.cpp
index 5476c28e787..dea40abcb4e 100644
--- a/src/mongo/db/s/shardsvr_split_chunk_command.cpp
+++ b/src/mongo/db/s/shardsvr_split_chunk_command.cpp
@@ -165,6 +165,13 @@ public:
OID expectedCollectionEpoch;
uassertStatusOK(bsonExtractOIDField(cmdObj, "epoch", &expectedCollectionEpoch));
+ boost::optional<Timestamp> expectedCollectionTimestamp;
+ if (cmdObj["timestamp"]) {
+ expectedCollectionTimestamp.emplace();
+ uassertStatusOK(bsonExtractTimestampField(
+ cmdObj, "timestamp", expectedCollectionTimestamp.get_ptr()));
+ }
+
bool fromChunkSplitter = [&]() {
bool field = false;
Status status = bsonExtractBooleanField(cmdObj, "fromChunkSplitter", &field);
@@ -178,6 +185,7 @@ public:
std::move(splitKeys),
shardName,
expectedCollectionEpoch,
+ expectedCollectionTimestamp,
fromChunkSplitter));
// Otherwise, we want to check whether or not top-chunk optimization should be performed. If
diff --git a/src/mongo/db/s/split_chunk.cpp b/src/mongo/db/s/split_chunk.cpp
index a97efd9be55..6ac4cf2620a 100644
--- a/src/mongo/db/s/split_chunk.cpp
+++ b/src/mongo/db/s/split_chunk.cpp
@@ -47,11 +47,11 @@
#include "mongo/db/s/shard_filtering_metadata_refresh.h"
#include "mongo/db/s/shard_key_index_util.h"
#include "mongo/db/s/sharding_state.h"
+#include "mongo/db/s/split_chunk_request_type.h"
#include "mongo/logv2/log.h"
#include "mongo/s/catalog/type_chunk.h"
#include "mongo/s/client/shard_registry.h"
#include "mongo/s/grid.h"
-#include "mongo/s/request_types/split_chunk_request_type.h"
namespace mongo {
namespace {
@@ -96,6 +96,7 @@ bool checkIfSingleDoc(OperationContext* opCtx,
bool checkMetadataForSuccessfulSplitChunk(OperationContext* opCtx,
const NamespaceString& nss,
const OID& epoch,
+ const boost::optional<Timestamp>& expectedTimestamp,
const ChunkRange& chunkRange,
const std::vector<BSONObj>& splitPoints) {
AutoGetCollection autoColl(opCtx, nss, MODE_IS);
@@ -104,7 +105,9 @@ bool checkMetadataForSuccessfulSplitChunk(OperationContext* opCtx,
uassert(ErrorCodes::StaleEpoch,
str::stream() << "Collection " << nss.ns() << " changed since split start",
- metadataAfterSplit && metadataAfterSplit->getShardVersion().epoch() == epoch);
+ metadataAfterSplit && metadataAfterSplit->getShardVersion().epoch() == epoch &&
+ (!expectedTimestamp ||
+ metadataAfterSplit->getShardVersion().getTimestamp() == expectedTimestamp));
ChunkType nextChunk;
for (auto it = splitPoints.begin(); it != splitPoints.end(); ++it) {
@@ -128,14 +131,16 @@ bool checkMetadataForSuccessfulSplitChunk(OperationContext* opCtx,
} // namespace
-StatusWith<boost::optional<ChunkRange>> splitChunk(OperationContext* opCtx,
- const NamespaceString& nss,
- const BSONObj& keyPatternObj,
- const ChunkRange& chunkRange,
- std::vector<BSONObj>&& splitPoints,
- const std::string& shardName,
- const OID& expectedCollectionEpoch,
- const bool fromChunkSplitter) {
+StatusWith<boost::optional<ChunkRange>> splitChunk(
+ OperationContext* opCtx,
+ const NamespaceString& nss,
+ const BSONObj& keyPatternObj,
+ const ChunkRange& chunkRange,
+ std::vector<BSONObj>&& splitPoints,
+ const std::string& shardName,
+ const OID& expectedCollectionEpoch,
+ const boost::optional<Timestamp>& expectedCollectionTimestamp,
+ const bool fromChunkSplitter) {
auto scopedSplitOrMergeChunk(uassertStatusOK(
ActiveMigrationsRegistry::get(opCtx).registerSplitOrMergeChunk(opCtx, nss, chunkRange)));
@@ -159,6 +164,7 @@ StatusWith<boost::optional<ChunkRange>> splitChunk(OperationContext* opCtx,
auto request = SplitChunkRequest(nss,
shardName,
expectedCollectionEpoch,
+ expectedCollectionTimestamp,
chunkRange,
std::move(splitPoints),
fromChunkSplitter);
@@ -250,8 +256,12 @@ StatusWith<boost::optional<ChunkRange>> splitChunk(OperationContext* opCtx,
// getting the response from the first call to _configsvrCommitChunkSplit, but it actually
// succeeds, thus the automatic retry fails with a precondition violation, for example.
if (!commandStatus.isOK() || !writeConcernStatus.isOK()) {
- if (checkMetadataForSuccessfulSplitChunk(
- opCtx, nss, expectedCollectionEpoch, chunkRange, request.getSplitPoints())) {
+ if (checkMetadataForSuccessfulSplitChunk(opCtx,
+ nss,
+ expectedCollectionEpoch,
+ expectedCollectionTimestamp,
+ chunkRange,
+ request.getSplitPoints())) {
// Split was committed.
} else if (!commandStatus.isOK()) {
return commandStatus;
diff --git a/src/mongo/db/s/split_chunk.h b/src/mongo/db/s/split_chunk.h
index d8787d358eb..2f98f203523 100644
--- a/src/mongo/db/s/split_chunk.h
+++ b/src/mongo/db/s/split_chunk.h
@@ -33,16 +33,16 @@
#include <string>
#include <vector>
+#include "mongo/base/status_with.h"
+#include "mongo/bson/oid.h"
+#include "mongo/bson/timestamp.h"
+
namespace mongo {
class BSONObj;
class ChunkRange;
-class KeyPattern;
class NamespaceString;
-class OID;
class OperationContext;
-template <typename T>
-class StatusWith;
/**
* Attempts to split a chunk with the specified parameters. If the split fails, then the StatusWith
@@ -55,12 +55,15 @@ class StatusWith;
* range for the top chunk. Note that this ChunkRange is boost::optional, meaning that if top-chunk
* optimization is not performed, boost::none will be returned inside of the StatusWith instead.
*/
-StatusWith<boost::optional<ChunkRange>> splitChunk(OperationContext* opCtx,
- const NamespaceString& nss,
- const BSONObj& keyPatternObj,
- const ChunkRange& chunkRange,
- std::vector<BSONObj>&& splitPoints,
- const std::string& shardName,
- const OID& expectedCollectionEpoch,
- bool fromChunkSplitter = false);
+StatusWith<boost::optional<ChunkRange>> splitChunk(
+ OperationContext* opCtx,
+ const NamespaceString& nss,
+ const BSONObj& keyPatternObj,
+ const ChunkRange& chunkRange,
+ std::vector<BSONObj>&& splitPoints,
+ const std::string& shardName,
+ const OID& expectedCollectionEpoch,
+ const boost::optional<Timestamp>& expectedCollectionTimestamp,
+ bool fromChunkSplitter = false);
+
} // namespace mongo
diff --git a/src/mongo/s/request_types/split_chunk_request_test.cpp b/src/mongo/db/s/split_chunk_request_test.cpp
index d5262fd88b5..00179486ca6 100644
--- a/src/mongo/s/request_types/split_chunk_request_test.cpp
+++ b/src/mongo/db/s/split_chunk_request_test.cpp
@@ -27,15 +27,11 @@
* it in the license file.
*/
-#include "mongo/platform/basic.h"
-
#include "mongo/bson/bsonobjbuilder.h"
-#include "mongo/s/request_types/split_chunk_request_type.h"
-
+#include "mongo/db/s/split_chunk_request_type.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
-
namespace {
using unittest::assertGet;
diff --git a/src/mongo/s/request_types/split_chunk_request_type.cpp b/src/mongo/db/s/split_chunk_request_type.cpp
index 82c654f5685..951e4d91e7a 100644
--- a/src/mongo/s/request_types/split_chunk_request_type.cpp
+++ b/src/mongo/db/s/split_chunk_request_type.cpp
@@ -27,44 +27,41 @@
* it in the license file.
*/
-#include "mongo/platform/basic.h"
-
-#include "mongo/s/request_types/split_chunk_request_type.h"
+#include "mongo/db/s/split_chunk_request_type.h"
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/bson/util/bson_extract.h"
#include "mongo/db/write_concern_options.h"
namespace mongo {
-
-using std::string;
-using std::vector;
-
namespace {
const char kConfigsvrSplitChunk[] = "_configsvrCommitChunkSplit";
const char kCollEpoch[] = "collEpoch";
+const char kCollTimestamp[] = "collTimestamp";
const char kSplitPoints[] = "splitPoints";
const char kShardName[] = "shard";
const char kFromChunkSplitter[] = "fromChunkSplitter";
-} // unnamed namespace
+} // namespace
SplitChunkRequest::SplitChunkRequest(NamespaceString nss,
- string shardName,
+ std::string shardName,
OID epoch,
+ boost::optional<Timestamp> timestamp,
ChunkRange chunkRange,
- vector<BSONObj> splitPoints,
+ std::vector<BSONObj> splitPoints,
bool fromChunkSplitter)
: _nss(std::move(nss)),
_epoch(std::move(epoch)),
+ _timestamp(std::move(timestamp)),
_chunkRange(std::move(chunkRange)),
_splitPoints(std::move(splitPoints)),
_shardName(std::move(shardName)),
_fromChunkSplitter(fromChunkSplitter) {}
StatusWith<SplitChunkRequest> SplitChunkRequest::parseFromConfigCommand(const BSONObj& cmdObj) {
- string ns;
+ std::string ns;
auto parseNamespaceStatus = bsonExtractStringField(cmdObj, kConfigsvrSplitChunk, &ns);
if (!parseNamespaceStatus.isOK()) {
@@ -78,13 +75,24 @@ StatusWith<SplitChunkRequest> SplitChunkRequest::parseFromConfigCommand(const BS
return parseEpochStatus;
}
+ boost::optional<Timestamp> timestamp;
+ if (cmdObj[kCollTimestamp]) {
+ timestamp.emplace();
+ auto parseTimestampStatus =
+ bsonExtractTimestampField(cmdObj, kCollTimestamp, timestamp.get_ptr());
+
+ if (!parseTimestampStatus.isOK()) {
+ return parseTimestampStatus;
+ }
+ }
+
auto chunkRangeStatus = ChunkRange::fromBSON(cmdObj);
if (!chunkRangeStatus.isOK()) {
return chunkRangeStatus.getStatus();
}
- vector<BSONObj> splitPoints;
+ std::vector<BSONObj> splitPoints;
{
BSONElement splitPointsElem;
auto splitPointsElemStatus =
@@ -99,7 +107,7 @@ StatusWith<SplitChunkRequest> SplitChunkRequest::parseFromConfigCommand(const BS
}
}
- string shardName;
+ std::string shardName;
auto parseShardNameStatus = bsonExtractStringField(cmdObj, kShardName, &shardName);
if (!parseShardNameStatus.isOK()) {
@@ -115,6 +123,7 @@ StatusWith<SplitChunkRequest> SplitChunkRequest::parseFromConfigCommand(const BS
auto request = SplitChunkRequest(NamespaceString(ns),
std::move(shardName),
std::move(epoch),
+ std::move(timestamp),
std::move(chunkRangeStatus.getValue()),
std::move(splitPoints),
fromChunkSplitter);
@@ -164,11 +173,11 @@ const ChunkRange& SplitChunkRequest::getChunkRange() const {
return _chunkRange;
}
-const vector<BSONObj>& SplitChunkRequest::getSplitPoints() const {
+const std::vector<BSONObj>& SplitChunkRequest::getSplitPoints() const {
return _splitPoints;
}
-const string& SplitChunkRequest::getShardName() const {
+const std::string& SplitChunkRequest::getShardName() const {
return _shardName;
}
diff --git a/src/mongo/s/request_types/split_chunk_request_type.h b/src/mongo/db/s/split_chunk_request_type.h
index 4dfa9c87ca7..52cedce7b5c 100644
--- a/src/mongo/s/request_types/split_chunk_request_type.h
+++ b/src/mongo/db/s/split_chunk_request_type.h
@@ -48,6 +48,7 @@ public:
SplitChunkRequest(NamespaceString nss,
std::string shardName,
OID epoch,
+ boost::optional<Timestamp> timestamp,
ChunkRange chunkRange,
std::vector<BSONObj> splitPoints,
bool fromChunkSplitter);
@@ -83,6 +84,9 @@ public:
const NamespaceString& getNamespace() const;
const OID& getEpoch() const;
+ const auto& getTimestamp() const {
+ return _timestamp;
+ }
const ChunkRange& getChunkRange() const;
const std::vector<BSONObj>& getSplitPoints() const;
const std::string& getShardName() const;
@@ -97,6 +101,7 @@ private:
NamespaceString _nss;
OID _epoch;
+ boost::optional<Timestamp> _timestamp;
ChunkRange _chunkRange;
std::vector<BSONObj> _splitPoints;
std::string _shardName;
diff --git a/src/mongo/db/s/split_chunk_test.cpp b/src/mongo/db/s/split_chunk_test.cpp
deleted file mode 100644
index 98ef66f4021..00000000000
--- a/src/mongo/db/s/split_chunk_test.cpp
+++ /dev/null
@@ -1,698 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest
-
-#include "mongo/platform/basic.h"
-
-#include <boost/optional.hpp>
-
-#include "mongo/db/json.h"
-#include "mongo/db/s/shard_server_test_fixture.h"
-#include "mongo/db/s/sharding_initialization_mongod.h"
-#include "mongo/db/s/split_chunk.h"
-#include "mongo/db/server_options.h"
-#include "mongo/executor/remote_command_request.h"
-#include "mongo/executor/remote_command_response.h"
-#include "mongo/executor/task_executor.h"
-#include "mongo/logv2/log.h"
-#include "mongo/s/catalog/type_chunk.h"
-#include "mongo/s/catalog/type_collection.h"
-#include "mongo/s/catalog/type_database_gen.h"
-#include "mongo/s/catalog/type_shard.h"
-#include "mongo/s/catalog_cache_loader.h"
-#include "mongo/s/client/shard_registry.h"
-#include "mongo/s/grid.h"
-#include "mongo/s/write_ops/batched_command_request.h"
-#include "mongo/s/write_ops/batched_command_response.h"
-
-namespace mongo {
-namespace {
-
-using executor::RemoteCommandRequest;
-using executor::RemoteCommandResponse;
-
-class SplitChunkTest : public ShardServerTestFixture {
-public:
- void setUp() override {
- ShardServerTestFixture::setUp();
-
- ShardingState::get(operationContext())->setInitialized(_shardId, OID::gen());
- CatalogCacheLoader::get(getServiceContext()).initializeReplicaSetRole(true);
-
- // Instantiate names.
- _epoch = OID::gen();
-
- _shardId = ShardId("shardId");
- _nss = NamespaceString(StringData("dbName"), StringData("collName"));
-
- // Set up the databases collection
- _db.setName("dbName");
- _db.setPrimary(_shardId.toString());
- _db.setSharded(true);
- ASSERT_OK(_db.validate());
-
- // Set up the collections collection
- _coll.setNss(_nss);
- _coll.setEpoch(_epoch);
- _coll.setUpdatedAt(Date_t::fromMillisSinceEpoch(ChunkVersion(1, 3, _epoch).toLong()));
- _coll.setKeyPattern(BSON("_id" << 1));
- _coll.setUique(false);
- ASSERT_OK(_coll.validate());
-
- // Set up the shard
- _shard.setName(_shardId.toString());
- _shard.setHost("TestHost1");
- ASSERT_OK(_shard.validate());
-
- setUpChunkRanges();
- setUpChunkVersions();
- }
-
- /**
- * Returns the mock response that correspond with particular requests. For example, dbResponse
- * returns a response for when a find-databases request occurs.
- *
- * commitChunkSplitResponse : responds with { "ok" : 1 } or { "ok" : 0 }
- * dbResponse : responds with vector containing _db.toBSON()
- * collResponse : responds with vector containing _coll.toBSON()
- * shardResponse : responds with vector containing _shard.toBSON()
- * chunkResponse : responds with vector containing all every chunk.toConfigBSON()
- * emptyResponse : responds with empty vector
- */
- void commitChunkSplitResponse(bool isOk);
- void dbResponse();
- void collResponse();
- void shardResponse();
- void chunkResponse();
- void emptyResponse();
-
-protected:
- /**
- * Helper functions to return vectors of basic chunk ranges, chunk versions to
- * be used by some of the tests.
- */
- void setUpChunkRanges();
- void setUpChunkVersions();
-
- OID _epoch;
-
- NamespaceString _nss;
- ShardId _shardId;
-
- DatabaseType _db;
- CollectionType _coll;
- ShardType _shard;
-
- std::vector<ChunkRange> _chunkRanges;
- std::vector<ChunkVersion> _chunkVersions;
-};
-
-void SplitChunkTest::setUpChunkRanges() {
- BSONObjBuilder minKeyBuilder;
- BSONObjBuilder maxKeyBuilder;
- minKeyBuilder.appendMinKey("foo");
- maxKeyBuilder.appendMaxKey("foo");
-
- const BSONObj key1 = minKeyBuilder.obj();
- const BSONObj key2 = BSON("foo" << 0);
- const BSONObj key3 = BSON("foo" << 1024);
- const BSONObj key4 = maxKeyBuilder.obj();
-
- _chunkRanges.push_back(ChunkRange(key1, key2));
- _chunkRanges.push_back(ChunkRange(key2, key3));
- _chunkRanges.push_back(ChunkRange(key3, key4));
-}
-
-void SplitChunkTest::setUpChunkVersions() {
- _chunkVersions = {
- ChunkVersion(1, 1, _epoch), ChunkVersion(1, 2, _epoch), ChunkVersion(1, 3, _epoch)};
-}
-
-void SplitChunkTest::commitChunkSplitResponse(bool isOk) {
- onCommand([&](const RemoteCommandRequest& request) {
- return isOk ? BSON("ok" << 1) : BSON("ok" << 0);
- });
-}
-
-void SplitChunkTest::dbResponse() {
- onFindCommand(
- [&](const RemoteCommandRequest& request) { return std::vector<BSONObj>{_db.toBSON()}; });
-}
-
-void SplitChunkTest::collResponse() {
- onFindCommand(
- [&](const RemoteCommandRequest& request) { return std::vector<BSONObj>{_coll.toBSON()}; });
-}
-
-void SplitChunkTest::shardResponse() {
- onFindCommand(
- [&](const RemoteCommandRequest& request) { return std::vector<BSONObj>{_shard.toBSON()}; });
-}
-
-void SplitChunkTest::chunkResponse() {
- onFindCommand([&](const RemoteCommandRequest& request) {
- std::vector<BSONObj> response;
- for (unsigned long i = 0; i < _chunkRanges.size(); ++i) {
- ChunkType chunk(_nss, _chunkRanges[i], _chunkVersions[i], _shardId);
- response.push_back(chunk.toConfigBSON());
- }
- return response;
- });
-}
-
-void SplitChunkTest::emptyResponse() {
- onFindCommand([&](const RemoteCommandRequest& request) { return std::vector<BSONObj>(); });
-}
-
-TEST_F(SplitChunkTest, HashedKeyPatternNumberLongSplitKeys) {
- BSONObj keyPatternObj = BSON("foo"
- << "hashed");
- _coll.setKeyPattern(BSON("_id"
- << "hashed"));
-
- // Build a vector of valid split keys, which are values of NumberLong types.
- std::vector<BSONObj> validSplitKeys;
- for (long long i = 256; i <= 1024; i += 256) {
- validSplitKeys.push_back(BSON("foo" << i));
- }
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- validSplitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_OK(statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. The requests first
- // do a find on the databases, then a find on all collections in the database we are looking
- // for. Next, filter by the specific collection, and find the relevant chunks and shards.
- dbResponse();
- collResponse();
- collResponse();
- chunkResponse();
- shardResponse();
-
- // Because we provided valid split points, the config server should respond with { "ok" : 1 }.
- commitChunkSplitResponse(true);
-
- // Finally, we find the original collection, and then find the relevant chunks.
- collResponse();
- chunkResponse();
-
- future.default_timed_get();
-}
-
-TEST_F(SplitChunkTest, HashedKeyPatternIntegerSplitKeys) {
- BSONObj keyPatternObj = BSON("foo"
- << "hashed");
- _coll.setKeyPattern(BSON("_id"
- << "hashed"));
-
- // Build a vector of valid split keys, which contains values that may not necessarily be able
- // to be converted to NumberLong types.
- std::vector<BSONObj> invalidSplitKeys{
- BSON("foo" << -1), BSON("foo" << 0), BSON("foo" << 1), BSON("foo" << 42)};
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- invalidSplitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_EQUALS(ErrorCodes::CannotSplit, statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. The requests first
- // do a find on the databases, then a find on all collections in the database we are looking
- // for. Next, filter by the specific collection, and find the relevant chunks and shards.
- dbResponse();
- collResponse();
- collResponse();
- chunkResponse();
- shardResponse();
-
- future.default_timed_get();
-}
-
-TEST_F(SplitChunkTest, HashedKeyPatternDoubleSplitKeys) {
- BSONObj keyPatternObj = BSON("foo"
- << "hashed");
- _coll.setKeyPattern(BSON("_id"
- << "hashed"));
-
- // Build a vector of valid split keys, which contains values that may not necessarily be able
- // to be converted to NumberLong types.
- std::vector<BSONObj> invalidSplitKeys{
- BSON("foo" << 47.21230129), BSON("foo" << 1.0), BSON("foo" << 0.0), BSON("foo" << -0.001)};
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- invalidSplitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_EQUALS(ErrorCodes::CannotSplit, statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. The requests first
- // do a find on the databases, then a find on all collections in the database we are looking
- // for. Next, filter by the specific collection, and find the relevant chunks and shards.
- dbResponse();
- collResponse();
- collResponse();
- chunkResponse();
- shardResponse();
-
- future.default_timed_get();
-}
-
-TEST_F(SplitChunkTest, HashedKeyPatternStringSplitKeys) {
- BSONObj keyPatternObj = BSON("foo"
- << "hashed");
- _coll.setKeyPattern(BSON("_id"
- << "hashed"));
-
- // Build a vector of valid split keys, which contains values that may not necessarily be able
- // to be converted to NumberLong types.
- std::vector<BSONObj> invalidSplitKeys{BSON("foo"
- << "@&(9@*88+_241(/.*@8uuDU@(9];a;s;]3"),
- BSON("foo"
- << "string"),
- BSON("foo"
- << "14.13289"),
- BSON("foo"
- << "")};
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- invalidSplitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_EQUALS(ErrorCodes::CannotSplit, statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. The requests first
- // do a find on the databases, then a find on all collections in the database we are looking
- // for. Next, filter by the specific collection, and find the relevant chunks and shards.
- dbResponse();
- collResponse();
- collResponse();
- chunkResponse();
- shardResponse();
-
- future.default_timed_get();
-}
-
-TEST_F(SplitChunkTest, ValidRangeKeyPatternSplitKeys) {
- BSONObj keyPatternObj = BSON("foo" << 1);
-
- // Build a vector of valid split keys, which contains values that may not necessarily be able
- // be converted to NumberLong types. However, this does not matter since we are not using a
- // hashed shard key pattern.
- std::vector<BSONObj> validSplitKeys{BSON("foo" << 20),
- BSON("foo" << 512),
- BSON("foo"
- << "hello"),
- BSON("foo"
- << ""),
- BSON("foo" << 3.1415926535)};
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- validSplitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_OK(statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. The requests first
- // do a find on the databases, then a find on all collections in the database we are looking
- // for. Next, filter by the specific collection, and find the relevant chunks and shards.
- dbResponse();
- collResponse();
- collResponse();
- chunkResponse();
- shardResponse();
-
- // Because we provided valid split points, the config server should respond with { "ok" : 1 }.
- commitChunkSplitResponse(true);
-
- // Finally, we find the original collection, and then find the relevant chunks.
- collResponse();
- chunkResponse();
-
- future.default_timed_get();
-}
-
-TEST_F(SplitChunkTest, SplitChunkWithNoErrors) {
- BSONObj keyPatternObj = BSON("foo" << 1);
-
- // Build a vector of split keys. Note that we start at {"foo" : 256} and end at {"foo" : 768},
- // neither of which are boundary points.
- std::vector<BSONObj> splitKeys;
- for (int i = 256; i < 1024; i += 256) {
- splitKeys.push_back(BSON("foo" << i));
- }
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- splitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_OK(statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. The requests first
- // do a find on the databases, then a find on all collections in the database we are looking
- // for. Next, filter by the specific collection, and find the relevant chunks and shards.
- dbResponse();
- collResponse();
- collResponse();
- chunkResponse();
- shardResponse();
-
- // Mock an OK response to the request to the config server regarding the chunk split, but first
- // check the request parameters.
- onCommand([&](const RemoteCommandRequest& request) {
- ASSERT_EQ(HostAndPort("dummy", 123), request.target);
- ASSERT_BSONOBJ_EQ(request.cmdObj["min"].Obj(), BSON("foo" << 0));
- ASSERT_BSONOBJ_EQ(request.cmdObj["max"].Obj(), BSON("foo" << 1024));
-
- // Check that the split points in the request are the same as the split keys that were
- // initially passed to the splitChunk function.
- std::vector<BSONElement> splitPoints = request.cmdObj["splitPoints"].Array();
- ASSERT_EQ(splitKeys.size(), splitPoints.size());
- int i = 0;
- for (auto e : splitPoints) {
- ASSERT(e.Obj().woCompare(splitKeys[i]) == 0);
- i++;
- }
-
- return BSON("ok" << 1);
- });
-
- // Finally, we find the original collection, and then find the relevant chunks.
- collResponse();
- chunkResponse();
-
- future.default_timed_get();
-}
-
-TEST_F(SplitChunkTest, AttemptSplitWithConfigsvrError) {
- BSONObj keyPatternObj = BSON("foo" << 1);
-
- // Build a vector of split keys. Note that we start at {"foo" : 0} and end at {"foo" : 1024},
- // both of which are boundary points.
- std::vector<BSONObj> splitKeys;
- for (int i = 0; i <= 1024; i += 256) {
- splitKeys.push_back(BSON("foo" << i));
- }
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- splitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_NOT_OK(statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. The requests first
- // do a find on the databases, then a find on all collections in the database we are looking
- // for. Next, filter by the specific collection, and find the relevant chunks and shards.
- dbResponse();
- collResponse();
- collResponse();
- chunkResponse();
- shardResponse();
-
- // Because we provided invalid split points, the config server should respond with { "ok" : 0 }.
- commitChunkSplitResponse(false);
-
- // Finally, we find the original collection, and then find the relevant chunks.
- collResponse();
- chunkResponse();
-
- future.default_timed_get();
-}
-
-TEST_F(SplitChunkTest, AttemptSplitOnNoDatabases) {
- BSONObj keyPatternObj = BSON("foo" << 1);
-
- // Build a vector of split keys. Note that we start at {"foo" : 256} and end at {"foo" : 768},
- // neither of which are boundary points.
- std::vector<BSONObj> splitKeys;
- for (int i = 256; i < 1024; i += 256) {
- splitKeys.push_back(BSON("foo" << i));
- }
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- splitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_NOT_OK(statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. We give an empty
- // response to the request that finds the database, along with the request that finds all
- // collections in the database.
- emptyResponse();
- emptyResponse();
-
- future.default_timed_get();
-}
-
-TEST_F(SplitChunkTest, AttemptSplitOnNoCollections) {
- BSONObj keyPatternObj = BSON("foo" << 1);
-
- // Build a vector of split keys. Note that we start at {"foo" : 256} and end at {"foo" : 768},
- // neither of which are boundary points.
- std::vector<BSONObj> splitKeys;
- for (int i = 256; i < 1024; i += 256) {
- splitKeys.push_back(BSON("foo" << i));
- }
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- splitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_NOT_OK(statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. We first respond
- // to the request finding the databases.
- dbResponse();
-
- // Next, we give an empty response to the request for finding collections in the database,
- // followed by a response to the request for relevant shards.
- emptyResponse();
- shardResponse();
-
- future.default_timed_get();
-}
-
-TEST_F(SplitChunkTest, AttemptSplitOnNoChunks) {
- BSONObj keyPatternObj = BSON("foo" << 1);
-
- // Build a vector of split keys. Note that we start at {"foo" : 256} and end at {"foo" : 768},
- // neither of which are boundary points.
- std::vector<BSONObj> splitKeys;
- for (int i = 256; i < 1024; i += 256) {
- splitKeys.push_back(BSON("foo" << i));
- }
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- splitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_NOT_OK(statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. The requests first
- // do a find on the databases, then a find on all collections in the database we are looking
- // for.
- dbResponse();
- collResponse();
-
- // We attempt to find the relevant chunks three times. For each of these times, we will respond
- // with the relevant collection, but no chunks.
- collResponse();
- emptyResponse();
- collResponse();
- emptyResponse();
- collResponse();
- emptyResponse();
-
- future.default_timed_get();
-}
-
-TEST_F(SplitChunkTest, NoCollectionAfterSplit) {
- BSONObj keyPatternObj = BSON("foo" << 1);
-
- // Build a vector of split keys. Note that we start at {"foo" : 256} and end at {"foo" : 768},
- // neither of which are boundary points.
- std::vector<BSONObj> splitKeys;
- for (int i = 256; i < 1024; i += 256) {
- splitKeys.push_back(BSON("foo" << i));
- }
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- splitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_OK(statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. The requests first
- // do a find on the databases, then a find on all collections in the database we are looking
- // for. Next, filter by the specific collection, and find the relevant chunks and shards.
- dbResponse();
- collResponse();
- collResponse();
- chunkResponse();
- shardResponse();
-
- // Here, we mock a successful response from the config server, which denotes that the split was
- // successful on the config server's end.
- commitChunkSplitResponse(true);
-
- // Finally, give an empty response to a request regarding a find on the original collection.
- emptyResponse();
-
- future.default_timed_get();
-}
-
-TEST_F(SplitChunkTest, NoChunksAfterSplit) {
- BSONObj keyPatternObj = BSON("foo" << 1);
-
- // Build a vector of split keys. Note that we start at {"foo" : 256} and end at {"foo" : 768},
- // neither of which are boundary points.
- std::vector<BSONObj> splitKeys;
- for (int i = 256; i < 1024; i += 256) {
- splitKeys.push_back(BSON("foo" << i));
- }
-
- // Call the splitChunk function asynchronously on a different thread, so that we do not block,
- // and so we can construct the mock responses to requests made by splitChunk below.
- auto future = launchAsync([&] {
- auto statusWithOptionalChunkRange = splitChunk(operationContext(),
- _nss,
- keyPatternObj,
- _chunkRanges[1],
- splitKeys,
- _shardId.toString(),
- _epoch);
- ASSERT_NOT_OK(statusWithOptionalChunkRange.getStatus());
- });
-
- // Here, we mock responses to the requests made by the splitChunk operation. The requests first
- // do a find on the databases, then a find on all collections in the database we are looking
- // for. Next, filter by the specific collection, and find the relevant chunks and shards.
- dbResponse();
- collResponse();
- collResponse();
- chunkResponse();
- shardResponse();
-
- // Here, we mock a successful response from the config server, which denotes that the split was
- // successful on the config server's end.
- commitChunkSplitResponse(true);
-
- // We attempt to find the relevant chunks three times. For each of these times, we will respond
- // with the relevant collection, but no chunks.
- collResponse();
- emptyResponse();
- collResponse();
- emptyResponse();
- collResponse();
- emptyResponse();
-
- future.default_timed_get();
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index cc5e33d5311..32bb92585ee 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -213,7 +213,6 @@ env.Library(
'request_types/set_allow_migrations.idl',
'request_types/set_shard_version_request.cpp',
'request_types/sharded_ddl_commands.idl',
- 'request_types/split_chunk_request_type.cpp',
'request_types/update_zone_key_range_request_type.cpp',
'request_types/wait_for_fail_point.idl',
'resharding/common_types.idl',
@@ -325,7 +324,6 @@ env.Library(
'catalog_cache_loader.cpp',
'cluster_identity_loader.cpp',
'config_server_catalog_cache_loader.cpp',
- 'config_server_client.cpp',
'shard_util.cpp',
],
LIBDEPS=[
@@ -639,7 +637,6 @@ env.CppUnitTest(
'request_types/move_chunk_request_test.cpp',
'request_types/remove_shard_from_zone_request_test.cpp',
'request_types/set_shard_version_request_test.cpp',
- 'request_types/split_chunk_request_test.cpp',
'request_types/update_zone_key_range_request_test.cpp',
'routing_table_history_test.cpp',
'sessions_collection_sharded_test.cpp',
diff --git a/src/mongo/s/chunk_version.cpp b/src/mongo/s/chunk_version.cpp
index e162bed1a72..b94d7a8f0b5 100644
--- a/src/mongo/s/chunk_version.cpp
+++ b/src/mongo/s/chunk_version.cpp
@@ -27,12 +27,10 @@
* it in the license file.
*/
-#include "mongo/platform/basic.h"
-
#include "mongo/s/chunk_version.h"
+
#include "mongo/s/chunk_version_gen.h"
#include "mongo/s/pm2583_feature_flags_gen.h"
-
#include "mongo/util/str.h"
namespace mongo {
diff --git a/src/mongo/s/chunk_version_test.cpp b/src/mongo/s/chunk_version_test.cpp
index d61c99de813..3962588b52b 100644
--- a/src/mongo/s/chunk_version_test.cpp
+++ b/src/mongo/s/chunk_version_test.cpp
@@ -27,19 +27,16 @@
* it in the license file.
*/
-#include "mongo/platform/basic.h"
-
#include <limits>
#include "mongo/s/chunk_version.h"
#include "mongo/s/chunk_version_gen.h"
-
#include "mongo/unittest/unittest.h"
namespace mongo {
namespace {
-TEST(ChunkVersionParsing, Parsing60Format) {
+TEST(ChunkVersionTest, Parsing60Format) {
const Timestamp majorMinor = Timestamp(Seconds(1), 2);
const OID epoch = OID::gen();
const Timestamp timestamp(42);
@@ -70,7 +67,7 @@ TEST(ChunkVersionParsing, Parsing60Format) {
ASSERT_EQ(timestamp, futureFormatChunkVersion2.getTimestamp());
}
-TEST(ChunkVersionParsing, ToFromBSONRoundtrip) {
+TEST(ChunkVersionTest, ToFromBSONRoundtrip) {
ChunkVersion version(1, 2, OID::gen(), Timestamp(42));
const auto roundTripVersion = ChunkVersion::fromBSONPositionalOrNewerFormat([&] {
BSONObjBuilder builder;
@@ -81,7 +78,7 @@ TEST(ChunkVersionParsing, ToFromBSONRoundtrip) {
ASSERT_EQ(version, roundTripVersion);
}
-TEST(ChunkVersionParsing, ToFromBSONLegacyRoundtrip) {
+TEST(ChunkVersionTest, ToFromBSONLegacyRoundtrip) {
ChunkVersion version(1, 2, OID::gen(), Timestamp(42));
const auto roundTripVersion = ChunkVersion::fromBSONLegacyOrNewerFormat(
[&] {
@@ -94,7 +91,7 @@ TEST(ChunkVersionParsing, ToFromBSONLegacyRoundtrip) {
ASSERT_EQ(version, roundTripVersion);
}
-TEST(ChunkVersionParsing, FromBSONMissingTimestamp) {
+TEST(ChunkVersionTest, FromBSONMissingTimestamp) {
ASSERT_THROWS_CODE(ChunkVersion::fromBSONPositionalOrNewerFormat(
BSON("testVersionField" << BSON_ARRAY(
Timestamp(Seconds(2), 3) << OID::gen()))["testVersionField"]),
@@ -102,7 +99,7 @@ TEST(ChunkVersionParsing, FromBSONMissingTimestamp) {
ErrorCodes::TypeMismatch);
}
-TEST(ChunkVersionParsing, FromBSON) {
+TEST(ChunkVersionTest, FromBSON) {
const OID oid = OID::gen();
const Timestamp timestamp(42);
ChunkVersion chunkVersionComplete = ChunkVersion::fromBSONPositionalOrNewerFormat(
@@ -116,7 +113,7 @@ TEST(ChunkVersionParsing, FromBSON) {
ASSERT_EQ(timestamp, chunkVersionComplete.getTimestamp());
}
-TEST(ChunkVersionParsing, FromBSONMissingEpoch) {
+TEST(ChunkVersionTest, FromBSONMissingEpoch) {
ASSERT_THROWS_CODE(
ChunkVersion::fromBSONPositionalOrNewerFormat(
BSON("testVersionField" << BSON_ARRAY(Timestamp(Seconds(2), 3)))["testVersionField"]),
@@ -124,14 +121,14 @@ TEST(ChunkVersionParsing, FromBSONMissingEpoch) {
ErrorCodes::TypeMismatch);
}
-TEST(ChunkVersionParsing, FromBSONMissingMajorAndMinor) {
+TEST(ChunkVersionTest, FromBSONMissingMajorAndMinor) {
ASSERT_THROWS_CODE(ChunkVersion::fromBSONPositionalOrNewerFormat(
BSON("testVersionField" << BSON_ARRAY(OID::gen()))["testVersionField"]),
DBException,
ErrorCodes::TypeMismatch);
}
-TEST(ChunkVersionParsing, FromBSONLegacy_WithTimestamp_WithEpoch) {
+TEST(ChunkVersionTest, FromBSONLegacy_WithTimestamp_WithEpoch) {
const OID oid = OID::gen();
ChunkVersion chunkVersionComplete = ChunkVersion::fromBSONLegacyOrNewerFormat(
BSON("lastmod" << Timestamp(Seconds(2), 3) << "lastmodEpoch" << oid << "lastmodTimestamp"
@@ -143,7 +140,7 @@ TEST(ChunkVersionParsing, FromBSONLegacy_WithTimestamp_WithEpoch) {
ASSERT_EQ(3u, chunkVersionComplete.minorVersion());
}
-TEST(ChunkVersionParsing, FromBSONLegacy_NoTimestamp_WithUnshardedEpoch) {
+TEST(ChunkVersionTest, FromBSONLegacy_NoTimestamp_WithUnshardedEpoch) {
ChunkVersion chunkVersion = ChunkVersion::fromBSONLegacyOrNewerFormat(
BSON("lastmod" << Timestamp() << "lastmodEpoch" << ChunkVersion::UNSHARDED().epoch()),
"lastmod");
@@ -153,7 +150,7 @@ TEST(ChunkVersionParsing, FromBSONLegacy_NoTimestamp_WithUnshardedEpoch) {
ASSERT_EQ(0u, chunkVersion.minorVersion());
}
-TEST(ChunkVersionParsing, FromBSONLegacy_NoTimestamp_WithIgnoredEpoch) {
+TEST(ChunkVersionTest, FromBSONLegacy_NoTimestamp_WithIgnoredEpoch) {
ChunkVersion chunkVersion = ChunkVersion::fromBSONLegacyOrNewerFormat(
BSON("lastmod" << Timestamp() << "lastmodEpoch" << ChunkVersion::IGNORED().epoch()),
"lastmod");
@@ -163,14 +160,14 @@ TEST(ChunkVersionParsing, FromBSONLegacy_NoTimestamp_WithIgnoredEpoch) {
ASSERT_EQ(0u, chunkVersion.minorVersion());
}
-TEST(ChunkVersionParsing, FromBSONLegacy_NoTimestamp_WithShardedEpoch_Throws) {
+TEST(ChunkVersionTest, FromBSONLegacy_NoTimestamp_WithShardedEpoch_Throws) {
ASSERT_THROWS(
ChunkVersion::fromBSONLegacyOrNewerFormat(
BSON("lastmod" << Timestamp(Seconds(3), 4) << "lastmodEpoch" << OID::gen()), "lastmod"),
DBException);
}
-TEST(ChunkVersionParsing, FromBSONLegacy_WithTimestamp_NoEpoch_Throws) {
+TEST(ChunkVersionTest, FromBSONLegacy_WithTimestamp_NoEpoch_Throws) {
ASSERT_THROWS(
ChunkVersion::fromBSONLegacyOrNewerFormat(
BSON("lastmod" << Timestamp(Seconds(3), 4) << "lastmodTimestamp" << Timestamp(42)),
@@ -178,7 +175,7 @@ TEST(ChunkVersionParsing, FromBSONLegacy_WithTimestamp_NoEpoch_Throws) {
DBException);
}
-TEST(ChunkVersionParsing, FromBSONLegacy_NoTimestamp_NoEpoch_Throws) {
+TEST(ChunkVersionTest, FromBSONLegacy_NoTimestamp_NoEpoch_Throws) {
ChunkVersion chunkVersion = ChunkVersion::fromBSONLegacyOrNewerFormat(
BSON("lastmod" << Timestamp(Seconds(3), 4)), "lastmod");
ASSERT_EQ(Timestamp(), chunkVersion.getTimestamp());
@@ -187,7 +184,7 @@ TEST(ChunkVersionParsing, FromBSONLegacy_NoTimestamp_NoEpoch_Throws) {
ASSERT_EQ(4u, chunkVersion.minorVersion());
}
-TEST(ChunkVersionComparison, EqualityOperators) {
+TEST(ChunkVersionTest, EqualityOperators) {
OID epoch = OID::gen();
Timestamp timestamp = Timestamp(1);
@@ -200,7 +197,7 @@ TEST(ChunkVersionComparison, EqualityOperators) {
ASSERT_NE(ChunkVersion(4, 2, epoch, timestamp), ChunkVersion(4, 1, epoch, timestamp));
}
-TEST(ChunkVersionComparison, OlderThan) {
+TEST(ChunkVersionTest, OlderThan) {
OID epoch = OID::gen();
Timestamp timestamp(1);
Timestamp newerTimestamp(2);
@@ -220,7 +217,7 @@ TEST(ChunkVersionComparison, OlderThan) {
ASSERT(!ChunkVersion(3, 1, epoch, timestamp).isOlderThan(ChunkVersion::UNSHARDED()));
}
-TEST(ChunkVersionConstruction, CreateWithLargeValues) {
+TEST(ChunkVersionTest, CreateWithLargeValues) {
const uint32_t majorVersion = std::numeric_limits<uint32_t>::max();
const uint32_t minorVersion = std::numeric_limits<uint32_t>::max();
const auto epoch = OID::gen();
@@ -232,7 +229,7 @@ TEST(ChunkVersionConstruction, CreateWithLargeValues) {
ASSERT_EQ(Timestamp(1, 1), version.getTimestamp());
}
-TEST(ChunkVersionManipulation, ThrowsErrorIfOverflowIsAttemptedForMajorVersion) {
+TEST(ChunkVersionTest, ThrowsErrorIfOverflowIsAttemptedForMajorVersion) {
const uint32_t majorVersion = std::numeric_limits<uint32_t>::max();
const uint32_t minorVersion = 0;
const auto epoch = OID::gen();
@@ -245,7 +242,7 @@ TEST(ChunkVersionManipulation, ThrowsErrorIfOverflowIsAttemptedForMajorVersion)
ASSERT_THROWS_CODE(version.incMajor(), DBException, 31180);
}
-TEST(ChunkVersionManipulation, ThrowsErrorIfOverflowIsAttemptedForMinorVersion) {
+TEST(ChunkVersionTest, ThrowsErrorIfOverflowIsAttemptedForMinorVersion) {
const uint32_t majorVersion = 0;
const uint32_t minorVersion = std::numeric_limits<uint32_t>::max();
const auto epoch = OID::gen();
diff --git a/src/mongo/s/commands/cluster_move_chunk_cmd.cpp b/src/mongo/s/commands/cluster_move_chunk_cmd.cpp
index c0ce46ebc49..ad1ce135972 100644
--- a/src/mongo/s/commands/cluster_move_chunk_cmd.cpp
+++ b/src/mongo/s/commands/cluster_move_chunk_cmd.cpp
@@ -43,7 +43,6 @@
#include "mongo/s/catalog_cache.h"
#include "mongo/s/client/shard_registry.h"
#include "mongo/s/cluster_commands_helpers.h"
-#include "mongo/s/config_server_client.h"
#include "mongo/s/grid.h"
#include "mongo/s/request_types/migration_secondary_throttle_options.h"
#include "mongo/s/request_types/move_range_request_gen.h"
diff --git a/src/mongo/s/commands/cluster_split_cmd.cpp b/src/mongo/s/commands/cluster_split_cmd.cpp
index 69d25edd3ad..7693d3ccf22 100644
--- a/src/mongo/s/commands/cluster_split_cmd.cpp
+++ b/src/mongo/s/commands/cluster_split_cmd.cpp
@@ -270,6 +270,7 @@ public:
nss,
cm.getShardKeyPattern(),
cm.getVersion().epoch(),
+ cm.getVersion().getTimestamp(),
cm.getVersion(chunk->getShardId()) /* shardVersion */,
ChunkRange(chunk->getMin(), chunk->getMax()),
{splitPoint}));
diff --git a/src/mongo/s/config_server_client.cpp b/src/mongo/s/config_server_client.cpp
deleted file mode 100644
index 015f63452e3..00000000000
--- a/src/mongo/s/config_server_client.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/s/config_server_client.h"
-
-#include "mongo/client/read_preference.h"
-#include "mongo/s/client/shard_registry.h"
-#include "mongo/s/grid.h"
-#include "mongo/s/request_types/balance_chunk_request_type.h"
-
-namespace mongo {
-namespace configsvr_client {
-namespace {
-
-const ReadPreferenceSetting kPrimaryOnlyReadPreference{ReadPreference::PrimaryOnly};
-
-} // namespace
-
-Status rebalanceChunk(OperationContext* opCtx, const NamespaceString& nss, const ChunkType& chunk) {
- auto shardRegistry = Grid::get(opCtx)->shardRegistry();
- auto shard = shardRegistry->getConfigShard();
- auto cmdResponseStatus = shard->runCommandWithFixedRetryAttempts(
- opCtx,
- kPrimaryOnlyReadPreference,
- "admin",
- BalanceChunkRequest::serializeToRebalanceCommandForConfig(nss, chunk),
- Shard::RetryPolicy::kNotIdempotent);
- if (!cmdResponseStatus.isOK()) {
- return cmdResponseStatus.getStatus();
- }
-
- return cmdResponseStatus.getValue().commandStatus;
-}
-
-} // namespace configsvr_client
-} // namespace mongo
diff --git a/src/mongo/s/config_server_client.h b/src/mongo/s/config_server_client.h
deleted file mode 100644
index 4143f6c6260..00000000000
--- a/src/mongo/s/config_server_client.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include "mongo/s/client/shard.h"
-
-namespace mongo {
-
-class ChunkType;
-class MigrationSecondaryThrottleOptions;
-class OperationContext;
-class Status;
-
-/**
- * This namespace contains all commands, which can be executed against the config server in order
- * exercise control over the state of the sharded cluster.
- */
-namespace configsvr_client {
-
-/**
- * Requests the balancer to move the specified chunk off of its current shard to a shard, considered
- * more appropriate under the balancing policy which is currently in effect.
- */
-Status rebalanceChunk(OperationContext* opCtx, const NamespaceString& nss, const ChunkType& chunk);
-
-} // namespace configsvr_client
-} // namespace mongo
diff --git a/src/mongo/s/request_types/balance_chunk_request_type.cpp b/src/mongo/s/request_types/balance_chunk_request_type.cpp
index 0bc3ad0ea42..278947708d3 100644
--- a/src/mongo/s/request_types/balance_chunk_request_type.cpp
+++ b/src/mongo/s/request_types/balance_chunk_request_type.cpp
@@ -34,7 +34,6 @@
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/bson/util/bson_extract.h"
#include "mongo/db/write_concern_options.h"
-#include "mongo/s/request_types/balance_chunk_request_type.h"
namespace mongo {
namespace {
@@ -143,36 +142,6 @@ StatusWith<BalanceChunkRequest> BalanceChunkRequest::parseFromConfigCommand(cons
return request;
}
-BSONObj BalanceChunkRequest::serializeToMoveCommandForConfig(
- const NamespaceString& nss,
- const ChunkType& chunk,
- const ShardId& newShardId,
- const MigrationSecondaryThrottleOptions& secondaryThrottle,
- bool waitForDelete,
- bool forceJumbo) {
- invariant(chunk.validate());
-
- BSONObjBuilder cmdBuilder;
- cmdBuilder.append(kConfigSvrMoveChunk, 1);
- cmdBuilder.append(kNS, nss.ns());
- cmdBuilder.appendElements(chunk.toConfigBSON());
- // ChunkType::toConfigBSON() no longer adds the epoch
- cmdBuilder.append(ChunkType::lastmod() + "Epoch", chunk.getVersion().epoch());
- cmdBuilder.append(ChunkType::lastmod() + "Timestamp", chunk.getVersion().getTimestamp());
- cmdBuilder.append(kToShardId, newShardId.toString());
- {
- BSONObjBuilder secondaryThrottleBuilder(cmdBuilder.subobjStart(kSecondaryThrottle));
- secondaryThrottle.append(&secondaryThrottleBuilder);
- secondaryThrottleBuilder.doneFast();
- }
- cmdBuilder.append(kWaitForDelete, waitForDelete);
- cmdBuilder.append(kForceJumbo, forceJumbo);
- cmdBuilder.append(WriteConcernOptions::kWriteConcernField,
- kMajorityWriteConcernNoTimeout.toBSON());
-
- return cmdBuilder.obj();
-}
-
BSONObj BalanceChunkRequest::serializeToRebalanceCommandForConfig(const NamespaceString& nss,
const ChunkType& chunk) {
invariant(chunk.validate());
diff --git a/src/mongo/s/request_types/balance_chunk_request_type.h b/src/mongo/s/request_types/balance_chunk_request_type.h
index 1386e15fcc4..0a139219441 100644
--- a/src/mongo/s/request_types/balance_chunk_request_type.h
+++ b/src/mongo/s/request_types/balance_chunk_request_type.h
@@ -58,18 +58,6 @@ public:
bool requireUUID = true);
/**
- * Produces a BSON object for the variant of the command, which requests the balancer to move a
- * chunk to a user-specified shard.
- */
- static BSONObj serializeToMoveCommandForConfig(
- const NamespaceString& nss,
- const ChunkType& chunk,
- const ShardId& newShardId,
- const MigrationSecondaryThrottleOptions& secondaryThrottle,
- bool waitForDelete,
- bool forceJumbo);
-
- /**
* Produces a BSON object for the variant of the command, which requests the balancer to pick a
* better location for a chunk.
*/
diff --git a/src/mongo/s/shard_util.cpp b/src/mongo/s/shard_util.cpp
index 5deba9b40eb..ae5e1aa9a1b 100644
--- a/src/mongo/s/shard_util.cpp
+++ b/src/mongo/s/shard_util.cpp
@@ -197,6 +197,7 @@ StatusWith<boost::optional<ChunkRange>> splitChunkAtMultiplePoints(
const NamespaceString& nss,
const ShardKeyPattern& shardKeyPattern,
const OID& epoch,
+ const Timestamp& timestamp,
ChunkVersion shardVersion,
const ChunkRange& chunkRange,
const std::vector<BSONObj>& splitPoints) {
@@ -237,6 +238,7 @@ StatusWith<boost::optional<ChunkRange>> splitChunkAtMultiplePoints(
cmd.append("from", shardId.toString());
cmd.append("keyPattern", shardKeyPattern.toBSON());
cmd.append("epoch", epoch);
+ cmd.append("timestamp", timestamp);
shardVersion.serializeToBSON(ChunkVersion::kShardVersionField, &cmd);
chunkRange.append(&cmd);
diff --git a/src/mongo/s/shard_util.h b/src/mongo/s/shard_util.h
index d89d78ca93b..997dcc1e4c9 100644
--- a/src/mongo/s/shard_util.h
+++ b/src/mongo/s/shard_util.h
@@ -112,6 +112,7 @@ StatusWith<boost::optional<ChunkRange>> splitChunkAtMultiplePoints(
const NamespaceString& nss,
const ShardKeyPattern& shardKeyPattern,
const OID& epoch,
+ const Timestamp& timestamp,
ChunkVersion shardVersion,
const ChunkRange& chunkRange,
const std::vector<BSONObj>& splitPoints);
diff --git a/src/mongo/s/stale_exception.cpp b/src/mongo/s/stale_exception.cpp
index 9f201a157b3..ac026a45ea2 100644
--- a/src/mongo/s/stale_exception.cpp
+++ b/src/mongo/s/stale_exception.cpp
@@ -53,17 +53,12 @@ void StaleConfigInfo::serialize(BSONObjBuilder* bob) const {
}
std::shared_ptr<const ErrorExtraInfo> StaleConfigInfo::parse(const BSONObj& obj) {
- return std::make_shared<StaleConfigInfo>(parseFromCommandError(obj));
-}
-
-StaleConfigInfo StaleConfigInfo::parseFromCommandError(const BSONObj& obj) {
const auto shardId = obj["shardId"].String();
- invariant(shardId != "");
+ uassert(ErrorCodes::NoSuchKey, "The shardId field is missing", !shardId.empty());
auto extractOptionalChunkVersion = [&obj](StringData field) -> boost::optional<ChunkVersion> {
try {
- return boost::make_optional<ChunkVersion>(
- ChunkVersion::fromBSONLegacyOrNewerFormat(obj, field));
+ return ChunkVersion::fromBSONLegacyOrNewerFormat(obj, field);
} catch (const DBException& ex) {
auto status = ex.toStatus();
if (status != ErrorCodes::NoSuchKey) {
@@ -73,10 +68,19 @@ StaleConfigInfo StaleConfigInfo::parseFromCommandError(const BSONObj& obj) {
return boost::none;
};
- return StaleConfigInfo(NamespaceString(obj["ns"].String()),
- ChunkVersion::fromBSONLegacyOrNewerFormat(obj, "vReceived"),
- extractOptionalChunkVersion("vWanted"),
- ShardId(shardId));
+ return std::make_shared<StaleConfigInfo>(
+ NamespaceString(obj["ns"].String()),
+ ChunkVersion::fromBSONLegacyOrNewerFormat(obj, "vReceived"),
+ extractOptionalChunkVersion("vWanted"),
+ ShardId(shardId));
+}
+
+void StaleEpochInfo::serialize(BSONObjBuilder* bob) const {
+ bob->append("ns", _nss.ns());
+}
+
+std::shared_ptr<const ErrorExtraInfo> StaleEpochInfo::parse(const BSONObj& obj) {
+ return std::make_shared<StaleEpochInfo>(NamespaceString(obj["ns"].String()));
}
void StaleDbRoutingVersion::serialize(BSONObjBuilder* bob) const {
@@ -88,13 +92,10 @@ void StaleDbRoutingVersion::serialize(BSONObjBuilder* bob) const {
}
std::shared_ptr<const ErrorExtraInfo> StaleDbRoutingVersion::parse(const BSONObj& obj) {
- return std::make_shared<StaleDbRoutingVersion>(parseFromCommandError(obj));
-}
-
-StaleDbRoutingVersion StaleDbRoutingVersion::parseFromCommandError(const BSONObj& obj) {
- return StaleDbRoutingVersion(obj["db"].String(),
- DatabaseVersion(obj["vReceived"].Obj()),
- !obj["vWanted"].eoo() ? DatabaseVersion(obj["vWanted"].Obj())
+ return std::make_shared<StaleDbRoutingVersion>(obj["db"].String(),
+ DatabaseVersion(obj["vReceived"].Obj()),
+ !obj["vWanted"].eoo()
+ ? DatabaseVersion(obj["vWanted"].Obj())
: boost::optional<DatabaseVersion>{});
}
diff --git a/src/mongo/s/stale_exception.h b/src/mongo/s/stale_exception.h
index d67e3415731..d82b18bab52 100644
--- a/src/mongo/s/stale_exception.h
+++ b/src/mongo/s/stale_exception.h
@@ -74,7 +74,6 @@ public:
void serialize(BSONObjBuilder* bob) const;
static std::shared_ptr<const ErrorExtraInfo> parse(const BSONObj& obj);
- static StaleConfigInfo parseFromCommandError(const BSONObj& obj);
protected:
NamespaceString _nss;
@@ -96,17 +95,8 @@ public:
return _nss;
}
- void serialize(BSONObjBuilder* bob) const {
- bob->append("ns", _nss.ns());
- }
-
- static std::shared_ptr<const ErrorExtraInfo> parse(const BSONObj& obj) {
- return std::make_shared<StaleEpochInfo>(parseFromCommandError(obj));
- }
-
- static StaleEpochInfo parseFromCommandError(const BSONObj& obj) {
- return StaleEpochInfo(NamespaceString(obj["ns"].String()));
- }
+ void serialize(BSONObjBuilder* bob) const;
+ static std::shared_ptr<const ErrorExtraInfo> parse(const BSONObj& obj);
private:
NamespaceString _nss;
@@ -146,7 +136,6 @@ public:
void serialize(BSONObjBuilder* bob) const override;
static std::shared_ptr<const ErrorExtraInfo> parse(const BSONObj&);
- static StaleDbRoutingVersion parseFromCommandError(const BSONObj& commandError);
private:
std::string _db;
diff --git a/src/mongo/s/stale_exception_test.cpp b/src/mongo/s/stale_exception_test.cpp
index 0c0c23d32f1..57cb2b89062 100644
--- a/src/mongo/s/stale_exception_test.cpp
+++ b/src/mongo/s/stale_exception_test.cpp
@@ -27,23 +27,16 @@
* it in the license file.
*/
-
-#include "mongo/platform/basic.h"
-
#include "mongo/s/shard_id.h"
-#include "mongo/s/sharding_router_test_fixture.h"
#include "mongo/s/stale_exception.h"
-#include "mongo/util/assert_util.h"
+#include "mongo/unittest/unittest.h"
namespace mongo {
-
namespace {
-using StaleExceptionTest = ShardingTestFixture;
-
const NamespaceString kNss("test.nss");
-TEST_F(StaleExceptionTest, StaleConfigInfoSerializationTest) {
+TEST(StaleExceptionTest, StaleConfigInfoSerializationTest) {
const ShardId kShardId("SHARD_ID");
StaleConfigInfo info(kNss, ChunkVersion::UNSHARDED(), ChunkVersion::UNSHARDED(), kShardId);
@@ -53,15 +46,16 @@ TEST_F(StaleExceptionTest, StaleConfigInfoSerializationTest) {
info.serialize(&bob);
// Deserialize
- auto deserializedInfo = StaleConfigInfo::parseFromCommandError(bob.obj());
+ auto deserializedInfo =
+ std::static_pointer_cast<const StaleConfigInfo>(StaleConfigInfo::parse(bob.obj()));
- ASSERT_EQUALS(deserializedInfo.getNss(), kNss);
- ASSERT_EQUALS(deserializedInfo.getVersionReceived(), ChunkVersion::UNSHARDED());
- ASSERT_EQUALS(*deserializedInfo.getVersionWanted(), ChunkVersion::UNSHARDED());
- ASSERT_EQUALS(deserializedInfo.getShardId(), kShardId);
+ ASSERT_EQUALS(deserializedInfo->getNss(), kNss);
+ ASSERT_EQUALS(deserializedInfo->getVersionReceived(), ChunkVersion::UNSHARDED());
+ ASSERT_EQUALS(*deserializedInfo->getVersionWanted(), ChunkVersion::UNSHARDED());
+ ASSERT_EQUALS(deserializedInfo->getShardId(), kShardId);
}
-TEST_F(StaleExceptionTest, StaleEpochInfoSerializationTest) {
+TEST(StaleExceptionTest, StaleEpochInfoSerializationTest) {
StaleEpochInfo info(kNss);
// Serialize
@@ -69,9 +63,10 @@ TEST_F(StaleExceptionTest, StaleEpochInfoSerializationTest) {
info.serialize(&bob);
// Deserialize
- auto deserializedInfo = StaleEpochInfo::parseFromCommandError(bob.obj());
+ auto deserializedInfo =
+ std::static_pointer_cast<const StaleEpochInfo>(StaleEpochInfo::parse(bob.obj()));
- ASSERT_EQUALS(deserializedInfo.getNss(), kNss);
+ ASSERT_EQUALS(deserializedInfo->getNss(), kNss);
}
} // namespace