diff options
author | Bruce Lucas <bruce.lucas@mongodb.com> | 2018-01-31 08:44:19 -0500 |
---|---|---|
committer | Louis Williams <louis.williams@mongodb.com> | 2018-02-20 12:44:06 -0500 |
commit | 5436c851b8322a0cb18611be0672f6a76d6e2f38 (patch) | |
tree | 927732ab12140ea0c4cb4c482ba1a363118f2cee /src/mongo | |
parent | 13b35bc5cfb20be89eb46dc50208d344caf305bb (diff) | |
download | mongo-5436c851b8322a0cb18611be0672f6a76d6e2f38.tar.gz |
SERVER-33233 Don't stall ftdc due to running out of tickets
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/concurrency/d_concurrency_test.cpp | 23 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_state.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/concurrency/locker.h | 14 | ||||
-rw-r--r-- | src/mongo/db/ftdc/collector.cpp | 1 |
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 e2e881ef866..67b903c51af 100644 --- a/src/mongo/db/concurrency/d_concurrency_test.cpp +++ b/src/mongo/db/concurrency/d_concurrency_test.cpp @@ -62,12 +62,13 @@ const int kMinPerfMillis = 30; // min duration for reliable timing 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: @@ -1008,6 +1009,24 @@ TEST_F(DConcurrencyTestFixture, Throttling) { ASSERT(!overlongWait); } +TEST_F(DConcurrencyTestFixture, 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, Date_t::now()); + ASSERT(R1.isLocked()); + + Lock::GlobalRead R2(opctx2, Date_t::now()); + ASSERT(R2.isLocked()); +} + TEST_F(DConcurrencyTestFixture, DBLockTimeout) { auto clientOpctxPairs = makeKClientsWithLockers<DefaultLockerImpl>(2); 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 34645189977..4efdb1c49b6 100644 --- a/src/mongo/db/concurrency/lock_state.cpp +++ b/src/mongo/db/concurrency/lock_state.cpp @@ -301,7 +301,7 @@ LockResult LockerImpl<IsForMMAPV1>::_lockGlobalBegin(LockMode mode, Date_t deadl 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 (deadline == Date_t::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 3e70d000fe8..ff133800115 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 78e4f0de60a..c1e0c47158d 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 opCtx = client->makeOperationContext(); opCtx->lockState()->setShouldConflictWithSecondaryBatchApplication(false); + opCtx->lockState()->setShouldAcquireTicket(false); for (auto& collector : _collectors) { BSONObjBuilder subObjBuilder(builder.subobjStart(collector->name())); |