diff options
-rw-r--r-- | src/mongo/db/commands/mr.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/pipeline/pipeline_d.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/read_concern.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/s/SConscript | 15 | ||||
-rw-r--r-- | src/mongo/db/s/collection_sharding_state_test.cpp | 84 | ||||
-rw-r--r-- | src/mongo/db/s/merge_chunks_command.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/s/move_primary_command.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/s/set_shard_version_command.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/s/shard_filtering_metadata_refresh.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/s/shard_server_catalog_cache_loader.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_state.cpp | 70 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_state.h | 74 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_state_command.cpp | 18 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_state_recovery.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_state_test.cpp | 94 | ||||
-rw-r--r-- | src/mongo/db/s/shardsvr_shard_collection.cpp | 2 | ||||
-rw-r--r-- | src/mongo/s/shard_id.cpp | 43 | ||||
-rw-r--r-- | src/mongo/s/shard_id.h | 50 |
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) { |