# whlog : HybridLog
## Introduction
whlog provides a Garnet Tsavorite-style HybridLog allocator: a 64-bit logical address space over the wdev device with wepoch epoch protection, a circular page buffer, and a three-region sliding state machine.
The three regions: `[read_only, tail)` mutable (in-place updates), `[head, read_only)` read-only (memory resident, updates append), `[begin, head)` on-disk. The boundary state machine enforces `0 <= begin <= safe_head <= head <= safe_read_only <= read_only <= tail`, plus `head <= flushed_until <= tail` (data evicted from memory is always already flushed).
## Module Layout
- `address`: `AddressManager` with 7 AtomicU64 boundaries + encodable `AddressSnapshot`
- `buffer`: `CircularPageBuffer` circular page buffer pool, per-page RwLock fine-grained concurrency
- `config`: `HybridLogConfig`; RO lag ratio is fixed-point (20 fractional bits), zero floats on hot paths
- `flush`: `PageFlushRange` + `PendingFlushList` with greedy merging of adjacent ranges and completion tracking
- `hlog/`: HybridLog core — append (appends and page turns), inplace (in-place update / tombstone / RMW / revivify), io (read path and batch flush I/O), shift (three-region boundary sliding and truncation)
- `output`: `RecordOutput` (zero-copy destructuring into Memory / Disk)
- `scan`: `ScanIterator` hybrid scan iterator with zero-copy item views
## Core API
- `HybridLog<D: Device>`: new(config, device, epoch), append, try_update_in_place, try_mark_tombstone_in_place, try_modify_record_in_place, try_modify_record_with_slack, try_revivify_in_chain, revivify_record_at, with_memory_record (synchronous zero-copy in-memory probe read, returning Ok(None) when not resident for cold-read fallback), read_record / read_disk_record (async), flush_page / flush_pages_range / sync / flush_all (async), iterate_version_chain, recover (async), scan / scan_iter (push/pull range scanning), shift_read_only_address / shift_read_only_to_tail, shift_head_address, shift_begin_address (async truncation: freezes the read-only region and flushes [flushed_until, new_begin) first, advances head inline with safe_head following via epoch drain and begin directly, then physically truncates historical segments), begin_address, etc.
- `AddressManager` / `AddressSnapshot`
- `CircularPageBuffer`
- `HybridLogConfig`: `DEFAULT_PAGE_SIZE = 64KiB`, `DEFAULT_NUM_PAGES = 16`, `DEFAULT_MUTABLE_FRACTION = 0.5`, `DEFAULT_INITIAL_ADDRESS = 64`, `SECTOR_ALIGNMENT = 4096`, `ro_lag_num_from_fraction()`
- `PendingFlushList` / `PageFlushRange`, `RecordOutput`, `ScanIterator`, `PAD_KEY_LEN`
## Design Notes
- Boundary advancement: Unsafe boundaries publish first; Safe boundaries advance only after epoch draining (BumpCurrentEpoch + drain actions)
- Crash-consistency boundary = the `flushed_until` contiguous prefix + caller `sync`; flushing is caller-driven single-threaded batch flush (compio thread-per-core model)
- recover forcibly zeroes torn records beyond the flushed_until prefix; recovered visible state is strictly limited to the persisted prefix
- Page locks are taken only on page turns; appends within a page are lock-free; wrapping a slot requires flushed + evicted + epoch-drained simultaneously, otherwise `PageNotReady` is returned for retry
- Cold read path carries a 2-slot direct-mapped disk page cache, loading only pages fully flushed and frozen read-only; a continuity heuristic (4096B probe reads) avoids full-page read amplification on random workloads
- ScanIterator snapshots read_only once at construction; head / flushed_until are deliberately not snapshotted to avoid missing records; lock-free bare reads of the read-only region require the calling thread to hold a LightEpoch
## Test Coverage
tests/ covers: append and in-memory reads, in-place updates with protection, page filling, flush and cold disk reads, RCU version chains, pending-flush merging, batch-flush Direct I/O, mixed disk/memory scans with early stop, recover snapshot invariants, resume-after-recovery, shift_read_only_to_tail, concurrent append stress, circular eviction, inplace lifecycle, revivify + Pad, Begin truncation, non-persisted prefix cleaning, torn-tail padding, config validation, cold-read precise trimming, disk page cache and adaptive loading, stale ranges and short writes, multi-segment recovery windows.