Each entry of the locks table consists of a:
Name | Description | Type |
---|---|---|
project | Project name | String |
ref | Ref path | String |
heartbeat | Timestamp updated every few seconds to identify staleness | Timestamp |
token | Timestamp used to identify the lock version | Timestamp |
owner | Gerrit instance identifier | String |
The primary key is a composite of (project, ref).
When the global-refdb attempts to acquire a lock on a given entry, we first try to insert the lock into the locks table.
If the insertion succeeds:
If the insertion fails due to a lock on that project/ref already existing:
Reclaiming an existing stale lock:
Updating a heartbeat:
When the lock is closed:
Reclaim process: | Project | Ref | Heartbeat | Token | Description | --------|-----|:----------|:------|:----------- project1
| ref1
| Stale timestamp
| T1
| When a new process attempts to lock project1-ref1
, it finds a stale heartbeat and can then insert a reclaim lock. RECLAIM_project1_T1
| ref1
| Tx
| Tx
| While this reclaim lock exists, no other process can succeed in the reclaim process.
Result: | Project | Ref | Heartbeat | Token | Description | --------|-----|:----------|:------|:----------- project1
| ref1
| Fresh timestamp
| T2
| Once the RECLAIM_ lock has successfully been inserted, the old lock is then updated and now belongs to the new process. If another process now attempts to reclaim the original lock, it will find a fresh timestamp and new token, indicating the lock is not stale and cannot be reclaimed.
Note: If a lock belonging to a frozen process is successfully reclaimed but the original owner resumes (i.e. after a long gc process), then its calling process may be unaware that it no longer holds the lock.
Sources: