[SERVER-39106] GlobalLock acquisition should throw when ticket acquisition times out if there is a max lock timeout and no deadline Created: 18/Jan/19  Updated: 29/Oct/23  Resolved: 11/Feb/19

Status: Closed
Project: Core Server
Component/s: Replication, Storage
Affects Version/s: None
Fix Version/s: 4.0.7, 4.1.8

Type: Bug Priority: Major - P3
Reporter: Tess Avitabile (Inactive) Assignee: Xiangyu Yao (Inactive)
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Backports
Depends
Related
related to SERVER-39320 lower wiredTigerConcurrentWriteTransa... Closed
Backwards Compatibility: Fully Compatible
Operating System: ALL
Backport Requested:
v4.0
Sprint: Storage NYC 2019-02-11
Participants:
Linked BF Score: 69
Story Points: 3

 Description   

If global lock acquisition times out acquiring a ticket, then the constructor will not throw, but the resource will be unlocked. This leads to invariant failure when we attempt to acquire the global lock here then call canAcceptWritesForDatabase() here, which invariants that the lock is held here.

If the caller did not provide a deadline, then they are not checking for lock acquisition failure, so the lock acquisition should throw. Consider applying the following patch:

diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp
index 11a4028..e7040b8 100644
--- a/src/mongo/db/concurrency/lock_state.cpp
+++ b/src/mongo/db/concurrency/lock_state.cpp
@@ -353,6 +353,12 @@ LockResult LockerImpl::_lockGlobalBegin(OperationContext* opCtx, LockMode mode,
     dassert(isLocked() == (_modeForTicket != MODE_NONE));
     if (_modeForTicket == MODE_NONE) {
         auto acquireTicketResult = _acquireTicket(opCtx, mode, deadline);
+        uassert(ErrorCodes::LockTimeout,
+                str::stream() << "Unable to acquire ticket with mode '" << mode
+                              << "' within a max lock request timeout of '"
+                              << _maxLockTimeout.get()
+                              << "' milliseconds.",
+                acquireTicketResult == LOCK_OK || !_maxLockTimeout);
         if (acquireTicketResult != LOCK_OK) {
             return acquireTicketResult;
         } 



 Comments   
Comment by Githook User [ 17/Feb/19 ]

Author:

{'name': 'Xiangyu Yao', 'email': 'xiangyu.yao@mongodb.com', 'username': 'xy24'}

Message: SERVER-39106 GlobalLock acquisition should throw if its ticket acquisition times out due to max lock timeout

(cherry picked from commit 691ab6da0c38f52f32c1028a8fa7447997ced255)
Branch: v4.0
https://github.com/mongodb/mongo/commit/1ba6286466917a01292f1b6f61c7b442770d7418

Comment by Githook User [ 11/Feb/19 ]

Author:

{'name': 'Xiangyu Yao', 'email': 'xiangyu.yao@mongodb.com', 'username': 'xy24'}

Message: SERVER-39106 GlobalLock acquisition should throw if its ticket acquisition times out due to max lock timeout
Branch: master
https://github.com/mongodb/mongo/commit/691ab6da0c38f52f32c1028a8fa7447997ced255

Comment by Geert Bosch [ 22/Jan/19 ]

Originally the rule was that you would be guaranteed to obtain the lock when not passing in a deadline. It seems that SERVER-33473 not only made ticket acquisition interruptible (and able to throw interrupt exceptions), but also added cases where we'd return LOCK_TIMEOUT even when in an interruptible context. As part of fixing this ticket we should also add missing unit testing.

Generated at Thu Feb 08 04:51:02 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.