Skip to content

Pager and buffer pool#2

Merged
tamnd merged 1 commit into
mainfrom
m1a-pager
Jun 20, 2026
Merged

Pager and buffer pool#2
tamnd merged 1 commit into
mainfrom
m1a-pager

Conversation

@tamnd

@tamnd tamnd commented Jun 20, 2026

Copy link
Copy Markdown
Owner

First vertical slice of M1: the pager that sits between the storage cores and the file.

What this adds

  • pager.Pager over the vfs seam: page numbers in, pinned in-memory frames out.
  • Frames carved from a single arena, so the pool is one GC object and every page slice is stable for the pool's lifetime (three-index slices cap capacity at one page).
  • Get/Unpin pin contract, Allocate/Free page lifecycle, Checkpoint(lsn) durability boundary.
  • CLOCK replacement with a bounded sweep that fails cleanly on a fully pinned pool instead of blocking.
  • In-memory freelist materialized to trunk pages only at checkpoint; loaded back at Open.

Design notes

  • Single-mutex for correctness. The lock-free read path, sharded page table, and OLC the spec describes (03 §6) are a later optimization that does not change any signature here.
  • A dirty victim can be written back during eviction because a page is never dirtied before its describing WAL batch is durable, so an early flush only moves committed bytes toward home; recovery replays the same batch idempotently. No page-LSN bookkeeping.
  • Intent (Read/Write) is advisory this milestone; dirtiness is declared at Unpin.

Tests

go test -race ./... green. Pager tests cover create/reopen round-trip, eviction round-trip (64 pages through an 8-frame pool), checkpoint durability across a simulated memfs crash, allocate/free reuse with freelist persistence, and clean pool-exhaustion failure.

Implementation doc: notes/Spec/2059/implementation/04-pager.md.

The pager turns page numbers into pinned in-memory frames and owns the
buffer pool. Frames are carved from a single arena so the pool is one GC
object and each page slice is stable for the pool's lifetime.

Get/Unpin is the pin contract the cores will use; Allocate/Free is the
page lifecycle; Checkpoint flushes dirty frames, persists the freelist
to trunk pages, and fsyncs to make the main file a torn-free image.

Replacement is CLOCK with a bounded sweep that fails cleanly when every
frame is pinned rather than blocking. Dirty victims can be written back
mid-flight because a page is never dirtied before its WAL batch is
durable, so an early flush only moves committed bytes home.

Concurrency is single-mutex for now. The lock-free read path and
sharded page table the spec describes are a later optimization that
does not change these signatures.
@tamnd tamnd merged commit ce7d927 into main Jun 20, 2026
1 check passed
@tamnd tamnd deleted the m1a-pager branch June 20, 2026 07:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant