diff options
author | Judah Schvimer <judah@mongodb.com> | 2019-04-17 14:26:44 -0400 |
---|---|---|
committer | Judah Schvimer <judah@mongodb.com> | 2019-04-17 14:26:44 -0400 |
commit | 7a9f240519c55cc6af45e4783bfd54d81a79d1e0 (patch) | |
tree | b9e3f0c8beb0c9557e94661092ad6244fa782a32 /src/mongo/db/concurrency | |
parent | d7fb557f6fc6d486fa7107a8f64342caf552eeb4 (diff) | |
download | mongo-7a9f240519c55cc6af45e4783bfd54d81a79d1e0.tar.gz |
SERVER-40069 Fix global lock tracking for txns
Includes SERVER-40084, stores global lock acquisition flag in an
atomic.
Diffstat (limited to 'src/mongo/db/concurrency')
-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 | 83 | ||||
-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 | 20 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_state.h | 15 | ||||
-rw-r--r-- | src/mongo/db/concurrency/locker.h | 23 | ||||
-rw-r--r-- | src/mongo/db/concurrency/locker_noop.h | 14 |
10 files changed, 116 insertions, 178 deletions
diff --git a/src/mongo/db/concurrency/SConscript b/src/mongo/db/concurrency/SConscript index cd43fc4fb44..f8e5c142eec 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 ffc24144b7f..0debd7b7ce8 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" @@ -218,7 +217,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()->setGlobalLockTakenInMode(lockMode); } void Lock::GlobalLock::_unlock() { diff --git a/src/mongo/db/concurrency/d_concurrency.h b/src/mongo/db/concurrency/d_concurrency.h index 82823093d5f..7300824373c 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::setGlobalLockTakenInMode(). 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::setGlobalLockTakenInMode(). */ 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 9043e00e4b7..7e2b70472bd 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()->wasGlobalLockTakenForWrite()); { 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()->wasGlobalLockTakenForWrite()); } TEST_F(DConcurrencyTestFixture, GlobalLockIXSetsGlobalWriteLockedOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenForWrite()); { 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()->wasGlobalLockTakenForWrite()); } TEST_F(DConcurrencyTestFixture, GlobalLockSDoesNotSetGlobalWriteLockedOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenForWrite()); { 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()->wasGlobalLockTakenForWrite()); } TEST_F(DConcurrencyTestFixture, GlobalLockISDoesNotSetGlobalWriteLockedOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenForWrite()); { 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()->wasGlobalLockTakenForWrite()); } TEST_F(DConcurrencyTestFixture, DBLockXSetsGlobalWriteLockedOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenForWrite()); { Lock::DBLock dbWrite(opCtx, "db", MODE_X); } - ASSERT_TRUE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_TRUE(opCtx->lockState()->wasGlobalLockTakenForWrite()); } TEST_F(DConcurrencyTestFixture, DBLockSDoesNotSetGlobalWriteLockedOnOperationContext) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenForWrite()); { Lock::DBLock dbRead(opCtx, "db", MODE_S); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenForWrite()); } 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()->wasGlobalLockTakenForWrite()); { ASSERT_THROWS_CODE( Lock::GlobalLock( @@ -550,92 +549,92 @@ TEST_F(DConcurrencyTestFixture, GlobalLockXDoesNotSetGlobalWriteLockedWhenLockAc AssertionException, ErrorCodes::LockTimeout); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalWriteLocked()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenForWrite()); } -TEST_F(DConcurrencyTestFixture, GlobalLockSSetsGlobalSharedLockTakenOnOperationContext) { +TEST_F(DConcurrencyTestFixture, GlobalLockSSetsGlobalLockTakenInModeConflictingWithWrites) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); { 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()->wasGlobalLockTakenInModeConflictingWithWrites()); } -TEST_F(DConcurrencyTestFixture, GlobalLockISDoesNotSetGlobalSharedLockTakenOnOperationContext) { +TEST_F(DConcurrencyTestFixture, GlobalLockISDoesNotSetGlobalLockTakenInModeConflictingWithWrites) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); { 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()->wasGlobalLockTakenInModeConflictingWithWrites()); } -TEST_F(DConcurrencyTestFixture, GlobalLockIXDoesNotSetGlobalSharedLockTakenOnOperationContext) { +TEST_F(DConcurrencyTestFixture, GlobalLockIXSetsGlobalLockTakenInModeConflictingWithWrites) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); { Lock::GlobalLock globalRead(opCtx, MODE_IX, Date_t::now(), Lock::InterruptBehavior::kThrow); ASSERT(globalRead.isLocked()); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_TRUE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); } -TEST_F(DConcurrencyTestFixture, GlobalLockXDoesNotSetGlobalSharedLockTakenOnOperationContext) { +TEST_F(DConcurrencyTestFixture, GlobalLockXSetsGlobalLockTakenInModeConflictingWithWrites) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); { Lock::GlobalLock globalRead(opCtx, MODE_X, Date_t::now(), Lock::InterruptBehavior::kThrow); ASSERT(globalRead.isLocked()); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_TRUE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); } -TEST_F(DConcurrencyTestFixture, DBLockSDoesNotSetGlobalSharedLockTakeOnOperationContext) { +TEST_F(DConcurrencyTestFixture, DBLockSDoesNotSetGlobalLockTakenInModeConflictingWithWrites) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); { Lock::DBLock dbWrite(opCtx, "db", MODE_S); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); } -TEST_F(DConcurrencyTestFixture, DBLockISDoesNotSetGlobalSharedLockTakeOnOperationContext) { +TEST_F(DConcurrencyTestFixture, DBLockISDoesNotSetGlobalLockTakenInModeConflictingWithWrites) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); { Lock::DBLock dbWrite(opCtx, "db", MODE_IS); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); } -TEST_F(DConcurrencyTestFixture, DBLockIXDoesNotSetGlobalSharedLockTakeOnOperationContext) { +TEST_F(DConcurrencyTestFixture, DBLockIXSetsGlobalLockTakenInModeConflictingWithWrites) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); { Lock::DBLock dbWrite(opCtx, "db", MODE_IX); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_TRUE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); } -TEST_F(DConcurrencyTestFixture, DBLockXDoesNotSetGlobalSharedLockTakeOnOperationContext) { +TEST_F(DConcurrencyTestFixture, DBLockXSetsGlobalLockTakenInModeConflictingWithWrites) { auto clients = makeKClientsWithLockers(1); auto opCtx = clients[0].second.get(); - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_FALSE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); { Lock::DBLock dbRead(opCtx, "db", MODE_X); } - ASSERT_FALSE(GlobalLockAcquisitionTracker::get(opCtx).getGlobalSharedLockTaken()); + ASSERT_TRUE(opCtx->lockState()->wasGlobalLockTakenInModeConflictingWithWrites()); } TEST_F(DConcurrencyTestFixture, - GlobalLockSDoesNotSetGlobalSharedLockTakenWhenLockAcquisitionTimesOut) { + GlobalLockSDoesNotSetGlobalLockTakenInModeConflictingWithWritesWhenLockAcquisitionTimesOut) { auto clients = makeKClientsWithLockers(2); // Take a global lock so that the next one times out. @@ -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()->wasGlobalLockTakenInModeConflictingWithWrites()); { 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()->wasGlobalLockTakenInModeConflictingWithWrites()); } 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 e5b095fdb66..617eb26f22f 100644 --- a/src/mongo/db/concurrency/lock_state.cpp +++ b/src/mongo/db/concurrency/lock_state.cpp @@ -588,6 +588,26 @@ bool LockerImpl::isCollectionLockedForMode(const NamespaceString& nss, LockMode return false; } +bool LockerImpl::wasGlobalLockTakenForWrite() const { + return _globalLockMode & ((1 << MODE_IX) | (1 << MODE_X)); +} + +bool LockerImpl::wasGlobalLockTakenInModeConflictingWithWrites() const { + return _wasGlobalLockTakenInModeConflictingWithWrites.load(); +} + +bool LockerImpl::wasGlobalLockTaken() const { + return _globalLockMode; +} + +void LockerImpl::setGlobalLockTakenInMode(LockMode mode) { + _globalLockMode |= (1 << mode); + + if (mode == MODE_IX || mode == MODE_X || mode == MODE_S) { + _wasGlobalLockTakenInModeConflictingWithWrites.store(true); + } +} + 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 4a0654cc2b8..0b9741633d5 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 wasGlobalLockTakenForWrite() const override; + + bool wasGlobalLockTakenInModeConflictingWithWrites() const override; + + bool wasGlobalLockTaken() const override; + + void setGlobalLockTakenInMode(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 @@ -357,6 +365,13 @@ private: // A structure for accumulating time spent getting flow control tickets. FlowControlTicketholder::CurOp _flowControlStats; + // Tracks the global lock modes ever acquired in this Locker's life. This value should only ever + // be accessed from the thread that owns the Locker. + unsigned char _globalLockMode = (1 << MODE_NONE); + + // Tracks whether this operation should be killed on step down. + AtomicWord<bool> _wasGlobalLockTakenInModeConflictingWithWrites{false}; + ////////////////////////////////////////////////////////////////////////////////////////// // // 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 8585cf0bb1c..61a0a950b3c 100644 --- a/src/mongo/db/concurrency/locker.h +++ b/src/mongo/db/concurrency/locker.h @@ -236,6 +236,29 @@ public: virtual bool inAWriteUnitOfWork() const = 0; /** + * Returns whether we have ever taken a global lock in X or IX mode in this operation. + * Should only be called on the thread owning the locker. + */ + virtual bool wasGlobalLockTakenForWrite() const = 0; + + /** + * Returns whether we have ever taken a global lock in S, X, or IX mode in this operation. + */ + virtual bool wasGlobalLockTakenInModeConflictingWithWrites() const = 0; + + /** + * Returns whether we have ever taken a global lock in this operation. + * Should only be called on the thread owning the locker. + */ + virtual bool wasGlobalLockTaken() const = 0; + + /** + * Sets the mode bit in _globalLockMode. Once a mode bit is set, we won't clear it. Also sets + * _wasGlobalLockTakenInModeConflictingWithWrites to true if the mode is S, X, or IX. + */ + virtual void setGlobalLockTakenInMode(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..886510cb16c 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 wasGlobalLockTakenForWrite() const { + return false; + } + + virtual bool wasGlobalLockTakenInModeConflictingWithWrites() const { + return false; + } + + virtual bool wasGlobalLockTaken() const { + return false; + } + + virtual void setGlobalLockTakenInMode(LockMode mode) {} + virtual LockResult lockRSTLBegin(OperationContext* opCtx, LockMode mode) { MONGO_UNREACHABLE; } |