Table of Contents

Reader-Writer & Resource Lifecycle Locks

CAS-only, allocation-free spin-locks every concurrent engine structure embeds for shared/exclusive or lifecycle access.

Status: โœ… Implemented ยท Visibility: Internal ยท Category: Foundation

๐ŸŽฏ What it solves

Typhon's microsecond-level latency targets rule out OS-level synchronization (mutexes, semaphores, ReaderWriterLockSlim) for the thousands of small, short-lived locks the engine needs โ€” page latches, B+Tree node locks, component-table guards, transaction-pool locks. Three purpose-built lock shapes cover the recurring access patterns the engine actually needs โ€” general reader/writer, a compact reader/writer for high-density embedding, and a three-mode lifecycle lock for structures that grow while being read โ€” without the cost of kernel objects or heap allocation.

โš™๏ธ How it works (in brief)

All three pack their entire state into a single atomic word (8, 4, and 4 bytes respectively) and transition exclusively via Interlocked.CompareExchange โ€” no wait queues, no kernel handles, no managed allocation. Contention spins via .NET's SpinWait (busy-spin โ†’ yield โ†’ sleep) and never parks a thread. Every blocking entry point takes a ref WaitContext (monotonic deadline + CancellationToken); pass ref WaitContext.Null for an infinite, zero-overhead wait. Picking the right one is a tradeoff between memory footprint, waiter fairness, and access semantics โ€” see the sub-features below.

Sub-features

Sub-feature Size Use it when...
AccessControl 8 bytes Few instances, many threads, writer starvation under read pressure is unacceptable
AccessControlSmall 4 bytes Thousands of instances embedded per-node/per-page, fairness isn't needed
ResourceAccessControl 4 bytes Structural growth must not block concurrent readers; destruction must drain everything

โš ๏ธ Guarantees & limits

  • All three are internal engine types โ€” application code never constructs or calls them directly; they're the plumbing inside ComponentTable, TransactionChain, page latches, B+Tree nodes, segment chains, etc.
  • Thread IDs are stored in exactly 16 bits everywhere (max 65,535) โ€” consistent overflow headroom across the family, sized for 500+ core servers.
  • Pure userspace spin-wait, never OS-level parking โ€” cheap for the engine's typical sub-microsecond hold times, wasteful if misused for long critical sections.
  • No deadlock detection by design: correctness rests on Typhon's MVCC (no cross-transaction lock holding) and strict latch-coupling order in the B+Tree/R-Tree, not on runtime detection in these primitives.
  • Contention surfaces through the profiler's trace-event stream (TyphonEvent.Emit*, gated and JIT-eliminated when the profiler is off) โ€” not an opt-in callback interface.

๐Ÿงช Tests

  • AccessControlTests โ€” full-featured RW lock: shared/exclusive/promote-demote, fairness under contention, deadline+cancellation wiring.
  • AccessControlSmallTests โ€” compact RW lock: idle/shared/exclusive transitions, misuse-throws contract.
  • ResourceAccessControlTests โ€” 3-mode Accessing/Modify/Destroy semantics, MODIFY_PENDING fairness, promote/demote.