summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Lucas <bruce.lucas@mongodb.com>2018-01-31 08:44:19 -0500
committerLouis Williams <louis.williams@mongodb.com>2018-03-01 13:18:58 -0500
commite0e83bfcb1757bdb7e1ba96df705b300732f9b72 (patch)
tree3eb32c3602cc0483807b97f71bec0a1c1e59f308
parent374e33da6bc28c21c9842802752e89841bfb3fa2 (diff)
downloadmongo-e0e83bfcb1757bdb7e1ba96df705b300732f9b72.tar.gz
SERVER-33233 Don't stall ftdc due to running out of tickets
(cherry picked from commit 5436c851b8322a0cb18611be0672f6a76d6e2f38)
-rw-r--r--src/mongo/db/concurrency/d_concurrency_test.cpp23
-rw-r--r--src/mongo/db/concurrency/lock_state.cpp4
-rw-r--r--src/mongo/db/concurrency/locker.h14
-rw-r--r--src/mongo/db/ftdc/collector.cpp1
4 files changed, 38 insertions, 4 deletions
diff --git a/src/mongo/db/concurrency/d_concurrency_test.cpp b/src/mongo/db/concurrency/d_concurrency_test.cpp
index 327f1efddc5..799aae8a7e3 100644
--- a/src/mongo/db/concurrency/d_concurrency_test.cpp
+++ b/src/mongo/db/concurrency/d_concurrency_test.cpp
@@ -81,12 +81,13 @@ private:
class UseGlobalThrottling {
public:
explicit UseGlobalThrottling(OperationContext* opCtx, int numTickets)
- : _opCtx(opCtx), _holder(1) {
+ : _opCtx(opCtx), _holder(numTickets) {
_opCtx->lockState()->setGlobalThrottling(&_holder, &_holder);
}
- ~UseGlobalThrottling() {
+ ~UseGlobalThrottling() noexcept(false) {
// Reset the global setting as we're about to destroy the ticket holder.
_opCtx->lockState()->setGlobalThrottling(nullptr, nullptr);
+ ASSERT_EQ(_holder.used(), 0);
}
private:
@@ -811,6 +812,24 @@ TEST(DConcurrency, Throttling) {
ASSERT(!overlongWait);
}
+TEST(DConcurrency, NoThrottlingWhenNotAcquiringTickets) {
+ auto clientOpctxPairs = makeKClientsWithLockers<DefaultLockerImpl>(2);
+ auto opctx1 = clientOpctxPairs[0].second.get();
+ auto opctx2 = clientOpctxPairs[1].second.get();
+ // Limit the locker to 1 ticket at a time.
+ UseGlobalThrottling throttle(opctx1, 1);
+
+ // Prevent the enforcement of ticket throttling.
+ opctx1->lockState()->setShouldAcquireTicket(false);
+
+ // Both locks should be acquired immediately because there is no throttling.
+ Lock::GlobalRead R1(opctx1->lockState(), 0);
+ ASSERT(R1.isLocked());
+
+ Lock::GlobalRead R2(opctx2->lockState(), 0);
+ ASSERT(R2.isLocked());
+}
+
TEST(DConcurrency, CompatibleFirstWithSXIS) {
auto clientOpctxPairs = makeKClientsWithLockers<DefaultLockerImpl>(3);
auto opctx1 = clientOpctxPairs[0].second.get();
diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp
index bf48ec3ba51..3625cef24f7 100644
--- a/src/mongo/db/concurrency/lock_state.cpp
+++ b/src/mongo/db/concurrency/lock_state.cpp
@@ -311,7 +311,7 @@ LockResult LockerImpl<IsForMMAPV1>::_lockGlobalBegin(LockMode mode, Milliseconds
dassert(isLocked() == (_modeForTicket != MODE_NONE));
if (_modeForTicket == MODE_NONE) {
const bool reader = isSharedLockMode(mode);
- auto holder = ticketHolders[mode];
+ auto holder = shouldAcquireTicket() ? ticketHolders[mode] : nullptr;
if (holder) {
_clientState.store(reader ? kQueuedReader : kQueuedWriter);
if (timeout == Milliseconds::max()) {
@@ -810,7 +810,7 @@ bool LockerImpl<IsForMMAPV1>::_unlockImpl(LockRequestsMap::Iterator* it) {
if (globalLockManager.unlock(it->objAddr())) {
if (it->key() == resourceIdGlobal) {
invariant(_modeForTicket != MODE_NONE);
- auto holder = ticketHolders[_modeForTicket];
+ auto holder = shouldAcquireTicket() ? ticketHolders[_modeForTicket] : nullptr;
_modeForTicket = MODE_NONE;
if (holder) {
holder->release();
diff --git a/src/mongo/db/concurrency/locker.h b/src/mongo/db/concurrency/locker.h
index 37af569124f..c1443865326 100644
--- a/src/mongo/db/concurrency/locker.h
+++ b/src/mongo/db/concurrency/locker.h
@@ -334,11 +334,25 @@ public:
return _shouldConflictWithSecondaryBatchApplication;
}
+ /**
+ * If set to false, this opts out of the ticket mechanism. This should be used sparingly
+ * for special purpose threads, such as FTDC.
+ */
+ void setShouldAcquireTicket(bool newValue) {
+ invariant(!isLocked());
+ _shouldAcquireTicket = newValue;
+ }
+ bool shouldAcquireTicket() const {
+ return _shouldAcquireTicket;
+ }
+
+
protected:
Locker() {}
private:
bool _shouldConflictWithSecondaryBatchApplication = true;
+ bool _shouldAcquireTicket = true;
};
} // namespace mongo
diff --git a/src/mongo/db/ftdc/collector.cpp b/src/mongo/db/ftdc/collector.cpp
index 611f12dff5a..7c35fb12bb6 100644
--- a/src/mongo/db/ftdc/collector.cpp
+++ b/src/mongo/db/ftdc/collector.cpp
@@ -67,6 +67,7 @@ std::tuple<BSONObj, Date_t> FTDCCollectorCollection::collect(Client* client) {
// batches that are taking a long time.
auto txn = client->makeOperationContext();
txn->lockState()->setShouldConflictWithSecondaryBatchApplication(false);
+ txn->lockState()->setShouldAcquireTicket(false);
for (auto& collector : _collectors) {
BSONObjBuilder subObjBuilder(builder.subobjStart(collector->name()));