diff options
author | A. Jesse Jiryu Davis <jesse@mongodb.com> | 2019-03-25 14:47:29 -0400 |
---|---|---|
committer | A. Jesse Jiryu Davis <jesse@mongodb.com> | 2019-03-28 11:34:55 -0400 |
commit | d99db775dbf73e27bd20e402f26f068dc199203d (patch) | |
tree | 6ed4928384ae0b1fce3165b58e9a2e87cfd2dfc9 /src/mongo/db | |
parent | f922827d45ce752e148185dfa3a785f7c9cf29fd (diff) | |
download | mongo-d99db775dbf73e27bd20e402f26f068dc199203d.tar.gz |
SERVER-40069 Fix global lock tracking for txns
Includes SERVER-40084, stores global lock acquisition flags in an
atomic.
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/concurrency/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/concurrency/d_concurrency.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/concurrency/d_concurrency.h | 6 | ||||
-rw-r--r-- | src/mongo/db/concurrency/d_concurrency_test.cpp | 65 | ||||
-rw-r--r-- | src/mongo/db/concurrency/global_lock_acquisition_tracker.cpp | 54 | ||||
-rw-r--r-- | src/mongo/db/concurrency/global_lock_acquisition_tracker.h | 75 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_state.cpp | 31 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_state.h | 11 | ||||
-rw-r--r-- | src/mongo/db/concurrency/locker.h | 20 | ||||
-rw-r--r-- | src/mongo/db/concurrency/locker_noop.h | 14 | ||||
-rw-r--r-- | src/mongo/db/curop.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/service_entry_point_common.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/service_entry_point_mongod.cpp | 4 |
14 files changed, 115 insertions, 182 deletions
diff --git a/src/mongo/db/concurrency/SConscript b/src/mongo/db/concurrency/SConscript index 986bb83c616..f74bf25ba89 100644 --- a/src/mongo/db/concurrency/SConscript +++ b/src/mongo/db/concurrency/SConscript @@ -40,7 +40,6 @@ env.Library( target='lock_manager', source=[ 'd_concurrency.cpp', - 'global_lock_acquisition_tracker.cpp', 'lock_manager.cpp', 'lock_state.cpp', 'lock_stats.cpp', diff --git a/src/mongo/db/concurrency/d_concurrency.cpp b/src/mongo/db/concurrency/d_concurrency.cpp index c1f858a75a0..dce90b1dcfb 100644 --- a/src/mongo/db/concurrency/d_concurrency.cpp +++ b/src/mongo/db/concurrency/d_concurrency.cpp @@ -37,7 +37,6 @@ #include <vector> #include "mongo/db/concurrency/flow_control_ticketholder.h" -#include "mongo/db/concurrency/global_lock_acquisition_tracker.h" #include "mongo/db/namespace_string.h" #include "mongo/db/service_context.h" #include "mongo/stdx/memory.h" @@ -223,7 +222,7 @@ void Lock::GlobalLock::waitForLockUntil(Date_t deadline) { const ResourceId globalResId(RESOURCE_GLOBAL, ResourceId::SINGLETON_GLOBAL); auto lockMode = _opCtx->lockState()->getLockMode(globalResId); - GlobalLockAcquisitionTracker::get(_opCtx).setGlobalLockModeBit(lockMode); + _opCtx->lockState()->setGlobalLockModeBit(lockMode); } void Lock::GlobalLock::_unlock() { diff --git a/src/mongo/db/concurrency/d_concurrency.h b/src/mongo/db/concurrency/d_concurrency.h index e6259e85ca4..7efb40ffd7d 100644 --- a/src/mongo/db/concurrency/d_concurrency.h +++ b/src/mongo/db/concurrency/d_concurrency.h @@ -211,8 +211,7 @@ public: * Enqueues lock but does not block on lock acquisition. * Call waitForLockUntil() to complete locking process. * - * Does not set that the global lock was taken on the GlobalLockAcquisitionTracker. Call - * waitForLockUntil to do so. + * Does not set Locker::wasGlobalWriteLockTaken(). Call waitForLockUntil to do so. */ GlobalLock(OperationContext* opCtx, LockMode lockMode, @@ -236,8 +235,7 @@ public: } /** - * Waits for lock to be granted. Sets that the global lock was taken on the - * GlobalLockAcquisitionTracker. + * Waits for lock to be granted. Sets Locker::wasGlobalWriteLockTaken(). */ void waitForLockUntil(Date_t deadline); diff --git a/src/mongo/db/concurrency/d_concurrency_test.cpp b/src/mongo/db/concurrency/d_concurrency_test.cpp index 4c919292b80..17987599def 100644 --- a/src/mongo/db/concurrency/d_concurrency_test.cpp +++ b/src/mongo/db/concurrency/d_concurrency_test.cpp @@ -36,7 +36,6 @@ #include <vector> #include "mongo/db/concurrency/d_concurrency.h" -#include "mongo/db/concurrency/global_lock_acquisition_tracker.h" #include "mongo/db/concurrency/lock_manager_test_help.h" #include "mongo/db/concurrency/replication_state_transition_lock_guard.h" #include "mongo/db/concurrency/write_conflict_exception.h" @@ -472,65 +471,65 @@ TEST_F(DConcurrencyTestFixture, RSTLmodeX_Timeout) { TEST_F(DConcurrencyTestFixture, GlobalLockXSetsGlobalWriteLockedOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalWriteLockTaken()); { Lock::GlobalLock globalWrite(opCtx, MODE_X, Date_t::now(), Lock::InterruptBehavior::kThrow); ASSERT(globalWrite.isLocked()); } - ASSERT_TRUE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_TRUE(opCtx->lockState()->wasGlobalWriteLockTaken()); } TEST_F(DConcurrencyTestFixture, GlobalLockIXSetsGlobalWriteLockedOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalWriteLockTaken()); { Lock::GlobalLock globalWrite( opCtx, MODE_IX, Date_t::now(), Lock::InterruptBehavior::kThrow); ASSERT(globalWrite.isLocked()); } - ASSERT_TRUE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_TRUE(opCtx->lockState()->wasGlobalWriteLockTaken()); } TEST_F(DConcurrencyTestFixture, GlobalLockSDoesNotSetGlobalWriteLockedOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalWriteLockTaken()); { Lock::GlobalLock globalRead(opCtx, MODE_S, Date_t::now(), Lock::InterruptBehavior::kThrow); ASSERT(globalRead.isLocked()); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalWriteLockTaken()); } TEST_F(DConcurrencyTestFixture, GlobalLockISDoesNotSetGlobalWriteLockedOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalWriteLockTaken()); { Lock::GlobalLock globalRead(opCtx, MODE_IS, Date_t::now(), Lock::InterruptBehavior::kThrow); ASSERT(globalRead.isLocked()); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalWriteLockTaken()); } TEST_F(DConcurrencyTestFixture, DBLockXSetsGlobalWriteLockedOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalWriteLockTaken()); { Lock::DBLock dbWrite(opCtx, "db", MODE_X); } - ASSERT_TRUE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_TRUE(opCtx->lockState()->wasGlobalWriteLockTaken()); } TEST_F(DConcurrencyTestFixture, DBLockSDoesNotSetGlobalWriteLockedOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalWriteLockTaken()); { Lock::DBLock dbRead(opCtx, "db", MODE_S); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalWriteLockTaken()); } TEST_F(DConcurrencyTestFixture, GlobalLockXDoesNotSetGlobalWriteLockedWhenLockAcquisitionTimesOut) { @@ -542,7 +541,7 @@ TEST_F(DConcurrencyTestFixture, GlobalLockXDoesNotSetGlobalWriteLockedWhenLockAc ASSERT(globalWrite0.isLocked()); auto opCtx = clients[1].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalWriteLockTaken()); { ASSERT_THROWS_CODE( Lock::GlobalLock( @@ -550,88 +549,88 @@ TEST_F(DConcurrencyTestFixture, GlobalLockXDoesNotSetGlobalWriteLockedWhenLockAc AssertionException, ErrorCodes::LockTimeout); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalWriteLockTaken()); } TEST_F(DConcurrencyTestFixture, GlobalLockSSetsGlobalSharedLockTakenOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); { Lock::GlobalLock globalWrite(opCtx, MODE_S, Date_t::now(), Lock::InterruptBehavior::kThrow); ASSERT(globalWrite.isLocked()); } - ASSERT_TRUE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_TRUE(opCtx->lockState()->wasGlobalSharedLockTaken()); } TEST_F(DConcurrencyTestFixture, GlobalLockISDoesNotSetGlobalSharedLockTakenOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); { Lock::GlobalLock globalRead(opCtx, MODE_IS, Date_t::now(), Lock::InterruptBehavior::kThrow); ASSERT(globalRead.isLocked()); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); } TEST_F(DConcurrencyTestFixture, GlobalLockIXDoesNotSetGlobalSharedLockTakenOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); { Lock::GlobalLock globalRead(opCtx, MODE_IX, Date_t::now(), Lock::InterruptBehavior::kThrow); ASSERT(globalRead.isLocked()); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); } TEST_F(DConcurrencyTestFixture, GlobalLockXDoesNotSetGlobalSharedLockTakenOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); { Lock::GlobalLock globalRead(opCtx, MODE_X, Date_t::now(), Lock::InterruptBehavior::kThrow); ASSERT(globalRead.isLocked()); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); } TEST_F(DConcurrencyTestFixture, DBLockSDoesNotSetGlobalSharedLockTakeOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); { Lock::DBLock dbWrite(opCtx, "db", MODE_S); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); } TEST_F(DConcurrencyTestFixture, DBLockISDoesNotSetGlobalSharedLockTakeOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); { Lock::DBLock dbWrite(opCtx, "db", MODE_IS); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); } TEST_F(DConcurrencyTestFixture, DBLockIXDoesNotSetGlobalSharedLockTakeOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); { Lock::DBLock dbWrite(opCtx, "db", MODE_IX); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); } TEST_F(DConcurrencyTestFixture, DBLockXDoesNotSetGlobalSharedLockTakeOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); { Lock::DBLock dbRead(opCtx, "db", MODE_X); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); } TEST_F(DConcurrencyTestFixture, @@ -644,7 +643,7 @@ TEST_F(DConcurrencyTestFixture, ASSERT(globalWrite0.isLocked()); auto opCtx = clients[1].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); { ASSERT_THROWS_CODE( Lock::GlobalLock( @@ -652,7 +651,7 @@ TEST_F(DConcurrencyTestFixture, AssertionException, ErrorCodes::LockTimeout); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalSharedLockTaken()); } TEST_F(DConcurrencyTestFixture, GlobalLockS_NoTimeoutDueToGlobalLockS) { diff --git a/src/mongo/db/concurrency/global_lock_acquisition_tracker.cpp b/src/mongo/db/concurrency/global_lock_acquisition_tracker.cpp deleted file mode 100644 index eeec12f3c1a..00000000000 --- a/src/mongo/db/concurrency/global_lock_acquisition_tracker.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/db/concurrency/global_lock_acquisition_tracker.h" - -namespace mongo { - -const OperationContext::Decoration<GlobalLockAcquisitionTracker> GlobalLockAcquisitionTracker::get = - OperationContext::declareDecoration<GlobalLockAcquisitionTracker>(); - -bool GlobalLockAcquisitionTracker::getGlobalWriteLocked() const { - return _globalLockMode & ((1 << MODE_IX) | (1 << MODE_X)); -} - -bool GlobalLockAcquisitionTracker::getGlobalSharedLockTaken() const { - return _globalLockMode & (1 << MODE_S); -} - -bool GlobalLockAcquisitionTracker::getGlobalLockTaken() const { - return _globalLockMode & ((1 << MODE_IX) | (1 << MODE_X) | (1 << MODE_IS) | (1 << MODE_S)); -} - -void GlobalLockAcquisitionTracker::setGlobalLockModeBit(LockMode mode) { - _globalLockMode |= (1 << mode); -} -} // namespace mongo diff --git a/src/mongo/db/concurrency/global_lock_acquisition_tracker.h b/src/mongo/db/concurrency/global_lock_acquisition_tracker.h deleted file mode 100644 index dae19eb537f..00000000000 --- a/src/mongo/db/concurrency/global_lock_acquisition_tracker.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include "mongo/db/operation_context.h" - -namespace mongo { - -/** - * GlobalLockAcquisitionTracker keeps track of the global lock modes acquired during the - * operation's lifetime. This class is used to track if we ever did a transaction with the - * intent to do a write, so that we can enforce write concern on noop writes. Also, used - * during step down to kill all user operations except those that acquired global lock in - * IS mode. - */ -class GlobalLockAcquisitionTracker { -public: - static const OperationContext::Decoration<GlobalLockAcquisitionTracker> get; - - // Decoration requires a default constructor. - GlobalLockAcquisitionTracker() = default; - - /** - * Returns whether we have ever taken a global lock in X or IX mode in this operation. - */ - bool getGlobalWriteLocked() const; - - /** - * Returns whether we have ever taken a global lock in S mode in this operation. - */ - bool getGlobalSharedLockTaken() const; - - /** - * Returns whether we have ever taken a global lock in this operation. - */ - bool getGlobalLockTaken() const; - - /** - * Sets the mode bit in _globalLockMode. Once a mode bit is set, we won't clear it. - */ - void setGlobalLockModeBit(LockMode mode); - -private: - // keeps track of the global lock modes acquired for this operation. - unsigned char _globalLockMode = (1 << MODE_NONE); -}; - -} // namespace mongo diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp index 225e563fe6e..1450ba98397 100644 --- a/src/mongo/db/concurrency/lock_state.cpp +++ b/src/mongo/db/concurrency/lock_state.cpp @@ -615,6 +615,37 @@ bool LockerImpl::isCollectionLockedForMode(const NamespaceString& nss, LockMode return false; } +bool LockerImpl::wasGlobalWriteLockTaken() const { + return _globalLockMode.load() & ((1 << MODE_IX) | (1 << MODE_X)); +} + +bool LockerImpl::wasGlobalSharedLockTaken() const { + return _globalLockMode.load() & (1 << MODE_S); +} + +bool LockerImpl::wasGlobalLockTaken() const { + return _globalLockMode.load() & + ((1 << MODE_IX) | (1 << MODE_X) | (1 << MODE_IS) | (1 << MODE_S)); +} + +void LockerImpl::setGlobalLockModeBit(LockMode mode) { + const unsigned char bit = 1 << mode; + unsigned char actual = _globalLockMode.load(); + unsigned char expected; + + // This is monotonic (once "bit" is set it is never unset) so we can optimistically try to set + // it, retrying if another thread modifies _globalLockMode between the load and the swap. If + // another thread sets "bit" while we are trying to, then we're done. + do { + if (actual & bit) { + return; + } + + expected = actual; + actual = _globalLockMode.compareAndSwap(expected, actual | bit); + } while (actual != expected); +} + ResourceId LockerImpl::getWaitingResource() const { scoped_spinlock scopedLock(_lock); diff --git a/src/mongo/db/concurrency/lock_state.h b/src/mongo/db/concurrency/lock_state.h index f7659dc9b4b..936e5585c64 100644 --- a/src/mongo/db/concurrency/lock_state.h +++ b/src/mongo/db/concurrency/lock_state.h @@ -158,6 +158,14 @@ public: return _wuowNestingLevel > 0; } + bool wasGlobalWriteLockTaken() const override; + + bool wasGlobalSharedLockTaken() const override; + + bool wasGlobalLockTaken() const override; + + void setGlobalLockModeBit(LockMode mode) override; + /** * Requests a lock for resource 'resId' with mode 'mode'. An OperationContext 'opCtx' must be * provided to interrupt waiting on the locker condition variable that indicates status of @@ -348,6 +356,9 @@ private: // available. Note this will be ineffective if uninterruptible lock guard is set. boost::optional<Milliseconds> _maxLockTimeout; + // Tracks the global lock modes ever acquired in this Locker's life. + AtomicWord<unsigned char> _globalLockMode; + ////////////////////////////////////////////////////////////////////////////////////////// // // Methods merged from LockState, which should eventually be removed or changed to methods diff --git a/src/mongo/db/concurrency/locker.h b/src/mongo/db/concurrency/locker.h index 24f9dfbd532..69a048e123f 100644 --- a/src/mongo/db/concurrency/locker.h +++ b/src/mongo/db/concurrency/locker.h @@ -235,6 +235,26 @@ public: virtual bool inAWriteUnitOfWork() const = 0; /** + * Returns whether we have ever taken a global lock in X or IX mode in this operation. + */ + virtual bool wasGlobalWriteLockTaken() const = 0; + + /** + * Returns whether we have ever taken a global lock in S mode in this operation. + */ + virtual bool wasGlobalSharedLockTaken() const = 0; + + /** + * Returns whether we have ever taken a global lock in this operation. + */ + virtual bool wasGlobalLockTaken() const = 0; + + /** + * Sets the mode bit in _globalLockMode. Once a mode bit is set, we won't clear it. + */ + virtual void setGlobalLockModeBit(LockMode mode) = 0; + + /** * Acquires lock on the specified resource in the specified mode and returns the outcome * of the operation. See the details for LockResult for more information on what the * different results mean. diff --git a/src/mongo/db/concurrency/locker_noop.h b/src/mongo/db/concurrency/locker_noop.h index 5e53bd6f6de..b06917043ed 100644 --- a/src/mongo/db/concurrency/locker_noop.h +++ b/src/mongo/db/concurrency/locker_noop.h @@ -118,6 +118,20 @@ public: return false; } + virtual bool wasGlobalWriteLockTaken() const { + return false; + } + + virtual bool wasGlobalSharedLockTaken() const { + return false; + } + + virtual bool wasGlobalLockTaken() const { + return false; + } + + virtual void setGlobalLockModeBit(LockMode mode) {} + virtual LockResult lockRSTLBegin(OperationContext* opCtx, LockMode mode) { MONGO_UNREACHABLE; } diff --git a/src/mongo/db/curop.cpp b/src/mongo/db/curop.cpp index cb18faa1337..bd5a1687bf6 100644 --- a/src/mongo/db/curop.cpp +++ b/src/mongo/db/curop.cpp @@ -43,7 +43,6 @@ #include "mongo/db/commands.h" #include "mongo/db/commands/server_status_metric.h" #include "mongo/db/concurrency/d_concurrency.h" -#include "mongo/db/concurrency/global_lock_acquisition_tracker.h" #include "mongo/db/concurrency/locker.h" #include "mongo/db/json.h" #include "mongo/db/query/getmore_request.h" @@ -406,9 +405,7 @@ bool CurOp::completeAndLogOperation(OperationContext* opCtx, if (shouldLogOp || (shouldSample && _debug.executionTimeMicros > slowMs * 1000LL)) { auto lockerInfo = opCtx->lockState()->getLockerInfo(_lockStatsBase); - const GlobalLockAcquisitionTracker& globalLockTracker = - GlobalLockAcquisitionTracker::get(opCtx); - if (_debug.storageStats == nullptr && globalLockTracker.getGlobalLockTaken() && + if (_debug.storageStats == nullptr && opCtx->lockState()->wasGlobalLockTaken() && opCtx->getServiceContext()->getStorageEngine()) { // Do not fetch operation statistics again if we have already got them (for instance, // as a part of stashing the transaction). diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index 674e244acd8..e5bd72235ba 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -46,7 +46,6 @@ #include "mongo/db/commands.h" #include "mongo/db/commands/test_commands_enabled.h" #include "mongo/db/concurrency/d_concurrency.h" -#include "mongo/db/concurrency/global_lock_acquisition_tracker.h" #include "mongo/db/concurrency/replication_state_transition_lock_guard.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/index_builds_coordinator.h" @@ -1808,10 +1807,8 @@ void ReplicationCoordinatorImpl::_killUserOperationsOnStepDown( // Don't kill the stepdown thread. if (toKill && !toKill->isKillPending() && toKill->getOpID() != stepDownOpCtx->getOpID()) { - const GlobalLockAcquisitionTracker& globalLockTracker = - GlobalLockAcquisitionTracker::get(toKill); - if (globalLockTracker.getGlobalWriteLocked() || - globalLockTracker.getGlobalSharedLockTaken()) { + auto locker = toKill->lockState(); + if (locker->wasGlobalWriteLockTaken() || locker->wasGlobalSharedLockTaken()) { serviceCtx->killOperation(lk, toKill, ErrorCodes::InterruptedDueToStepDown); userOpsKilled.increment(); } else { diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp index a3077e08a38..ee195f4ad49 100644 --- a/src/mongo/db/service_entry_point_common.cpp +++ b/src/mongo/db/service_entry_point_common.cpp @@ -44,7 +44,6 @@ #include "mongo/db/commands.h" #include "mongo/db/commands/test_commands_enabled.h" #include "mongo/db/commands/txn_cmds_gen.h" -#include "mongo/db/concurrency/global_lock_acquisition_tracker.h" #include "mongo/db/curop.h" #include "mongo/db/curop_failpoint_helpers.h" #include "mongo/db/curop_metrics.h" diff --git a/src/mongo/db/service_entry_point_mongod.cpp b/src/mongo/db/service_entry_point_mongod.cpp index 533db3576e8..d67b6fee50a 100644 --- a/src/mongo/db/service_entry_point_mongod.cpp +++ b/src/mongo/db/service_entry_point_mongod.cpp @@ -34,7 +34,6 @@ #include "mongo/db/service_entry_point_mongod.h" #include "mongo/db/commands/fsync_locked.h" -#include "mongo/db/concurrency/global_lock_acquisition_tracker.h" #include "mongo/db/curop.h" #include "mongo/db/read_concern.h" #include "mongo/db/repl/repl_client_info.h" @@ -106,8 +105,7 @@ public: auto lastOpAfterRun = repl::ReplClientInfo::forClient(opCtx->getClient()).getLastOp(); // Ensures that if we tried to do a write, we wait for write concern, even if that write was // a noop. - if ((lastOpAfterRun == lastOpBeforeRun) && - GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()) { + if ((lastOpAfterRun == lastOpBeforeRun) && opCtx->lockState()->wasGlobalWriteLockTaken()) { repl::ReplClientInfo::forClient(opCtx->getClient()).setLastOpToSystemLastOpTime(opCtx); lastOpAfterRun = repl::ReplClientInfo::forClient(opCtx->getClient()).getLastOp(); } |