summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/commands/mr.cpp4
-rw-r--r--src/mongo/db/pipeline/pipeline_d.cpp2
-rw-r--r--src/mongo/db/read_concern.cpp3
-rw-r--r--src/mongo/db/s/SConscript15
-rw-r--r--src/mongo/db/s/collection_sharding_state_test.cpp84
-rw-r--r--src/mongo/db/s/merge_chunks_command.cpp16
-rw-r--r--src/mongo/db/s/move_primary_command.cpp2
-rw-r--r--src/mongo/db/s/set_shard_version_command.cpp2
-rw-r--r--src/mongo/db/s/shard_filtering_metadata_refresh.cpp2
-rw-r--r--src/mongo/db/s/shard_server_catalog_cache_loader.cpp4
-rw-r--r--src/mongo/db/s/sharding_state.cpp70
-rw-r--r--src/mongo/db/s/sharding_state.h74
-rw-r--r--src/mongo/db/s/sharding_state_command.cpp18
-rw-r--r--src/mongo/db/s/sharding_state_recovery.cpp7
-rw-r--r--src/mongo/db/s/sharding_state_test.cpp94
-rw-r--r--src/mongo/db/s/shardsvr_shard_collection.cpp2
-rw-r--r--src/mongo/s/shard_id.cpp43
-rw-r--r--src/mongo/s/shard_id.h50
18 files changed, 225 insertions, 267 deletions
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index c89c76f2a17..b32c21aa099 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -1773,10 +1773,10 @@ public:
if (auto cm = outRoutingInfoStatus.getValue().cm()) {
// Fetch result from other shards 1 chunk at a time. It would be better to do just
// one big $or query, but then the sorting would not be efficient.
- const string shardName = ShardingState::get(opCtx)->getShardName();
+ const auto shardId = ShardingState::get(opCtx)->shardId();
for (const auto& chunk : cm->chunks()) {
- if (chunk.getShardId() == shardName) {
+ if (chunk.getShardId() == shardId) {
chunks.push_back(chunk);
}
}
diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp
index 653cc389344..f437fc87dfc 100644
--- a/src/mongo/db/pipeline/pipeline_d.cpp
+++ b/src/mongo/db/pipeline/pipeline_d.cpp
@@ -822,7 +822,7 @@ Status PipelineD::MongoDInterface::attachCursorSourceToPipeline(
std::string PipelineD::MongoDInterface::getShardName(OperationContext* opCtx) const {
if (ShardingState::get(opCtx)->enabled()) {
- return ShardingState::get(opCtx)->getShardName();
+ return ShardingState::get(opCtx)->shardId().toString();
}
return std::string();
diff --git a/src/mongo/db/read_concern.cpp b/src/mongo/db/read_concern.cpp
index fef22f8ab1f..f1130eb6942 100644
--- a/src/mongo/db/read_concern.cpp
+++ b/src/mongo/db/read_concern.cpp
@@ -141,8 +141,7 @@ Status makeNoopWriteIfNeeded(OperationContext* opCtx, LogicalTime clusterTime) {
return Status::OK();
}
- auto myShard =
- Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardingState->getShardName());
+ auto myShard = Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardingState->shardId());
if (!myShard.isOK()) {
return myShard.getStatus();
}
diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript
index dc9c95c08cb..b8f62dac438 100644
--- a/src/mongo/db/s/SConscript
+++ b/src/mongo/db/s/SConscript
@@ -356,6 +356,7 @@ env.CppUnitTest(
'migration_chunk_cloner_source_legacy_test.cpp',
'migration_destination_manager_test.cpp',
'namespace_metadata_change_notifications_test.cpp',
+ 'shard_metadata_util_test.cpp',
'shard_server_catalog_cache_loader_test.cpp',
'sharding_state_test.cpp',
'split_vector_test.cpp',
@@ -373,7 +374,7 @@ env.CppUnitTest(
)
env.CppUnitTest(
- target='collection_sharding_state_test',
+ target='collection_sharding_runtime_test',
source=[
'collection_metadata_filtering_test.cpp',
'collection_metadata_test.cpp',
@@ -393,18 +394,6 @@ env.CppUnitTest(
)
env.CppUnitTest(
- target='shard_metadata_util_test',
- source=[
- 'shard_metadata_util_test.cpp',
- ],
- LIBDEPS=[
- '$BUILD_DIR/mongo/db/auth/authmocks',
- '$BUILD_DIR/mongo/s/shard_server_test_fixture',
- 'sharding',
- ],
-)
-
-env.CppUnitTest(
target='session_catalog_migration_source_test',
source=[
'session_catalog_migration_source_test.cpp',
diff --git a/src/mongo/db/s/collection_sharding_state_test.cpp b/src/mongo/db/s/collection_sharding_state_test.cpp
index 34952c22777..10fb4937c1d 100644
--- a/src/mongo/db/s/collection_sharding_state_test.cpp
+++ b/src/mongo/db/s/collection_sharding_state_test.cpp
@@ -28,12 +28,9 @@
#include "mongo/platform/basic.h"
#include "mongo/db/catalog_raii.h"
-#include "mongo/db/dbdirectclient.h"
#include "mongo/db/s/collection_sharding_runtime.h"
#include "mongo/db/s/shard_server_op_observer.h"
-#include "mongo/db/s/sharding_state.h"
#include "mongo/db/s/type_shard_identity.h"
-#include "mongo/s/catalog/type_chunk.h"
#include "mongo/s/shard_server_test_fixture.h"
namespace mongo {
@@ -41,87 +38,6 @@ namespace {
const NamespaceString kTestNss("TestDB", "TestColl");
-class CollectionShardingStateTest : public ShardServerTestFixture {
-public:
- void setUp() override {
- ShardServerTestFixture::setUp();
-
- // Note: this assumes that globalInit will always be called on the same thread as the main
- // test thread.
- ShardingState::get(operationContext())
- ->setGlobalInitMethodForTest(
- [this](OperationContext*, const ConnectionString&, StringData) {
- _initCallCount++;
- return Status::OK();
- });
- }
-
- int getInitCallCount() const {
- return _initCallCount;
- }
-
-private:
- int _initCallCount = 0;
-};
-
-TEST_F(CollectionShardingStateTest, GlobalInitGetsCalledAfterWriteCommits) {
- ShardIdentityType shardIdentity;
- shardIdentity.setConfigsvrConnectionString(
- ConnectionString(ConnectionString::SET, "a:1,b:2", "config"));
- shardIdentity.setShardName("a");
- shardIdentity.setClusterId(OID::gen());
-
- DBDirectClient client(operationContext());
- client.insert("admin.system.version", shardIdentity.toShardIdentityDocument());
- ASSERT_EQ(1, getInitCallCount());
-}
-
-TEST_F(CollectionShardingStateTest, GlobalInitDoesntGetCalledIfWriteAborts) {
- ShardIdentityType shardIdentity;
- shardIdentity.setConfigsvrConnectionString(
- ConnectionString(ConnectionString::SET, "a:1,b:2", "config"));
- shardIdentity.setShardName("a");
- shardIdentity.setClusterId(OID::gen());
-
- // This part of the test ensures that the collection exists for the AutoGetCollection below to
- // find and also validates that the initializer does not get called for non-sharding documents
- DBDirectClient client(operationContext());
- client.insert("admin.system.version", BSON("_id" << 1));
- ASSERT_EQ(0, getInitCallCount());
-
- {
- AutoGetCollection autoColl(
- operationContext(), NamespaceString("admin.system.version"), MODE_IX);
-
- WriteUnitOfWork wuow(operationContext());
- ASSERT_OK(autoColl.getCollection()->insertDocument(
- operationContext(), shardIdentity.toShardIdentityDocument(), {}));
- ASSERT_EQ(0, getInitCallCount());
- }
-
- ASSERT_EQ(0, getInitCallCount());
-}
-
-TEST_F(CollectionShardingStateTest, GlobalInitDoesntGetsCalledIfNSIsNotForShardIdentity) {
- ShardIdentityType shardIdentity;
- shardIdentity.setConfigsvrConnectionString(
- ConnectionString(ConnectionString::SET, "a:1,b:2", "config"));
- shardIdentity.setShardName("a");
- shardIdentity.setClusterId(OID::gen());
-
- DBDirectClient client(operationContext());
- client.insert("admin.user", shardIdentity.toShardIdentityDocument());
- ASSERT_EQ(0, getInitCallCount());
-}
-
-TEST_F(CollectionShardingStateTest, OnInsertOpThrowWithIncompleteShardIdentityDocument) {
- DBDirectClient client(operationContext());
- client.insert(
- "admin.system.version",
- BSON("_id" << ShardIdentityType::IdName << ShardIdentity::kShardNameFieldName << "a"));
- ASSERT(!client.getLastError().empty());
-}
-
/**
* Constructs a CollectionMetadata suitable for refreshing a CollectionShardingState. The only
* salient detail is the argument `keyPattern` which, defining the shard key, selects the fields
diff --git a/src/mongo/db/s/merge_chunks_command.cpp b/src/mongo/db/s/merge_chunks_command.cpp
index c8d67321745..e145f684bc9 100644
--- a/src/mongo/db/s/merge_chunks_command.cpp
+++ b/src/mongo/db/s/merge_chunks_command.cpp
@@ -162,7 +162,7 @@ Status mergeChunks(OperationContext* opCtx,
std::string errmsg = stream()
<< "could not merge chunks, collection " << nss.ns() << " range starting at "
<< redact(minKey) << " and ending at " << redact(maxKey) << " does not belong to shard "
- << shardingState->getShardName();
+ << shardingState->shardId();
warning() << errmsg;
return Status(ErrorCodes::IllegalOperation, errmsg);
@@ -178,9 +178,9 @@ Status mergeChunks(OperationContext* opCtx,
bool minKeyInRange = rangeContains(firstDocMin, firstDocMax, minKey);
if (!minKeyInRange) {
- std::string errmsg = stream()
- << "could not merge chunks, collection " << nss.ns() << " range starting at "
- << redact(minKey) << " does not belong to shard " << shardingState->getShardName();
+ std::string errmsg = stream() << "could not merge chunks, collection " << nss.ns()
+ << " range starting at " << redact(minKey)
+ << " does not belong to shard " << shardingState->shardId();
warning() << errmsg;
return Status(ErrorCodes::IllegalOperation, errmsg);
@@ -192,9 +192,9 @@ Status mergeChunks(OperationContext* opCtx,
bool maxKeyInRange = lastDocMin.woCompare(maxKey) < 0 && lastDocMax.woCompare(maxKey) >= 0;
if (!maxKeyInRange) {
- std::string errmsg = stream()
- << "could not merge chunks, collection " << nss.ns() << " range ending at "
- << redact(maxKey) << " does not belong to shard " << shardingState->getShardName();
+ std::string errmsg = stream() << "could not merge chunks, collection " << nss.ns()
+ << " range ending at " << redact(maxKey)
+ << " does not belong to shard " << shardingState->shardId();
warning() << errmsg;
return Status(ErrorCodes::IllegalOperation, errmsg);
@@ -242,7 +242,7 @@ Status mergeChunks(OperationContext* opCtx,
// Run _configsvrCommitChunkMerge.
//
MergeChunkRequest request{nss,
- shardingState->getShardName(),
+ shardingState->shardId().toString(),
shardVersion.epoch(),
chunkBoundaries,
LogicalClock::get(opCtx)->getClusterTime().asTimestamp()};
diff --git a/src/mongo/db/s/move_primary_command.cpp b/src/mongo/db/s/move_primary_command.cpp
index dc0905adc51..e4c0ff0fc34 100644
--- a/src/mongo/db/s/move_primary_command.cpp
+++ b/src/mongo/db/s/move_primary_command.cpp
@@ -151,7 +151,7 @@ private:
static void _runImpl(OperationContext* opCtx,
const ShardMovePrimary movePrimaryRequest,
const StringData dbname) {
- ShardId fromShardId = ShardingState::get(opCtx)->getShardName();
+ ShardId fromShardId = ShardingState::get(opCtx)->shardId();
ShardId toShardId = movePrimaryRequest.getTo().toString();
MovePrimarySourceManager movePrimarySourceManager(
diff --git a/src/mongo/db/s/set_shard_version_command.cpp b/src/mongo/db/s/set_shard_version_command.cpp
index 034eec0b9ae..0876fc56eb5 100644
--- a/src/mongo/db/s/set_shard_version_command.cpp
+++ b/src/mongo/db/s/set_shard_version_command.cpp
@@ -160,7 +160,7 @@ public:
// Validate shardName parameter.
const auto shardName = cmdObj["shard"].str();
- const auto storedShardName = shardingState->getShardName();
+ const auto storedShardName = shardingState->shardId().toString();
uassert(ErrorCodes::BadValue,
str::stream() << "received shardName " << shardName
<< " which differs from stored shardName "
diff --git a/src/mongo/db/s/shard_filtering_metadata_refresh.cpp b/src/mongo/db/s/shard_filtering_metadata_refresh.cpp
index 8c97a3e26fa..8bb5b5a2614 100644
--- a/src/mongo/db/s/shard_filtering_metadata_refresh.cpp
+++ b/src/mongo/db/s/shard_filtering_metadata_refresh.cpp
@@ -154,7 +154,7 @@ ChunkVersion forceShardFilteringMetadataRefresh(OperationContext* opCtx,
}
std::unique_ptr<CollectionMetadata> newCollectionMetadata =
- stdx::make_unique<CollectionMetadata>(cm, shardingState->getShardName());
+ stdx::make_unique<CollectionMetadata>(cm, shardingState->shardId());
css->refreshMetadata(opCtx, std::move(newCollectionMetadata));
diff --git a/src/mongo/db/s/shard_server_catalog_cache_loader.cpp b/src/mongo/db/s/shard_server_catalog_cache_loader.cpp
index 2db03cec50a..bffca0350bd 100644
--- a/src/mongo/db/s/shard_server_catalog_cache_loader.cpp
+++ b/src/mongo/db/s/shard_server_catalog_cache_loader.cpp
@@ -277,7 +277,7 @@ void forcePrimaryCollectionRefreshAndWaitForReplication(OperationContext* opCtx,
invariant(shardingState->enabled());
auto selfShard = uassertStatusOK(
- Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardingState->getShardName()));
+ Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardingState->shardId()));
auto cmdResponse = uassertStatusOK(selfShard->runCommandWithFixedRetryAttempts(
opCtx,
@@ -302,7 +302,7 @@ void forcePrimaryDatabaseRefreshAndWaitForReplication(OperationContext* opCtx, S
invariant(shardingState->enabled());
auto selfShard = uassertStatusOK(
- Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardingState->getShardName()));
+ Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardingState->shardId()));
auto cmdResponse = uassertStatusOK(selfShard->runCommandWithFixedRetryAttempts(
opCtx,
diff --git a/src/mongo/db/s/sharding_state.cpp b/src/mongo/db/s/sharding_state.cpp
index 18c2c10f703..cc3583e830d 100644
--- a/src/mongo/db/s/sharding_state.cpp
+++ b/src/mongo/db/s/sharding_state.cpp
@@ -32,7 +32,6 @@
#include "mongo/db/s/sharding_state.h"
-#include "mongo/base/init.h"
#include "mongo/bson/util/bson_extract.h"
#include "mongo/client/connection_string.h"
#include "mongo/client/replica_set_monitor.h"
@@ -55,15 +54,12 @@
#include "mongo/rpc/metadata/config_server_metadata.h"
#include "mongo/rpc/metadata/metadata_hook.h"
#include "mongo/s/catalog/sharding_catalog_client.h"
-#include "mongo/s/catalog/type_chunk.h"
-#include "mongo/s/catalog_cache.h"
-#include "mongo/s/chunk_version.h"
+#include "mongo/s/catalog_cache_loader.h"
#include "mongo/s/client/shard_registry.h"
#include "mongo/s/client/sharding_network_connection_hook.h"
#include "mongo/s/grid.h"
#include "mongo/s/sharding_initialization.h"
#include "mongo/util/log.h"
-#include "mongo/util/mongoutils/str.h"
namespace mongo {
namespace {
@@ -101,9 +97,9 @@ void updateShardIdentityConfigStringCB(const std::string& setName,
} // namespace
ShardingState::ShardingState()
- : _initializationState(static_cast<uint32_t>(InitializationState::kNew)),
- _initializationStatus(Status(ErrorCodes::InternalError, "Uninitialized value")),
- _globalInit(&initializeGlobalShardingStateForMongod) {}
+ : _globalInit(&initializeGlobalShardingStateForMongod),
+ _initializationState(static_cast<uint32_t>(InitializationState::kNew)),
+ _initializationStatus(Status(ErrorCodes::InternalError, "Uninitialized value")) {}
ShardingState::~ShardingState() = default;
@@ -120,8 +116,8 @@ bool ShardingState::enabled() const {
}
void ShardingState::setEnabledForTest(const std::string& shardName) {
+ _shardId = shardName;
_setInitializationState(InitializationState::kInitialized);
- _shardName = shardName;
}
Status ShardingState::canAcceptShardedCommands() const {
@@ -137,10 +133,28 @@ Status ShardingState::canAcceptShardedCommands() const {
}
}
-std::string ShardingState::getShardName() {
+ShardId ShardingState::shardId() {
invariant(enabled());
stdx::lock_guard<stdx::mutex> lk(_mutex);
- return _shardName;
+ return _shardId;
+}
+
+OID ShardingState::clusterId() {
+ invariant(enabled());
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ return _clusterId;
+}
+
+bool ShardingState::needCollectionMetadata(OperationContext* opCtx, const std::string& ns) {
+ if (!enabled())
+ return false;
+
+ Client* client = opCtx->getClient();
+
+ // Shard version information received from mongos may either by attached to the Client or
+ // directly to the OperationContext.
+ return ShardedConnectionInfo::get(client, false) ||
+ OperationShardingState::get(opCtx).hasShardVersion();
}
void ShardingState::shutDown(OperationContext* opCtx) {
@@ -175,8 +189,6 @@ void ShardingState::setGlobalInitMethodForTest(GlobalInitFunc func) {
_globalInit = func;
}
-// NOTE: This method will be called inside a database lock so it should never take any database
-// locks, perform I/O, or any long running operations.
Status ShardingState::initializeFromShardIdentity(OperationContext* opCtx,
const ShardIdentityType& shardIdentity) {
invariant(serverGlobalParams.clusterRole == ClusterRole::ShardServer);
@@ -195,8 +207,8 @@ Status ShardingState::initializeFromShardIdentity(OperationContext* opCtx,
const auto& configSvrConnStr = shardIdentity.getConfigsvrConnectionString();
if (enabled()) {
- invariant(!_shardName.empty());
- fassert(40372, _shardName == shardIdentity.getShardName());
+ invariant(_shardId.isValid());
+ fassert(40372, _shardId == shardIdentity.getShardName());
auto prevConfigsvrConnStr =
Grid::get(opCtx)->shardRegistry()->getConfigServerConnectionString();
@@ -245,7 +257,7 @@ Status ShardingState::initializeFromShardIdentity(OperationContext* opCtx,
_initializationStatus = status;
_setInitializationState(InitializationState::kError);
}
- _shardName = shardIdentity.getShardName().toString();
+ _shardId = shardIdentity.getShardName().toString();
_clusterId = shardIdentity.getClusterId();
return status;
@@ -375,32 +387,6 @@ StatusWith<bool> ShardingState::initializeShardingAwarenessIfNeeded(OperationCon
}
}
-void ShardingState::appendInfo(OperationContext* opCtx, BSONObjBuilder& builder) {
- const bool isEnabled = enabled();
- builder.appendBool("enabled", isEnabled);
- if (!isEnabled)
- return;
-
- stdx::lock_guard<stdx::mutex> lk(_mutex);
-
- builder.append("configServer",
- Grid::get(opCtx)->shardRegistry()->getConfigServerConnectionString().toString());
- builder.append("shardName", _shardName);
- builder.append("clusterId", _clusterId);
-}
-
-bool ShardingState::needCollectionMetadata(OperationContext* opCtx, const std::string& ns) {
- if (!enabled())
- return false;
-
- Client* client = opCtx->getClient();
-
- // Shard version information received from mongos may either by attached to the Client or
- // directly to the OperationContext.
- return ShardedConnectionInfo::get(client, false) ||
- OperationShardingState::get(opCtx).hasShardVersion();
-}
-
Status ShardingState::updateShardIdentityConfigString(OperationContext* opCtx,
const std::string& newConnectionString) {
BSONObj updateObj(ShardIdentityType::createConfigServerUpdateObject(newConnectionString));
diff --git a/src/mongo/db/s/sharding_state.h b/src/mongo/db/s/sharding_state.h
index 38e663b9087..29c21d879a3 100644
--- a/src/mongo/db/s/sharding_state.h
+++ b/src/mongo/db/s/sharding_state.h
@@ -29,13 +29,11 @@
#pragma once
#include <string>
-#include <vector>
#include "mongo/base/disallow_copying.h"
#include "mongo/bson/oid.h"
-#include "mongo/db/s/collection_sharding_state.h"
+#include "mongo/s/shard_id.h"
#include "mongo/stdx/functional.h"
-#include "mongo/stdx/memory.h"
#include "mongo/stdx/mutex.h"
namespace mongo {
@@ -86,12 +84,6 @@ public:
bool enabled() const;
/**
- * Force-sets the initialization state to InitializationState::kInitialized, for testing
- * purposes. Note that this function should ONLY be used for testing purposes.
- */
- void setEnabledForTest(const std::string& shardName);
-
- /**
* Returns Status::OK if the ShardingState is enabled; if not, returns an error describing
* whether the ShardingState is just not yet initialized, or if this shard is not running with
* --shardsvr at all.
@@ -101,17 +93,23 @@ public:
*/
Status canAcceptShardedCommands() const;
- std::string getShardName();
+ /**
+ * Returns the shard id to which this node belongs. May only be called if 'enabled()' above
+ * returns true.
+ */
+ ShardId shardId();
/**
- * Initializes the sharding state of this server from the shard identity document argument
- * and sets secondary or primary state information on the catalog cache loader.
- *
- * Note: caller must hold a global/database lock! Needed in order to stably check for
- * replica set state (primary, secondary, standalone).
+ * Returns the cluster id of the cluster to which this node belongs. May only be called if
+ * 'enabled()' above returns true.
*/
- Status initializeFromShardIdentity(OperationContext* opCtx,
- const ShardIdentityType& shardIdentity);
+ OID clusterId();
+
+ /**
+ * Returns true if this node is a shard and if the currently runnint operation must engage the
+ * sharding subsystem (i.e., perform version checking, orphan filtering, etc).
+ */
+ bool needCollectionMetadata(OperationContext* opCtx, const std::string& ns);
/**
* Shuts down sharding machinery on the shard.
@@ -124,10 +122,6 @@ public:
*/
Status updateConfigServerOpTimeFromMetadata(OperationContext* opCtx);
- void appendInfo(OperationContext* opCtx, BSONObjBuilder& b);
-
- bool needCollectionMetadata(OperationContext* opCtx, const std::string& ns);
-
/**
* Updates the config server field of the shardIdentity document with the given connection
* string.
@@ -138,12 +132,6 @@ public:
const std::string& newConnectionString);
/**
- * For testing only. Mock the initialization method used by initializeFromConfigConnString and
- * initializeFromShardIdentity after all checks are performed.
- */
- void setGlobalInitMethodForTest(GlobalInitFunc func);
-
- /**
* If started with --shardsvr, initializes sharding awareness from the shardIdentity document
* on disk, if there is one.
* If started with --shardsvr in queryableBackupMode, initializes sharding awareness from the
@@ -158,6 +146,27 @@ public:
*/
StatusWith<bool> initializeShardingAwarenessIfNeeded(OperationContext* opCtx);
+ /**
+ * Initializes the sharding state of this server from the shard identity document argument
+ * and sets secondary or primary state information on the catalog cache loader.
+ *
+ * NOTE: This must be called under at least Global IX lock in order for the replica set member
+ * state to be stable (primary/secondary).
+ */
+ Status initializeFromShardIdentity(OperationContext* opCtx,
+ const ShardIdentityType& shardIdentity);
+
+ /**
+ * For testing only. Mock the initialization method used by initializeFromConfigConnString and
+ * initializeFromShardIdentity after all checks are performed.
+ */
+ void setGlobalInitMethodForTest(GlobalInitFunc func);
+
+ /**
+ * For testing only. Force-sets the initialization state to InitializationState::kInitialized.
+ */
+ void setEnabledForTest(const std::string& shardName);
+
private:
// Progress of the sharding state initialization
enum class InitializationState : uint32_t {
@@ -185,6 +194,9 @@ private:
*/
void _setInitializationState(InitializationState newState);
+ // Function for initializing the external sharding state components not owned here.
+ GlobalInitFunc _globalInit;
+
// Protects state below
stdx::mutex _mutex;
@@ -194,17 +206,11 @@ private:
// Only valid if _initializationState is kError. Contains the reason for initialization failure.
Status _initializationStatus;
- // Signaled when ::initialize finishes.
- stdx::condition_variable _initializationFinishedCondition;
-
// Sets the shard name for this host (comes through setShardVersion)
- std::string _shardName;
+ ShardId _shardId;
// The id for the cluster this shard belongs to.
OID _clusterId;
-
- // Function for initializing the external sharding state components not owned here.
- GlobalInitFunc _globalInit;
};
} // namespace mongo
diff --git a/src/mongo/db/s/sharding_state_command.cpp b/src/mongo/db/s/sharding_state_command.cpp
index f22986f7a71..24abfee411c 100644
--- a/src/mongo/db/s/sharding_state_command.cpp
+++ b/src/mongo/db/s/sharding_state_command.cpp
@@ -34,7 +34,9 @@
#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/privilege.h"
#include "mongo/db/commands.h"
+#include "mongo/db/s/collection_sharding_state.h"
#include "mongo/db/s/sharding_state.h"
+#include "mongo/s/grid.h"
#include "mongo/util/log.h"
namespace mongo {
@@ -68,8 +70,20 @@ public:
const std::string& dbname,
const BSONObj& cmdObj,
BSONObjBuilder& result) override {
- ShardingState::get(opCtx)->appendInfo(opCtx, result);
- CollectionShardingState::report(opCtx, &result);
+ auto const shardingState = ShardingState::get(opCtx);
+ const bool isEnabled = shardingState->enabled();
+ result.appendBool("enabled", isEnabled);
+
+ if (isEnabled) {
+ auto const shardRegistry = Grid::get(opCtx)->shardRegistry();
+ result.append("configServer",
+ shardRegistry->getConfigServerConnectionString().toString());
+ result.append("shardName", shardingState->shardId());
+ result.append("clusterId", shardingState->clusterId());
+
+ CollectionShardingState::report(opCtx, &result);
+ }
+
return true;
}
diff --git a/src/mongo/db/s/sharding_state_recovery.cpp b/src/mongo/db/s/sharding_state_recovery.cpp
index 3623d448ec7..8b6e9d99f22 100644
--- a/src/mongo/db/s/sharding_state_recovery.cpp
+++ b/src/mongo/db/s/sharding_state_recovery.cpp
@@ -159,10 +159,11 @@ Status modifyRecoveryDocument(OperationContext* opCtx,
// nodes still expect to find them, so we must include them until after 4.0 ships.
//
// TODO SERVER-34166: Stop writing config server connection string and shard name.
+ auto const grid = Grid::get(opCtx);
BSONObj updateObj = RecoveryDocument::createChangeObj(
- Grid::get(opCtx)->shardRegistry()->getConfigServerConnectionString(),
- ShardingState::get(opCtx)->getShardName(),
- Grid::get(opCtx)->configOpTime(),
+ grid->shardRegistry()->getConfigServerConnectionString(),
+ ShardingState::get(opCtx)->shardId().toString(),
+ grid->configOpTime(),
change);
LOG(1) << "Changing sharding recovery document " << redact(updateObj);
diff --git a/src/mongo/db/s/sharding_state_test.cpp b/src/mongo/db/s/sharding_state_test.cpp
index 94346a3e34d..36b6024cc21 100644
--- a/src/mongo/db/s/sharding_state_test.cpp
+++ b/src/mongo/db/s/sharding_state_test.cpp
@@ -29,6 +29,7 @@
#include "mongo/platform/basic.h"
#include "mongo/client/remote_command_targeter_mock.h"
+#include "mongo/db/catalog_raii.h"
#include "mongo/db/concurrency/d_concurrency.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/op_observer_impl.h"
@@ -40,19 +41,99 @@
#include "mongo/db/s/sharding_state.h"
#include "mongo/db/s/type_shard_identity.h"
#include "mongo/db/server_options.h"
-#include "mongo/db/storage/storage_options.h"
#include "mongo/s/catalog/dist_lock_manager_mock.h"
#include "mongo/s/catalog/sharding_catalog_client_impl.h"
#include "mongo/s/client/shard_registry.h"
#include "mongo/s/config_server_catalog_cache_loader.h"
+#include "mongo/s/shard_server_test_fixture.h"
#include "mongo/s/sharding_mongod_test_fixture.h"
namespace mongo {
namespace {
-using executor::RemoteCommandRequest;
+const std::string kShardName("TestShard");
+
+class ShardingInitializationOpObserverTest : public ShardServerTestFixture {
+public:
+ void setUp() override {
+ ShardServerTestFixture::setUp();
+
+ // NOTE: this assumes that globalInit will always be called on the same thread as the main
+ // test thread
+ ShardingState::get(operationContext())
+ ->setGlobalInitMethodForTest(
+ [this](OperationContext*, const ConnectionString&, StringData) {
+ _initCallCount++;
+ return Status::OK();
+ });
+ }
+
+ int getInitCallCount() const {
+ return _initCallCount;
+ }
+
+private:
+ int _initCallCount = 0;
+};
+
+TEST_F(ShardingInitializationOpObserverTest, GlobalInitGetsCalledAfterWriteCommits) {
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnectionString(
+ ConnectionString(ConnectionString::SET, "a:1,b:2", "config"));
+ shardIdentity.setShardName(kShardName);
+ shardIdentity.setClusterId(OID::gen());
+
+ DBDirectClient client(operationContext());
+ client.insert("admin.system.version", shardIdentity.toShardIdentityDocument());
+ ASSERT_EQ(1, getInitCallCount());
+}
+
+TEST_F(ShardingInitializationOpObserverTest, GlobalInitDoesntGetCalledIfWriteAborts) {
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnectionString(
+ ConnectionString(ConnectionString::SET, "a:1,b:2", "config"));
+ shardIdentity.setShardName(kShardName);
+ shardIdentity.setClusterId(OID::gen());
+
+ // This part of the test ensures that the collection exists for the AutoGetCollection below to
+ // find and also validates that the initializer does not get called for non-sharding documents
+ DBDirectClient client(operationContext());
+ client.insert("admin.system.version", BSON("_id" << 1));
+ ASSERT_EQ(0, getInitCallCount());
+
+ {
+ AutoGetCollection autoColl(
+ operationContext(), NamespaceString("admin.system.version"), MODE_IX);
+
+ WriteUnitOfWork wuow(operationContext());
+ ASSERT_OK(autoColl.getCollection()->insertDocument(
+ operationContext(), shardIdentity.toShardIdentityDocument(), {}));
+ ASSERT_EQ(0, getInitCallCount());
+ }
+
+ ASSERT_EQ(0, getInitCallCount());
+}
+
+TEST_F(ShardingInitializationOpObserverTest, GlobalInitDoesntGetsCalledIfNSIsNotForShardIdentity) {
+ ShardIdentityType shardIdentity;
+ shardIdentity.setConfigsvrConnectionString(
+ ConnectionString(ConnectionString::SET, "a:1,b:2", "config"));
+ shardIdentity.setShardName(kShardName);
+ shardIdentity.setClusterId(OID::gen());
+
+ DBDirectClient client(operationContext());
+ client.insert("admin.user", shardIdentity.toShardIdentityDocument());
+ ASSERT_EQ(0, getInitCallCount());
+}
+
+TEST_F(ShardingInitializationOpObserverTest, OnInsertOpThrowWithIncompleteShardIdentityDocument) {
+ DBDirectClient client(operationContext());
+ client.insert("admin.system.version",
+ BSON("_id" << ShardIdentityType::IdName << ShardIdentity::kShardNameFieldName
+ << kShardName));
+ ASSERT(!client.getLastError().empty());
+}
-const std::string kShardName("a");
class ShardingStateTest : public ShardingMongodTestFixture {
protected:
@@ -162,7 +243,7 @@ TEST_F(ShardingStateTest, ValidShardIdentitySucceeds) {
ASSERT_OK(shardingState()->initializeFromShardIdentity(operationContext(), shardIdentity));
ASSERT_TRUE(shardingState()->enabled());
- ASSERT_EQ(kShardName, shardingState()->getShardName());
+ ASSERT_EQ(kShardName, shardingState()->shardId());
ASSERT_EQ("config/a:1,b:2", shardRegistry()->getConfigServerConnectionString().toString());
}
@@ -230,7 +311,7 @@ TEST_F(ShardingStateTest, InitializeAgainWithMatchingShardIdentitySucceeds) {
ASSERT_OK(shardingState()->initializeFromShardIdentity(operationContext(), shardIdentity2));
ASSERT_TRUE(shardingState()->enabled());
- ASSERT_EQ(kShardName, shardingState()->getShardName());
+ ASSERT_EQ(kShardName, shardingState()->shardId());
ASSERT_EQ("config/a:1,b:2", shardRegistry()->getConfigServerConnectionString().toString());
}
@@ -261,7 +342,7 @@ TEST_F(ShardingStateTest, InitializeAgainWithSameReplSetNameSucceeds) {
ASSERT_OK(shardingState()->initializeFromShardIdentity(operationContext(), shardIdentity2));
ASSERT_TRUE(shardingState()->enabled());
- ASSERT_EQ(kShardName, shardingState()->getShardName());
+ ASSERT_EQ(kShardName, shardingState()->shardId());
ASSERT_EQ("config/a:1,b:2", shardRegistry()->getConfigServerConnectionString().toString());
}
@@ -441,7 +522,6 @@ TEST_F(ShardingStateTest,
ASSERT_EQUALS(ErrorCodes::UnsupportedFormat, swShardingInitialized.getStatus().code());
}
-
TEST_F(ShardingStateTest,
InitializeShardingAwarenessIfNeededNotReadOnlyAndShardServerAndValidShardIdentity) {
// Insert the shardIdentity doc to disk while pretending that we are in "standalone" mode,
diff --git a/src/mongo/db/s/shardsvr_shard_collection.cpp b/src/mongo/db/s/shardsvr_shard_collection.cpp
index ec2528b6835..6c727aef65c 100644
--- a/src/mongo/db/s/shardsvr_shard_collection.cpp
+++ b/src/mongo/db/s/shardsvr_shard_collection.cpp
@@ -663,7 +663,7 @@ public:
request.getUnique(),
finalSplitPoints,
fromMapReduce,
- ShardingState::get(opCtx)->getShardName(),
+ ShardingState::get(opCtx)->shardId(),
numContiguousChunksPerShard);
return true;
diff --git a/src/mongo/s/shard_id.cpp b/src/mongo/s/shard_id.cpp
index 961c8711e17..098fcedde1f 100644
--- a/src/mongo/s/shard_id.cpp
+++ b/src/mongo/s/shard_id.cpp
@@ -30,54 +30,16 @@
#include "mongo/platform/basic.h"
-#include <functional>
-#include <string.h>
-
-#include "mongo/base/status_with.h"
#include "mongo/s/shard_id.h"
-namespace mongo {
-
-using std::string;
-using std::ostream;
-
-bool ShardId::operator==(const ShardId& other) const {
- return (this->_shardId == other._shardId);
-}
-
-bool ShardId::operator!=(const ShardId& other) const {
- return !(*this == other);
-}
-
-bool ShardId::operator==(const string& other) const {
- return (this->_shardId == other);
-}
-
-bool ShardId::operator!=(const string& other) const {
- return !(*this == other);
-}
-
-ShardId::operator StringData() {
- return StringData(_shardId.data(), _shardId.size());
-}
+#include <functional>
-const string& ShardId::toString() const {
- return _shardId;
-}
+namespace mongo {
bool ShardId::isValid() const {
return !_shardId.empty();
}
-ostream& operator<<(ostream& os, const ShardId& shardId) {
- os << shardId._shardId;
- return os;
-}
-
-bool ShardId::operator<(const ShardId& other) const {
- return _shardId < other._shardId;
-}
-
int ShardId::compare(const ShardId& other) const {
return _shardId.compare(other._shardId);
}
@@ -85,4 +47,5 @@ int ShardId::compare(const ShardId& other) const {
std::size_t ShardId::Hasher::operator()(const ShardId& shardId) const {
return std::hash<std::string>()(shardId._shardId);
}
+
} // namespace mongo
diff --git a/src/mongo/s/shard_id.h b/src/mongo/s/shard_id.h
index cbb15032cca..d4aed48a972 100644
--- a/src/mongo/s/shard_id.h
+++ b/src/mongo/s/shard_id.h
@@ -28,36 +28,25 @@
#pragma once
-#include <iostream>
+#include <ostream>
#include <string>
#include "mongo/base/string_data.h"
#include "mongo/bson/util/builder.h"
-
namespace mongo {
-class NamespaceString;
-
/**
* Representation of a shard identifier.
*/
class ShardId {
public:
- friend std::ostream& operator<<(std::ostream&, const ShardId&);
-
ShardId() = default;
-
- // Note that this c-tor allows the implicit conversion from std::string
ShardId(std::string shardId) : _shardId(std::move(shardId)) {}
- // Implicit StringData conversion
- operator StringData();
-
- bool operator==(const ShardId&) const;
- bool operator!=(const ShardId&) const;
- bool operator==(const std::string&) const;
- bool operator!=(const std::string&) const;
+ operator StringData() const {
+ return StringData(_shardId);
+ }
template <size_t N>
bool operator==(const char (&val)[N]) const {
@@ -69,10 +58,14 @@ public:
return (strncmp(val, _shardId.data(), N) != 0);
}
- // The operator< is needed to do proper comparison in a std::map
- bool operator<(const ShardId&) const;
+ const std::string& toString() const {
+ return _shardId;
+ }
- const std::string& toString() const;
+ /**
+ * Returns true if _shardId is not empty. Subject to include more validations in the future.
+ */
+ bool isValid() const;
/**
* Returns -1, 0, or 1 if 'this' is less, equal, or greater than 'other' in
@@ -81,11 +74,6 @@ public:
int compare(const ShardId& other) const;
/**
- * Returns true if _shardId is not empty. Subject to include more validations in the future.
- */
- bool isValid() const;
-
- /**
* Functor compatible with std::hash for std::unordered_{map,set}
*/
struct Hasher {
@@ -96,6 +84,22 @@ private:
std::string _shardId;
};
+inline bool operator==(const ShardId& lhs, const ShardId& rhs) {
+ return lhs.compare(rhs) == 0;
+}
+
+inline bool operator!=(const ShardId& lhs, const ShardId& rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator<(const ShardId& lhs, const ShardId& rhs) {
+ return lhs.compare(rhs) < 0;
+}
+
+inline std::ostream& operator<<(std::ostream& os, const ShardId& shardId) {
+ return os << shardId.toString();
+}
+
template <typename Allocator>
StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& stream,
const ShardId& shardId) {