diff options
author | Jordi Olivares Provencio <jordi.olivares-provencio@mongodb.com> | 2022-05-18 10:07:43 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-05-18 12:27:07 +0000 |
commit | 25c66e358f9701b127b7b7f08a1246b424fd0067 (patch) | |
tree | daceab5b2154f52b555854264a538700c1e464dc | |
parent | 6d7e4ea84316181578b9e78981f4adc1b0e9838d (diff) | |
download | mongo-25c66e358f9701b127b7b7f08a1246b424fd0067.tar.gz |
SERVER-66249 Refactor Tickets to be RAII and auto releasable
-rw-r--r-- | src/mongo/db/concurrency/lock_state.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_state.h | 2 | ||||
-rw-r--r-- | src/mongo/dbtests/threadedtests.cpp | 1 | ||||
-rw-r--r-- | src/mongo/util/concurrency/ticket.h | 90 | ||||
-rw-r--r-- | src/mongo/util/concurrency/ticketholder.cpp | 42 | ||||
-rw-r--r-- | src/mongo/util/concurrency/ticketholder.h | 93 | ||||
-rw-r--r-- | src/mongo/util/concurrency/ticketholder_bm.cpp | 31 | ||||
-rw-r--r-- | src/mongo/util/concurrency/ticketholder_test.cpp | 99 |
8 files changed, 135 insertions, 227 deletions
diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp index 0c050d528c7..681043076dd 100644 --- a/src/mongo/db/concurrency/lock_state.cpp +++ b/src/mongo/db/concurrency/lock_state.cpp @@ -1076,10 +1076,6 @@ void LockerImpl::releaseTicket() { } void LockerImpl::_releaseTicket() { - auto holder = shouldAcquireTicket() ? _ticketHolders->getTicketHolder(_modeForTicket) : nullptr; - if (holder) { - holder->release(&_admCtx, std::move(*_ticket)); - } _ticket.reset(); _clientState.store(kInactive); } diff --git a/src/mongo/db/concurrency/lock_state.h b/src/mongo/db/concurrency/lock_state.h index a6677385e2f..af95dbe4d79 100644 --- a/src/mongo/db/concurrency/lock_state.h +++ b/src/mongo/db/concurrency/lock_state.h @@ -39,7 +39,7 @@ #include "mongo/platform/atomic_word.h" #include "mongo/util/concurrency/admission_context.h" #include "mongo/util/concurrency/spin_lock.h" -#include "mongo/util/concurrency/ticket.h" +#include "mongo/util/concurrency/ticketholder.h" namespace mongo { diff --git a/src/mongo/dbtests/threadedtests.cpp b/src/mongo/dbtests/threadedtests.cpp index e5fe2ec48df..2d0449856ab 100644 --- a/src/mongo/dbtests/threadedtests.cpp +++ b/src/mongo/dbtests/threadedtests.cpp @@ -274,7 +274,6 @@ private: AdmissionContext admCtx; auto ticket = _tickets->waitForTicket( opCtx.get(), &admCtx, TicketHolder::WaitMode::kUninterruptible); - TicketHolderReleaser whenDone(std::move(ticket), &admCtx, _tickets.get()); _hotel.checkIn(); diff --git a/src/mongo/util/concurrency/ticket.h b/src/mongo/util/concurrency/ticket.h deleted file mode 100644 index 3f10db3e6a1..00000000000 --- a/src/mongo/util/concurrency/ticket.h +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Copyright (C) 2022-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 <boost/optional.hpp> - -#include "mongo/util/assert_util_core.h" -#include "mongo/util/tick_source.h" - -namespace mongo { - -class SemaphoreTicketHolder; -class FifoTicketHolder; - -/** - * Move-only token that gets generated when a ticket is acquired and has to be marked invalid when - * it is released. Only TicketHolders can create and release valid Tickets. - */ -class Ticket { - friend class SemaphoreTicketHolder; - friend class FifoTicketHolder; - -public: - Ticket(Ticket&& t) : _valid(t._valid) { - t._valid = false; - } - - Ticket& operator=(Ticket&& t) { - invariant(!_valid); - _valid = t._valid; - t._valid = false; - return *this; - }; - - ~Ticket() { - // A Ticket can't be destroyed unless it's been released. - invariant(!_valid); - } - - /** - * Returns whether or not a ticket is held. The default constructor creates an invalid Ticket - * and the move operators mark the source object as invalid. - */ - bool valid() { - return _valid; - } - -private: - Ticket() : _valid(true) {} - - void release() { - invariant(_valid); - _valid = false; - } - - // No copy constructors. - Ticket(const Ticket&) = delete; - Ticket& operator=(const Ticket&) = delete; - - // Whether this represents a ticket being held. - bool _valid; -}; - -} // namespace mongo diff --git a/src/mongo/util/concurrency/ticketholder.cpp b/src/mongo/util/concurrency/ticketholder.cpp index 392f7146c3a..82fe813b516 100644 --- a/src/mongo/util/concurrency/ticketholder.cpp +++ b/src/mongo/util/concurrency/ticketholder.cpp @@ -32,7 +32,6 @@ #include "mongo/db/service_context.h" #include "mongo/util/concurrency/admission_context.h" -#include "mongo/util/concurrency/ticket.h" #include "mongo/util/concurrency/ticketholder.h" #include <iostream> @@ -93,7 +92,7 @@ boost::optional<Ticket> SemaphoreTicketHolder::tryAcquire(AdmissionContext* admC if (errno != EINTR) failWithErrno(errno); } - return Ticket{}; + return Ticket{this, admCtx}; } Ticket SemaphoreTicketHolder::waitForTicket(OperationContext* opCtx, @@ -111,7 +110,7 @@ boost::optional<Ticket> SemaphoreTicketHolder::waitForTicketUntil(OperationConte // Attempt to get a ticket without waiting in order to avoid expensive time calculations. if (sem_trywait(&_sem) == 0) { - return Ticket{}; + return Ticket{this, admCtx}; } const Milliseconds intervalMs(500); @@ -141,12 +140,11 @@ boost::optional<Ticket> SemaphoreTicketHolder::waitForTicketUntil(OperationConte if (waitMode == WaitMode::kInterruptible) opCtx->checkForInterrupt(); } - return Ticket{}; + return Ticket{this, admCtx}; } -void SemaphoreTicketHolder::release(AdmissionContext* admCtx, Ticket&& ticket) { +void SemaphoreTicketHolder::_release(AdmissionContext* admCtx) noexcept { check(sem_post(&_sem)); - ticket.release(); } Status SemaphoreTicketHolder::resize(int newSize) { @@ -163,14 +161,13 @@ Status SemaphoreTicketHolder::resize(int newSize) { AdmissionContext admCtx; while (_outof.load() < newSize) { - Ticket ticket; - release(&admCtx, std::move(ticket)); + _release(&admCtx); _outof.fetchAndAdd(1); } while (_outof.load() > newSize) { auto ticket = waitForTicket(nullptr, &admCtx, WaitMode::kUninterruptible); - ticket.release(); + ticket.discard(); _outof.subtractAndFetch(1); } @@ -203,7 +200,7 @@ boost::optional<Ticket> SemaphoreTicketHolder::tryAcquire(AdmissionContext* admC if (!_tryAcquire()) { return boost::none; } - return Ticket{}; + return Ticket{this, admCtx}; } Ticket SemaphoreTicketHolder::waitForTicket(OperationContext* opCtx, @@ -216,7 +213,7 @@ Ticket SemaphoreTicketHolder::waitForTicket(OperationContext* opCtx, } else { _newTicket.wait(lk, [this] { return _tryAcquire(); }); } - return Ticket{}; + return Ticket{this, admCtx}; } @@ -238,16 +235,15 @@ boost::optional<Ticket> SemaphoreTicketHolder::waitForTicketUntil(OperationConte if (!taken) { return boost::none; } - return Ticket{}; + return Ticket{this, admCtx}; } -void SemaphoreTicketHolder::release(AdmissionContext* admCtx, Ticket&& ticket) { +void SemaphoreTicketHolder::release(AdmissionContext* admCtx) { { stdx::lock_guard<Latch> lk(_mutex); _num++; } _newTicket.notify_one(); - ticket.release(); } Status SemaphoreTicketHolder::resize(int newSize) { @@ -324,10 +320,9 @@ int FifoTicketHolder::queued() const { return std::max(static_cast<int>(added - removed), 0); } -void FifoTicketHolder::release(AdmissionContext* admCtx, Ticket&& ticket) { +void FifoTicketHolder::_release(AdmissionContext* admCtx) noexcept { invariant(admCtx); - ticket.release(); auto tickSource = _serviceContext->getTickSource(); // Update statistics. @@ -382,7 +377,7 @@ boost::optional<Ticket> FifoTicketHolder::tryAcquire(AdmissionContext* admCtx) { } admCtx->start(_serviceContext->getTickSource()); _totalStartedProcessing.fetchAndAddRelaxed(1); - return Ticket{}; + return Ticket{this, admCtx}; } Ticket FifoTicketHolder::waitForTicket(OperationContext* opCtx, @@ -438,7 +433,7 @@ boost::optional<Ticket> FifoTicketHolder::waitForTicketUntil(OperationContext* o if (remaining >= 0) { _enqueuedElements.subtractAndFetch(1); startProcessing(); - return Ticket{}; + return Ticket{this, admCtx}; } _ticketsAvailable.addAndFetch(1); // We copy-construct the shared_ptr here as the waiting element needs to be alive in both @@ -460,7 +455,7 @@ boost::optional<Ticket> FifoTicketHolder::waitForTicketUntil(OperationContext* o // To cover the edge case of getting a ticket assigned before cancelling the ticket // request. As we have been granted a ticket we must release it. startProcessing(); - release(admCtx, Ticket{}); + _release(admCtx); } }); @@ -487,7 +482,7 @@ boost::optional<Ticket> FifoTicketHolder::waitForTicketUntil(OperationContext* o if (assigned) { cancelWait.dismiss(); startProcessing(); - return Ticket{}; + return Ticket{this, admCtx}; } else { return boost::none; } @@ -502,15 +497,14 @@ Status FifoTicketHolder::resize(int newSize) { AdmissionContext admCtx; while (_capacity.load() < newSize) { - Ticket ticket; admCtx.start(_serviceContext->getTickSource()); - release(&admCtx, std::move(ticket)); + _release(&admCtx); _capacity.fetchAndAdd(1); } while (_capacity.load() > newSize) { - Ticket ticket = waitForTicket(nullptr, &admCtx, WaitMode::kUninterruptible); - ticket.release(); + auto ticket = waitForTicket(nullptr, &admCtx, WaitMode::kUninterruptible); + ticket.discard(); _capacity.subtractAndFetch(1); } diff --git a/src/mongo/util/concurrency/ticketholder.h b/src/mongo/util/concurrency/ticketholder.h index a03518f908b..3e8348a80ac 100644 --- a/src/mongo/util/concurrency/ticketholder.h +++ b/src/mongo/util/concurrency/ticketholder.h @@ -41,13 +41,16 @@ #include "mongo/stdx/future.h" #include "mongo/util/concurrency/admission_context.h" #include "mongo/util/concurrency/mutex.h" -#include "mongo/util/concurrency/ticket.h" #include "mongo/util/hierarchical_acquisition.h" #include "mongo/util/time_support.h" namespace mongo { +class Ticket; + class TicketHolder { + friend class Ticket; + public: /** * Wait mode for ticket acquisition: interruptible or uninterruptible. @@ -80,7 +83,6 @@ public: AdmissionContext* admCtx, Date_t until, WaitMode waitMode) = 0; - virtual void release(AdmissionContext* admCtx, Ticket&& ticket) = 0; virtual Status resize(int newSize) = 0; @@ -91,6 +93,9 @@ public: virtual int outof() const = 0; virtual void appendStats(BSONObjBuilder& b) const = 0; + +private: + virtual void _release(AdmissionContext* admCtx) noexcept = 0; }; class SemaphoreTicketHolder final : public TicketHolder { @@ -109,7 +114,6 @@ public: Date_t until, WaitMode waitMode) override final; - void release(AdmissionContext* admCtx, Ticket&& ticket) override final; Status resize(int newSize) override final; @@ -122,6 +126,8 @@ public: void appendStats(BSONObjBuilder& b) const override final; private: + void _release(AdmissionContext* admCtx) noexcept override final; + #if defined(__linux__) mutable sem_t _sem; @@ -161,7 +167,6 @@ public: Date_t until, WaitMode waitMode) override final; - void release(AdmissionContext* admCtx, Ticket&& ticket) override final; Status resize(int newSize) override final; @@ -176,6 +181,8 @@ public: void appendStats(BSONObjBuilder& b) const override final; private: + void _release(AdmissionContext* admCtx) noexcept override final; + void _release(WithLock); Mutex _resizeMutex = @@ -207,50 +214,60 @@ private: ServiceContext* _serviceContext; }; -class ScopedTicket { -public: - ScopedTicket(OperationContext* opCtx, TicketHolder* holder, TicketHolder::WaitMode waitMode) - : _holder(holder), _ticket(_holder->waitForTicket(opCtx, &_admCtx, waitMode)) {} - - ~ScopedTicket() { - _holder->release(&_admCtx, std::move(_ticket)); - } - -private: - AdmissionContext _admCtx; - TicketHolder* _holder; - Ticket _ticket; -}; - -class TicketHolderReleaser { - TicketHolderReleaser(const TicketHolderReleaser&) = delete; - TicketHolderReleaser& operator=(const TicketHolderReleaser&) = delete; +/** + * RAII-style movable token that gets generated when a ticket is acquired and is automatically + * released when going out of scope. + */ +class Ticket { + friend class SemaphoreTicketHolder; + friend class FifoTicketHolder; public: - explicit TicketHolderReleaser(Ticket&& ticket, AdmissionContext* admCtx, TicketHolder* holder) - : _holder(holder), _ticket(std::move(ticket)), _admCtx(admCtx) {} + Ticket(Ticket&& t) : _ticketholder(t._ticketholder), _admissionContext(t._admissionContext) { + t._ticketholder = nullptr; + t._admissionContext = nullptr; + } + Ticket& operator=(Ticket&& t) { + invariant(!valid(), "Attempting to overwrite a valid ticket with another one"); + _ticketholder = t._ticketholder; + _admissionContext = t._admissionContext; + t._ticketholder = nullptr; + t._admissionContext = nullptr; + return *this; + }; - ~TicketHolderReleaser() { - if (_holder) { - _holder->release(_admCtx, std::move(_ticket)); + ~Ticket() { + if (_ticketholder) { + _ticketholder->_release(_admissionContext); } } - bool hasTicket() const { - return _holder != nullptr; + /** + * Returns whether or not a ticket is being held. + */ + bool valid() { + return _ticketholder != nullptr; } - void reset(TicketHolder* holder = nullptr) { - if (_holder) { - _holder->release(_admCtx, std::move(_ticket)); - } - _holder = holder; +private: + Ticket(TicketHolder* ticketHolder, AdmissionContext* admissionContext) + : _ticketholder(ticketHolder), _admissionContext(admissionContext) {} + + /** + * Discards the ticket without releasing it back to the ticketholder. + */ + void discard() { + _ticketholder = nullptr; + _admissionContext = nullptr; } -private: - TicketHolder* _holder; - Ticket _ticket; - AdmissionContext* _admCtx; + // No copy constructors. + Ticket(const Ticket&) = delete; + Ticket& operator=(const Ticket&) = delete; + + TicketHolder* _ticketholder; + AdmissionContext* _admissionContext; }; + } // namespace mongo diff --git a/src/mongo/util/concurrency/ticketholder_bm.cpp b/src/mongo/util/concurrency/ticketholder_bm.cpp index be4c3034d44..0e26465aff4 100644 --- a/src/mongo/util/concurrency/ticketholder_bm.cpp +++ b/src/mongo/util/concurrency/ticketholder_bm.cpp @@ -83,8 +83,8 @@ void BM_tryAcquire(benchmark::State& state) { attempted++; if (ticket) { acquired++; - p->ticketHolder->release(&admCtx, std::move(*ticket)); } + ticket.reset(); state.ResumeTiming(); } state.counters["Attempted"] = attempted; @@ -105,10 +105,11 @@ void BM_acquire(benchmark::State& state) { for (auto _ : state) { AdmissionContext admCtx; auto opCtx = p->opCtxs[state.thread_index].get(); - auto ticket = p->ticketHolder->waitForTicket(opCtx, &admCtx, waitMode); - state.PauseTiming(); - sleepmicros(1); - p->ticketHolder->release(&admCtx, std::move(ticket)); + { + auto ticket = p->ticketHolder->waitForTicket(opCtx, &admCtx, waitMode); + state.PauseTiming(); + sleepmicros(1); + } acquired++; state.ResumeTiming(); } @@ -132,10 +133,11 @@ void BM_release(benchmark::State& state) { AdmissionContext admCtx; auto opCtx = p->opCtxs[state.thread_index].get(); state.PauseTiming(); - auto ticket = p->ticketHolder->waitForTicket(opCtx, &admCtx, waitMode); - sleepmicros(1); - state.ResumeTiming(); - p->ticketHolder->release(&admCtx, std::move(ticket)); + { + auto ticket = p->ticketHolder->waitForTicket(opCtx, &admCtx, waitMode); + sleepmicros(1); + state.ResumeTiming(); + } acquired++; } state.counters["Acquired"] = benchmark::Counter(acquired, benchmark::Counter::kIsRate); @@ -158,11 +160,12 @@ void BM_acquireAndRelease(benchmark::State& state) { for (auto _ : state) { AdmissionContext admCtx; auto opCtx = p->opCtxs[state.thread_index].get(); - auto ticket = p->ticketHolder->waitForTicket(opCtx, &admCtx, waitMode); - state.PauseTiming(); - sleepmicros(1); - state.ResumeTiming(); - p->ticketHolder->release(&admCtx, std::move(ticket)); + { + auto ticket = p->ticketHolder->waitForTicket(opCtx, &admCtx, waitMode); + state.PauseTiming(); + sleepmicros(1); + state.ResumeTiming(); + } acquired++; } state.counters["Acquired"] = benchmark::Counter(acquired, benchmark::Counter::kIsRate); diff --git a/src/mongo/util/concurrency/ticketholder_test.cpp b/src/mongo/util/concurrency/ticketholder_test.cpp index 7a7db89c656..64077c87819 100644 --- a/src/mongo/util/concurrency/ticketholder_test.cpp +++ b/src/mongo/util/concurrency/ticketholder_test.cpp @@ -71,7 +71,7 @@ void basicTimeout(OperationContext* opCtx) { AdmissionContext admCtx; { - ScopedTicket ticket(opCtx, holder.get(), mode); + auto ticket = holder->waitForTicket(opCtx, &admCtx, mode); ASSERT_EQ(holder->used(), 1); ASSERT_EQ(holder->available(), 0); ASSERT_EQ(holder->outof(), 1); @@ -88,48 +88,48 @@ void basicTimeout(OperationContext* opCtx) { ASSERT_EQ(holder->available(), 1); ASSERT_EQ(holder->outof(), 1); - auto ticket = holder->waitForTicketUntil(opCtx, &admCtx, Date_t::now(), mode); - ASSERT(ticket); - holder->release(&admCtx, std::move(*ticket)); + { + auto ticket = holder->waitForTicketUntil(opCtx, &admCtx, Date_t::now(), mode); + ASSERT(ticket); + } ASSERT_EQ(holder->used(), 0); - ticket = holder->waitForTicketUntil(opCtx, &admCtx, Date_t::now() + Milliseconds(20), mode); - ASSERT(ticket); - ASSERT_EQ(holder->used(), 1); + { + auto ticket = + holder->waitForTicketUntil(opCtx, &admCtx, Date_t::now() + Milliseconds(20), mode); + ASSERT(ticket); + ASSERT_EQ(holder->used(), 1); + ASSERT_FALSE( + holder->waitForTicketUntil(opCtx, &admCtx, Date_t::now() + Milliseconds(2), mode)); + } - ASSERT_FALSE(holder->waitForTicketUntil(opCtx, &admCtx, Date_t::now() + Milliseconds(2), mode)); - holder->release(&admCtx, std::move(*ticket)); ASSERT_EQ(holder->used(), 0); // // Test resize // ASSERT(holder->resize(6).isOK()); - ticket = holder->waitForTicket(opCtx, &admCtx, mode); - ASSERT(ticket); - ASSERT_EQ(holder->used(), 1); - ASSERT_EQ(holder->outof(), 6); - std::array<boost::optional<Ticket>, 5> tickets; - for (int i = 0; i < 5; ++i) { - tickets[i] = holder->waitForTicket(opCtx, &admCtx, mode); - ASSERT_EQ(holder->used(), 2 + i); + { + auto ticket = holder->waitForTicket(opCtx, &admCtx, mode); + ASSERT_EQ(holder->used(), 1); ASSERT_EQ(holder->outof(), 6); - } - ASSERT_FALSE(holder->waitForTicketUntil(opCtx, &admCtx, Date_t::now() + Milliseconds(1), mode)); + for (int i = 0; i < 5; ++i) { + tickets[i] = holder->waitForTicket(opCtx, &admCtx, mode); + ASSERT_EQ(holder->used(), 2 + i); + ASSERT_EQ(holder->outof(), 6); + } - holder->release(&admCtx, std::move(*ticket)); + ASSERT_FALSE( + holder->waitForTicketUntil(opCtx, &admCtx, Date_t::now() + Milliseconds(1), mode)); + } ASSERT(holder->resize(5).isOK()); ASSERT_EQ(holder->used(), 5); ASSERT_EQ(holder->outof(), 5); ASSERT_FALSE(holder->waitForTicketUntil(opCtx, &admCtx, Date_t::now() + Milliseconds(1), mode)); - - for (int i = 0; i < 5; ++i) { - holder->release(&admCtx, std::move(*tickets[i])); - } } TEST_F(TicketHolderTest, BasicTimeoutFifo) { @@ -162,7 +162,7 @@ TEST_F(TicketHolderTest, FifoBasicMetrics) { Stats stats(&holder); AdmissionContext admCtx; - auto ticket = + boost::optional<Ticket> ticket = holder.waitForTicket(_opCtx.get(), &admCtx, TicketHolder::WaitMode::kInterruptible); unittest::Barrier barrier(2); @@ -174,7 +174,6 @@ TEST_F(TicketHolderTest, FifoBasicMetrics) { auto ticket = holder.waitForTicket(opCtx.get(), &admCtx, TicketHolder::WaitMode::kInterruptible); barrier.countDownAndWait(); - holder.release(&admCtx, std::move(ticket)); }); while (holder.queued() == 0) { @@ -187,7 +186,7 @@ TEST_F(TicketHolderTest, FifoBasicMetrics) { ASSERT_EQ(stats["queueLength"], 1); tickSource->advance(Microseconds(100)); - holder.release(&admCtx, std::move(ticket)); + ticket.reset(); while (holder.queued() > 0) { // Wait for thread to take ticket. @@ -213,8 +212,7 @@ TEST_F(TicketHolderTest, FifoBasicMetrics) { ASSERT_EQ(stats["newAdmissions"], 2); // Retake ticket. - ticket = holder.waitForTicket(_opCtx.get(), &admCtx, TicketHolder::WaitMode::kInterruptible); - holder.release(&admCtx, std::move(ticket)); + holder.waitForTicket(_opCtx.get(), &admCtx, TicketHolder::WaitMode::kInterruptible); ASSERT_EQ(admCtx.getAdmissions(), 2); ASSERT_EQ(stats["newAdmissions"], 2); @@ -228,26 +226,27 @@ TEST_F(TicketHolderTest, FifoCanceled) { Stats stats(&holder); AdmissionContext admCtx; - auto ticket = - holder.waitForTicket(_opCtx.get(), &admCtx, TicketHolder::WaitMode::kInterruptible); + { + auto ticket = + holder.waitForTicket(_opCtx.get(), &admCtx, TicketHolder::WaitMode::kInterruptible); - stdx::thread waiting([this, &holder]() { - auto client = this->getServiceContext()->makeClient("waiting"); - auto opCtx = client->makeOperationContext(); + stdx::thread waiting([this, &holder]() { + auto client = this->getServiceContext()->makeClient("waiting"); + auto opCtx = client->makeOperationContext(); - AdmissionContext admCtx; - auto deadline = Date_t::now() + Milliseconds(100); - ASSERT_FALSE(holder.waitForTicketUntil( - opCtx.get(), &admCtx, deadline, TicketHolder::WaitMode::kInterruptible)); - }); + AdmissionContext admCtx; + auto deadline = Date_t::now() + Milliseconds(100); + ASSERT_FALSE(holder.waitForTicketUntil( + opCtx.get(), &admCtx, deadline, TicketHolder::WaitMode::kInterruptible)); + }); - while (holder.queued() == 0) { - // Wait for thread to take ticket. - } + while (holder.queued() == 0) { + // Wait for thread to take ticket. + } - tickSource->advance(Microseconds(100)); - waiting.join(); - holder.release(&admCtx, std::move(ticket)); + tickSource->advance(Microseconds(100)); + waiting.join(); + } ASSERT_EQ(stats["addedToQueue"], 1); ASSERT_EQ(stats["removedFromQueue"], 1); @@ -260,14 +259,4 @@ TEST_F(TicketHolderTest, FifoCanceled) { ASSERT_EQ(stats["canceled"], 1); } -DEATH_TEST_F(TicketHolderTest, UnreleasedTicket, "invariant") { - ServiceContext serviceContext; - serviceContext.setTickSource(std::make_unique<TickSourceMock<Microseconds>>()); - FifoTicketHolder holder(1, &serviceContext); - Stats stats(&holder); - AdmissionContext admCtx; - - auto ticket = - holder.waitForTicket(_opCtx.get(), &admCtx, TicketHolder::WaitMode::kInterruptible); -} } // namespace |