Expand description
v7.37.15 (Phase C.4) — row-level lock table, the four PG tuple-lock modes, and wait-for deadlock detection.
§Why this exists
Phase C’s in-place write path (C.3) lets concurrent transactions
update / delete different rows without blocking. But two writers
that touch the SAME row must serialise, and a SELECT ... FOR UPDATE must be able to reserve rows ahead of the write. This
module is the lock table that arbitrates: it keys locks on the
stable (RelId, RowId) identity (Phase C.1) so a held lock keeps
naming the same row across concurrent compaction.
§Additive at this commit
Pure no_std logic with no consumer yet: the write path (C.3/C.4)
calls acquire / release_all, and the host (spg-server,
thread-per-connection) parks a waiting thread behind a Parker
informed by LockOutcome::WouldBlock. The engine core only
records the wait-for edges and runs the cycle detector — keeping it
no_std (no thread primitives leak into the core). Under today’s
single external engine lock the table is mutated serially; the
sharded lock-free version is Phase C.5.
§The four modes and their conflicts
Mirrors PG’s tuple-lock strengths (weakest → strongest):
KeyShare < Share < NoKeyUpdate < Exclusive. The load-bearing
compatibility is KeyShare ∥ NoKeyUpdate: an FK existence check
(FOR KEY SHARE) runs concurrently with a non-key UPDATE
(NoKeyUpdate) on the same parent row — a real concurrency win we
match, not a coincidence.
Structs§
- Lock
Table - The row-lock table. Keyed on stable
(RelId, RowId); carries the wait-for graph used for deadlock detection.
Enums§
- Lock
Mode - A PG tuple-lock strength.
FOR KEY SHARE/FOR SHARE/FOR NO KEY UPDATE/FOR UPDATE, plus the implicit modes a write takes: a key-touching UPDATE or any DELETE takesExclusive; a non-key UPDATE takesNoKeyUpdate. - Lock
Outcome - The result of an
LockTable::acquireattempt. - Wait
Policy - What a caller wants to happen when the lock it requests is not
immediately available. Mirrors PG’s
LockWaitPolicy.