diff options
author | Blake Oler <blake.oler@mongodb.com> | 2019-01-22 19:32:10 -0500 |
---|---|---|
committer | Blake Oler <blake.oler@mongodb.com> | 2019-01-30 16:42:07 -0500 |
commit | c2fb213da54e20a87a96816449e070623bdafe61 (patch) | |
tree | 0d9d5530591737c8a2a3798a875be2c535ead5b0 | |
parent | 6658305fbf6942f1f1294d0bffeaec9adb1bf03a (diff) | |
download | mongo-c2fb213da54e20a87a96816449e070623bdafe61.tar.gz |
Introduce CollectionShardingRuntimeLock usage to collection critical sections.
Allows us to reduce MODE_X collection locks to MODE_IX when under
UninterruptibleLockGuards.
-rw-r--r-- | src/mongo/db/s/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/s/collection_sharding_runtime.cpp | 38 | ||||
-rw-r--r-- | src/mongo/db/s/collection_sharding_runtime.h | 41 | ||||
-rw-r--r-- | src/mongo/db/s/collection_sharding_runtime_lock.cpp | 61 | ||||
-rw-r--r-- | src/mongo/db/s/collection_sharding_runtime_lock.h | 82 | ||||
-rw-r--r-- | src/mongo/db/s/collection_sharding_state.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/s/collection_sharding_state.h | 29 | ||||
-rw-r--r-- | src/mongo/db/s/migration_destination_manager.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/s/migration_source_manager.cpp | 13 |
9 files changed, 207 insertions, 85 deletions
diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript index 128f6985853..93b25b698e3 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -13,6 +13,7 @@ env.Library( source=[ 'collection_metadata.cpp', 'collection_sharding_state.cpp', + 'collection_sharding_runtime_lock.cpp', 'database_sharding_state.cpp', 'operation_sharding_state.cpp', 'sharded_connection_info.cpp', diff --git a/src/mongo/db/s/collection_sharding_runtime.cpp b/src/mongo/db/s/collection_sharding_runtime.cpp index 2eff2a8f609..b8ef4917c82 100644 --- a/src/mongo/db/s/collection_sharding_runtime.cpp +++ b/src/mongo/db/s/collection_sharding_runtime.cpp @@ -79,7 +79,6 @@ CollectionShardingRuntime::CollectionShardingRuntime(ServiceContext* sc, NamespaceString nss, executor::TaskExecutor* rangeDeleterExecutor) : CollectionShardingState(nss), - _stateChangeMutex(nss.toString()), _nss(std::move(nss)), _metadataManager(std::make_shared<MetadataManager>(sc, _nss, rangeDeleterExecutor)) { if (isNamespaceAlwaysUnsharded(_nss)) { @@ -185,26 +184,6 @@ boost::optional<ScopedCollectionMetadata> CollectionShardingRuntime::_getMetadat return _metadataManager->getActiveMetadata(_metadataManager, atClusterTime); } -CollectionShardingRuntimeLock::CollectionShardingRuntimeLock(OperationContext* opCtx, - CollectionShardingRuntime* csr, - LockMode lockMode) - : _lock([&]() -> CSRLock { - invariant(lockMode == MODE_IS || lockMode == MODE_X); - return (lockMode == MODE_IS - ? CSRLock(Lock::SharedLock(opCtx->lockState(), csr->_stateChangeMutex)) - : CSRLock(Lock::ExclusiveLock(opCtx->lockState(), csr->_stateChangeMutex))); - }()) {} - -CollectionShardingRuntimeLock CollectionShardingRuntimeLock::lock(OperationContext* opCtx, - CollectionShardingRuntime* csr) { - return CollectionShardingRuntimeLock(opCtx, csr, MODE_IS); -} - -CollectionShardingRuntimeLock CollectionShardingRuntimeLock::lockExclusive( - OperationContext* opCtx, CollectionShardingRuntime* csr) { - return CollectionShardingRuntimeLock(opCtx, csr, MODE_X); -} - CollectionCriticalSection::CollectionCriticalSection(OperationContext* opCtx, NamespaceString ns) : _nss(std::move(ns)), _opCtx(opCtx) { AutoGetCollection autoColl(_opCtx, @@ -214,13 +193,19 @@ CollectionCriticalSection::CollectionCriticalSection(OperationContext* opCtx, Na AutoGetCollection::ViewMode::kViewsForbidden, opCtx->getServiceContext()->getPreciseClockSource()->now() + Milliseconds(migrationLockAcquisitionMaxWaitMS.load())); - CollectionShardingState::get(opCtx, _nss)->enterCriticalSectionCatchUpPhase(_opCtx); + auto* const csr = CollectionShardingRuntime::get(_opCtx, _nss); + auto csrLock = CollectionShardingRuntimeLock::lockExclusive(_opCtx, csr); + + csr->enterCriticalSectionCatchUpPhase(_opCtx, csrLock); } CollectionCriticalSection::~CollectionCriticalSection() { UninterruptibleLockGuard noInterrupt(_opCtx->lockState()); - AutoGetCollection autoColl(_opCtx, _nss, MODE_IX, MODE_X); - CollectionShardingState::get(_opCtx, _nss)->exitCriticalSection(_opCtx); + AutoGetCollection autoColl(_opCtx, _nss, MODE_IX, MODE_IX); + auto* const csr = CollectionShardingRuntime::get(_opCtx, _nss); + auto csrLock = CollectionShardingRuntimeLock::lockExclusive(_opCtx, csr); + + csr->exitCriticalSection(_opCtx, csrLock); } void CollectionCriticalSection::enterCommitPhase() { @@ -231,7 +216,10 @@ void CollectionCriticalSection::enterCommitPhase() { AutoGetCollection::ViewMode::kViewsForbidden, _opCtx->getServiceContext()->getPreciseClockSource()->now() + Milliseconds(migrationLockAcquisitionMaxWaitMS.load())); - CollectionShardingState::get(_opCtx, _nss)->enterCriticalSectionCommitPhase(_opCtx); + auto* const csr = CollectionShardingRuntime::get(_opCtx, _nss); + auto csrLock = CollectionShardingRuntimeLock::lockExclusive(_opCtx, csr); + + csr->enterCriticalSectionCommitPhase(_opCtx, csrLock); } } // namespace mongo diff --git a/src/mongo/db/s/collection_sharding_runtime.h b/src/mongo/db/s/collection_sharding_runtime.h index 89171876643..57b61e7390b 100644 --- a/src/mongo/db/s/collection_sharding_runtime.h +++ b/src/mongo/db/s/collection_sharding_runtime.h @@ -33,6 +33,7 @@ #include "mongo/base/disallow_copying.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/s/collection_sharding_runtime_lock.h" #include "mongo/db/s/collection_sharding_state.h" #include "mongo/db/s/metadata_manager.h" #include "mongo/platform/atomic_word.h" @@ -154,10 +155,6 @@ private: friend boost::optional<Date_t> CollectionRangeDeleter::cleanUpNextRange( OperationContext*, NamespaceString const&, OID const&, int, CollectionRangeDeleter*); - // Object-wide ResourceMutex to protect changes to the CollectionShardingRuntime or objects - // held within. - Lock::ResourceMutex _stateChangeMutex; - // Namespace this state belongs to. const NamespaceString _nss; @@ -169,42 +166,6 @@ private: }; /** - * RAII-style class that locks the CollectionShardingRuntime using the CollectionShardingRuntime's - * ResourceMutex. The lock will be created and acquired on construction. The lock will be dismissed - * upon destruction of the CollectionShardingRuntimeLock object. - */ -class CollectionShardingRuntimeLock { - -public: - using CSRLock = stdx::variant<Lock::SharedLock, Lock::ExclusiveLock>; - - /** - * Locks the sharding runtime state for the specified collection with the - * CollectionShardingRuntime object's ResourceMutex in MODE_IS. When the object goes out of - * scope, the ResourceMutex will be unlocked. - */ - static CollectionShardingRuntimeLock lock(OperationContext* opCtx, - CollectionShardingRuntime* csr); - - /** - * Follows the same functionality as the CollectionShardingRuntimeLock lock method, except - * that lockExclusive takes the ResourceMutex in MODE_X. - */ - static CollectionShardingRuntimeLock lockExclusive(OperationContext* opCtx, - CollectionShardingRuntime* csr); - -private: - CollectionShardingRuntimeLock(OperationContext* opCtx, - CollectionShardingRuntime* csr, - LockMode lockMode); - - // The lock created and locked upon construction of a CollectionShardingRuntimeLock object. - // It locks the ResourceMutex taken from the CollectionShardingRuntime class, passed in on - // construction. - CSRLock _lock; -}; - -/** * RAII-style class, which obtains a reference to the critical section for the specified collection. */ class CollectionCriticalSection { diff --git a/src/mongo/db/s/collection_sharding_runtime_lock.cpp b/src/mongo/db/s/collection_sharding_runtime_lock.cpp new file mode 100644 index 00000000000..b16016f76fc --- /dev/null +++ b/src/mongo/db/s/collection_sharding_runtime_lock.cpp @@ -0,0 +1,61 @@ + +/** + * 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_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kSharding + +#include "mongo/platform/basic.h" + +#include "mongo/db/s/collection_sharding_runtime_lock.h" + +#include "mongo/db/s/collection_sharding_runtime.h" + +namespace mongo { + +CollectionShardingRuntimeLock::CollectionShardingRuntimeLock(OperationContext* opCtx, + CollectionShardingState* csr, + LockMode lockMode) + : _lock([&]() -> CSRLock { + invariant(lockMode == MODE_IS || lockMode == MODE_X); + return (lockMode == MODE_IS + ? CSRLock(Lock::SharedLock(opCtx->lockState(), csr->_stateChangeMutex)) + : CSRLock(Lock::ExclusiveLock(opCtx->lockState(), csr->_stateChangeMutex))); + }()) {} + +CollectionShardingRuntimeLock CollectionShardingRuntimeLock::lock(OperationContext* opCtx, + CollectionShardingState* csr) { + return CollectionShardingRuntimeLock(opCtx, csr, MODE_IS); +} + +CollectionShardingRuntimeLock CollectionShardingRuntimeLock::lockExclusive( + OperationContext* opCtx, CollectionShardingState* csr) { + return CollectionShardingRuntimeLock(opCtx, csr, MODE_X); +} + +} // namespace mongo
\ No newline at end of file diff --git a/src/mongo/db/s/collection_sharding_runtime_lock.h b/src/mongo/db/s/collection_sharding_runtime_lock.h new file mode 100644 index 00000000000..3105f52157b --- /dev/null +++ b/src/mongo/db/s/collection_sharding_runtime_lock.h @@ -0,0 +1,82 @@ +/** + * 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/base/disallow_copying.h" +#include "mongo/db/concurrency/d_concurrency.h" +#include "mongo/stdx/variant.h" + +namespace mongo { + +class CollectionShardingState; + +/** + * RAII-style class that locks the CollectionShardingRuntime using the CollectionShardingRuntime's + * ResourceMutex. The lock will be created and acquired on construction. The lock will be dismissed + * upon destruction of the CollectionShardingRuntimeLock object. + * + * The CollectionShardingRuntimeLock currently ensures concurrent access to the following sections: + * + * - The collection's critical section + * - Attaching and detaching the MigrationSoourceManager from the CollectionShardingRuntime and + * accessing the MigrationSourceManager from the CollectionShardingRuntime. + */ +class CollectionShardingRuntimeLock { + +public: + using CSRLock = stdx::variant<Lock::SharedLock, Lock::ExclusiveLock>; + + /** + * Locks the sharding runtime state for the specified collection with the + * CollectionShardingRuntime object's ResourceMutex in MODE_IS. When the object goes out of + * scope, the ResourceMutex will be unlocked. + */ + static CollectionShardingRuntimeLock lock(OperationContext* opCtx, + CollectionShardingState* csr); + + /** + * Follows the same functionality as the CollectionShardingRuntimeLock lock method, except + * that lockExclusive takes the ResourceMutex in MODE_X. + */ + static CollectionShardingRuntimeLock lockExclusive(OperationContext* opCtx, + CollectionShardingState* csr); + +private: + CollectionShardingRuntimeLock(OperationContext* opCtx, + CollectionShardingState* csr, + LockMode lockMode); + + // The lock created and locked upon construction of a CollectionShardingRuntimeLock object. + // It locks the ResourceMutex taken from the CollectionShardingRuntime class, passed in on + // construction. + CSRLock _lock; +}; + +} // namespace mongo
\ No newline at end of file diff --git a/src/mongo/db/s/collection_sharding_state.cpp b/src/mongo/db/s/collection_sharding_state.cpp index f65f262a029..296ec6f10de 100644 --- a/src/mongo/db/s/collection_sharding_state.cpp +++ b/src/mongo/db/s/collection_sharding_state.cpp @@ -35,6 +35,7 @@ #include "mongo/db/s/collection_sharding_state.h" #include "mongo/db/repl/read_concern_args.h" +#include "mongo/db/s/collection_sharding_runtime_lock.h" #include "mongo/db/s/operation_sharding_state.h" #include "mongo/db/s/sharded_connection_info.h" #include "mongo/s/stale_exception.h" @@ -135,7 +136,8 @@ ChunkVersion getOperationReceivedVersion(OperationContext* opCtx, const Namespac } // namespace -CollectionShardingState::CollectionShardingState(NamespaceString nss) : _nss(std::move(nss)) {} +CollectionShardingState::CollectionShardingState(NamespaceString nss) + : _stateChangeMutex(nss.toString()), _nss(std::move(nss)) {} CollectionShardingState* CollectionShardingState::get(OperationContext* opCtx, const NamespaceString& nss) { @@ -207,9 +209,13 @@ void CollectionShardingState::checkShardVersionOrThrow(OperationContext* opCtx) const auto wantedShardVersion = metadata->isSharded() ? metadata->getShardVersion() : ChunkVersion::UNSHARDED(); - auto criticalSectionSignal = _critSec.getSignal(opCtx->lockState()->isWriteLocked() - ? ShardingMigrationCriticalSection::kWrite - : ShardingMigrationCriticalSection::kRead); + auto criticalSectionSignal = [&] { + auto csrLock = CollectionShardingRuntimeLock::lock(opCtx, this); + return _critSec.getSignal(opCtx->lockState()->isWriteLocked() + ? ShardingMigrationCriticalSection::kWrite + : ShardingMigrationCriticalSection::kRead); + }(); + if (criticalSectionSignal) { // Set migration critical section on operation sharding state: operation will wait for the // migration to finish before returning failure and retrying. @@ -258,18 +264,21 @@ void CollectionShardingState::checkShardVersionOrThrow(OperationContext* opCtx) MONGO_UNREACHABLE; } -void CollectionShardingState::enterCriticalSectionCatchUpPhase(OperationContext* opCtx) { +void CollectionShardingState::enterCriticalSectionCatchUpPhase(OperationContext* opCtx, + CollectionShardingRuntimeLock&) { invariant(opCtx->lockState()->isCollectionLockedForMode(_nss.ns(), MODE_X)); _critSec.enterCriticalSectionCatchUpPhase(); } -void CollectionShardingState::enterCriticalSectionCommitPhase(OperationContext* opCtx) { +void CollectionShardingState::enterCriticalSectionCommitPhase(OperationContext* opCtx, + CollectionShardingRuntimeLock&) { invariant(opCtx->lockState()->isCollectionLockedForMode(_nss.ns(), MODE_X)); _critSec.enterCriticalSectionCommitPhase(); } -void CollectionShardingState::exitCriticalSection(OperationContext* opCtx) { - invariant(opCtx->lockState()->isCollectionLockedForMode(_nss.ns(), MODE_X)); +void CollectionShardingState::exitCriticalSection(OperationContext* opCtx, + CollectionShardingRuntimeLock&) { + invariant(opCtx->lockState()->isCollectionLockedForMode(_nss.ns(), MODE_IX)); _critSec.exitCriticalSection(); } diff --git a/src/mongo/db/s/collection_sharding_state.h b/src/mongo/db/s/collection_sharding_state.h index e964dbced12..5e0e2a9c8db 100644 --- a/src/mongo/db/s/collection_sharding_state.h +++ b/src/mongo/db/s/collection_sharding_state.h @@ -33,6 +33,7 @@ #include "mongo/base/disallow_copying.h" #include "mongo/db/logical_time.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/s/collection_sharding_runtime_lock.h" #include "mongo/db/s/scoped_collection_metadata.h" #include "mongo/db/s/sharding_migration_critical_section.h" @@ -104,12 +105,24 @@ public: void checkShardVersionOrThrow(OperationContext* opCtx); /** - * Methods to control the collection's critical section. Must be called with the collection X - * lock held. + * Methods to control the collection's critical section. Methods listed below must be called + * with both the collection lock and CollectionShardingRuntimeLock held in exclusive mode. + * + * In these methods, the CollectionShardingRuntimeLock ensures concurrent access to the + * critical section. + */ + void enterCriticalSectionCatchUpPhase(OperationContext* opCtx, CollectionShardingRuntimeLock&); + void enterCriticalSectionCommitPhase(OperationContext* opCtx, CollectionShardingRuntimeLock&); + + + /** + * Method to control the collection's critical secion. Method listed below must be called with + * the collection lock in IX mode and the CollectionShardingRuntimeLock in exclusive mode. + * + * In this method, the CollectionShardingRuntimeLock ensures concurrent access to the + * critical section. */ - void enterCriticalSectionCatchUpPhase(OperationContext* opCtx); - void enterCriticalSectionCommitPhase(OperationContext* opCtx); - void exitCriticalSection(OperationContext* opCtx); + void exitCriticalSection(OperationContext* opCtx, CollectionShardingRuntimeLock&); /** * If the collection is currently in a critical section, returns the critical section signal to @@ -123,6 +136,12 @@ protected: CollectionShardingState(NamespaceString nss); private: + friend CollectionShardingRuntimeLock; + + // Object-wide ResourceMutex to protect changes to the CollectionShardingRuntime or objects + // held within. Use only the CollectionShardingRuntimeLock to lock this mutex. + Lock::ResourceMutex _stateChangeMutex; + // Namespace this state belongs to. const NamespaceString _nss; diff --git a/src/mongo/db/s/migration_destination_manager.cpp b/src/mongo/db/s/migration_destination_manager.cpp index e5fd84ce884..8d12d740d1b 100644 --- a/src/mongo/db/s/migration_destination_manager.cpp +++ b/src/mongo/db/s/migration_destination_manager.cpp @@ -1202,7 +1202,7 @@ void MigrationDestinationManager::_forgetPending(OperationContext* opCtx, ChunkR } UninterruptibleLockGuard noInterrupt(opCtx->lockState()); - AutoGetCollection autoColl(opCtx, _nss, MODE_IX, MODE_X); + AutoGetCollection autoColl(opCtx, _nss, MODE_IX, MODE_IX); auto* const css = CollectionShardingRuntime::get(opCtx, _nss); const auto optMetadata = css->getCurrentMetadataIfKnown(); diff --git a/src/mongo/db/s/migration_source_manager.cpp b/src/mongo/db/s/migration_source_manager.cpp index 5031490ba21..d0973fd57d3 100644 --- a/src/mongo/db/s/migration_source_manager.cpp +++ b/src/mongo/db/s/migration_source_manager.cpp @@ -449,7 +449,7 @@ Status MigrationSourceManager::commitChunkMetadataOnConfig(OperationContext* opC // this node can accept writes for this collection as a proxy for it being primary. if (!status.isOK()) { UninterruptibleLockGuard noInterrupt(opCtx->lockState()); - AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_X); + AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_IX); if (!repl::ReplicationCoordinator::get(opCtx)->canAcceptWritesFor(opCtx, getNss())) { CollectionShardingRuntime::get(opCtx, getNss())->clearFilteringMetadata(); uassertStatusOK(status.withContext( @@ -485,7 +485,7 @@ Status MigrationSourceManager::commitChunkMetadataOnConfig(OperationContext* opC if (!refreshStatus.isOK()) { UninterruptibleLockGuard noInterrupt(opCtx->lockState()); - AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_X); + AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_IX); CollectionShardingRuntime::get(opCtx, getNss())->clearFilteringMetadata(); @@ -684,18 +684,19 @@ void MigrationSourceManager::_cleanup(OperationContext* opCtx) { auto cloneDriver = [&]() { // Unregister from the collection's sharding state and exit the migration critical section. UninterruptibleLockGuard noInterrupt(opCtx->lockState()); - AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_X); - auto* const css = CollectionShardingRuntime::get(opCtx, getNss()); + AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_IX); + auto* const csr = CollectionShardingRuntime::get(opCtx, getNss()); + auto csrLock = CollectionShardingRuntimeLock::lockExclusive(opCtx, csr); // In the kCreated state there should be no state to clean up, but we can verify this // just to be safe. if (_state == kCreated) { // Verify that we did not set the MSM on the CSR. - invariant(!msmForCsr(css)); + invariant(!msmForCsr(csr)); // Verify that the clone driver was not initialized. invariant(!_cloneDriver); } else { - auto oldMsmOnCsr = std::exchange(msmForCsr(css), nullptr); + auto oldMsmOnCsr = std::exchange(msmForCsr(csr), nullptr); invariant(this == oldMsmOnCsr); } _critSec.reset(); |