summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorA. Jesse Jiryu Davis <jesse@mongodb.com>2019-03-25 14:47:29 -0400
committerA. Jesse Jiryu Davis <jesse@mongodb.com>2019-03-28 11:34:55 -0400
commitd99db775dbf73e27bd20e402f26f068dc199203d (patch)
tree6ed4928384ae0b1fce3165b58e9a2e87cfd2dfc9 /src/mongo/db
parentf922827d45ce752e148185dfa3a785f7c9cf29fd (diff)
downloadmongo-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/SConscript1
-rw-r--r--src/mongo/db/concurrency/d_concurrency.cpp3
-rw-r--r--src/mongo/db/concurrency/d_concurrency.h6
-rw-r--r--src/mongo/db/concurrency/d_concurrency_test.cpp65
-rw-r--r--src/mongo/db/concurrency/global_lock_acquisition_tracker.cpp54
-rw-r--r--src/mongo/db/concurrency/global_lock_acquisition_tracker.h75
-rw-r--r--src/mongo/db/concurrency/lock_state.cpp31
-rw-r--r--src/mongo/db/concurrency/lock_state.h11
-rw-r--r--src/mongo/db/concurrency/locker.h20
-rw-r--r--src/mongo/db/concurrency/locker_noop.h14
-rw-r--r--src/mongo/db/curop.cpp5
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.cpp7
-rw-r--r--src/mongo/db/service_entry_point_common.cpp1
-rw-r--r--src/mongo/db/service_entry_point_mongod.cpp4
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();
}