summaryrefslogtreecommitdiff
path: root/src/mongo/db/concurrency
diff options
context:
space:
mode:
authorJudah Schvimer <judah@mongodb.com>2019-04-17 14:26:44 -0400
committerJudah Schvimer <judah@mongodb.com>2019-04-17 14:26:44 -0400
commit7a9f240519c55cc6af45e4783bfd54d81a79d1e0 (patch)
treeb9e3f0c8beb0c9557e94661092ad6244fa782a32 /src/mongo/db/concurrency
parentd7fb557f6fc6d486fa7107a8f64342caf552eeb4 (diff)
downloadmongo-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/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.cpp83
-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.cpp20
-rw-r--r--src/mongo/db/concurrency/lock_state.h15
-rw-r--r--src/mongo/db/concurrency/locker.h23
-rw-r--r--src/mongo/db/concurrency/locker_noop.h14
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;
}