From 2cc62a244fb4cb88114072d5fec3591b246982e8 Mon Sep 17 00:00:00 2001 From: Marcos Grillo Date: Mon, 9 Mar 2026 19:17:38 +0100 Subject: [PATCH] SERVER-119731 Allow re-entering low priority operations in ordered queue even if maxQueueDepth is exceeded (#49077) Co-authored-by: Pol Pinol Castuera GitOrigin-RevId: ce084777b81af22b48f0e0ccb9acddd482b187c8 --- .../concurrency/ordered_ticket_semaphore.cpp | 3 +- .../ordered_ticket_semaphore_test.cpp | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/mongo/util/concurrency/ordered_ticket_semaphore.cpp b/src/mongo/util/concurrency/ordered_ticket_semaphore.cpp index 62739c979c4..3dc151b3db6 100644 --- a/src/mongo/util/concurrency/ordered_ticket_semaphore.cpp +++ b/src/mongo/util/concurrency/ordered_ticket_semaphore.cpp @@ -49,7 +49,8 @@ bool OrderedTicketSemaphore::acquire(OperationContext* opCtx, return true; } - if (static_cast(_waitQueue.size()) >= _maxWaiters.loadRelaxed()) { + if (admCtx->getLowAdmissions() == 0 && + static_cast(_waitQueue.size()) >= _maxWaiters.loadRelaxed()) { admCtx->recordOperationLoadShed(); lk.unlock(); uasserted(ErrorCodes::AdmissionQueueOverflow, diff --git a/src/mongo/util/concurrency/ordered_ticket_semaphore_test.cpp b/src/mongo/util/concurrency/ordered_ticket_semaphore_test.cpp index f3fa545901b..f02d62180a7 100644 --- a/src/mongo/util/concurrency/ordered_ticket_semaphore_test.cpp +++ b/src/mongo/util/concurrency/ordered_ticket_semaphore_test.cpp @@ -370,4 +370,42 @@ TEST_F(OrderedTicketSemaphoreTest, TryAcquireReturnsFalseWhenWaitersQueued) { future.get(); ASSERT_EQ(sem->available(), 0); } + +/** + * Test that operations with lowAdmissions > 0 can bypass the max waiters limit. + */ +TEST_F(OrderedTicketSemaphoreTest, LowAdmissionsCanBypassMaxWaitersLimit) { + auto sem = makeSemaphore(0, 1); // 0 tickets, max 1 waiter. + + MockAdmissionContext admCtx1, admCtx2WithLowAdmissions, admCtx3NoLowAdmissions; + + auto future1 = launchAsync([&]() { + auto [client, opCtx] = makeOpCtx(); + ASSERT_TRUE(sem->acquire(opCtx.get(), &admCtx1, Date_t::max(), true)); + }); + + waitForQueuedThreads(sem, 1); + ASSERT_EQ(sem->waiters(), 1); + + ASSERT_THROWS_CODE(sem->acquire(opCtx(), &admCtx3NoLowAdmissions, getDeadline(), true), + DBException, + ErrorCodes::AdmissionQueueOverflow); + ASSERT_EQ(sem->waiters(), 1); // Queue unchanged. + + // An operation with lowAdmissions > 0 should be able to bypass the limit. + admCtx2WithLowAdmissions.recordLowAdmission(); + ASSERT_GT(admCtx2WithLowAdmissions.getLowAdmissions(), 0); + + auto future2 = launchAsync([&]() { + auto [client, opCtx] = makeOpCtx(); + ASSERT_TRUE(sem->acquire(opCtx.get(), &admCtx2WithLowAdmissions, Date_t::max(), true)); + }); + + waitForQueuedThreads(sem, 2); + ASSERT_EQ(sem->waiters(), 2); + + sem->resize(2); + future1.get(); + future2.get(); +} } // namespace mongo