Concurrency Manager
Concurrency Manager provides a simple set of APIs that abstract away the complexity of providing isolation for database requests and making sure the requests are executed in a fashion that doesn't run into anomalies. The Concurrency Manager is composed of a latch manager, a lock table, and a txnWaitQueue.
Concurrency Manager API
The API is made up of two methods: sequence_req
and finish_req
.
Sequence_req: (request) → Result<Guard, SequenceReqError>
Sequence_req
provides isolation for the request by acquiring latches and waiting for conflicting locks to be released. Once Sequence_req
returns a Guard
, the request is guaranteed isolation until the guard is released.
Finish_req: (guard) → ()
Finish_req
is called when the request has finished executing. It releases the request from the components of the concurrency manager and allows blocked requests to proceed.
Implementation
Sequence_req
Sequence_req first figures out the keys it needs to acquire latches and locks for. It then creates a loop. Each time it loops, it performs the following:
- it acquires the latches
- it calls the lock table’s
scan_and_enqueue
method to see if there is a conflicting lock for one of the request’s keys- if there is a conflicting lock, the thread will release the latches and wait until the lock is released. After waiting, it will have become a
reservation
for the lock. In that case, it is free to re-acquire latches and rescan the lock table in the next iteration of the loop. - if there isn’t a conflicting lock, the function stops looping and returns.
- if there is a conflicting lock, the thread will release the latches and wait until the lock is released. After waiting, it will have become a
Finish_req
Finish_req simply releases the latches and dequeues acquired locks from the lock table.
CockroachDB’s Implementation
The core idea behind CockroachDB’s SequenceReq implementation is similar to my implementation. The difference is that it has different modes, such as OptimisticEval and PessimisticEval. If the mode is OptimisticEval, it calls AcquireOptimistic which does not wait for conflicting latches to be released. It needs to be followed with CheckOptimisticNoConflicts to ensure correctness.
My implementation is more similar to the pessimistic evaluation approach, which acquires latches. CockroachDB’s SequenceReq then calls ScanAndEnqueue to find conflicting locks. If a conflicting lock is found, WaitOn is called, which waits until the lock is released or pushes the transaction if it times out.