◐ Off-By-One · answer catalog

go-paged-kv-cache-block-manager-cow-prefix-share

2 answer(s)gogo1.26gogo1.26

Implement a fixed-pool paged KV-cache block manager in Go with:

📦 Source in repository (JSON)

Answer 1

The complete solution is written to ~/kvcache/SOLUTION.md, with the verified code in ~/kvcache/manager.go and ~/kvcache/manager_test.go. Here is the solution.


vLLM-style Paged KV-Cache Block Manager — Diagnosis & Fix

Problem

Implement a fixed-pool paged KV-cache block manager in Go with:

Root-cause analysis

A naive implementation fails in five independent ways. Each maps to a concrete bug the fix must prevent:

  1. Immediate free on release. Treating a block as free as soon as one sequence releases it destroys prefix blocks still used by forks. Cause: no per-block reference count. Fix: reference-count every physical block; release only decrements and the block becomes evictable at zero.
  2. No COW on a shared partial tail. Appending into a partially filled tail that is shared by a fork mutates the parent (and every sibling). Cause: writes go straight into the current physical block. Fix: if the write lands in a shared tail (refs > 1), reserve a fresh block, copy the payload, swap the table slot, and drop the old reference. A full shared block needs no COW because the next token starts a new block.
  3. Mutate-then-allocate. Allocating the COW block first, then failing to allocate an additional block, leaves the table half-rewritten. Cause: allocation happens piecemeal inside the commit. Fix: compute the full reservation set up front (COW block + missing tail blocks), reserve all of it, and roll back reservations if any allocation fails — so the table is never touched on ErrNoBlockAvailable.
  4. Arbitrary / non-deterministic eviction. Picking any refcount-zero block (or a free-list pop) gives no temporal locality and no recompute signal. Cause: no recency metadata. Fix: assign a monotonic logical clock, touch blocks on every reference/append, and reclaim the minimum-lastTouch refcount-zero block; invoke the recompute hook with a copy of its payload before scrubbing.
  5. Silent exhaustion. Returning a sentinel -1/nil or reusing a referenced block corrupts live tables. Cause: no typed error path. Fix: ErrNoBlockAvailable when no refcount-zero block exists, and an explicit rollback path.

An invariant checker (CheckInvariants) recomputes every refcount and the block coverage of every live sequence from scratch, which is what catches classes 1–3 during randomized testing.

The fix

Module example.com/kvblock. Two files: manager.go and manager_test.go.

manager.go

// Package kvblock implements a vLLM-style paged KV-cache block manager.
//
// A fixed pool of physical blocks (numBlocks, each holding blockSize tokens)
// is shared by many sequences. Every sequence owns a block table mapping
// logical block index -> physical BlockID. Appends grow the table; a partially
// filled final block keeps accepting tokens. Forked sequences share prefix
// blocks copy-on-write (COW) via reference counts. Blocks whose refcount drops
// to zero become cached/evictable and are recycled LRU-first when the pool is
// exhausted; if nothing is evictable the allocation fails closed with
// ErrNoBlockAvailable and leaves the caller's table untouched.
package kvblock

import (
    "errors"
    "fmt"
)

// BlockID identifies a physical block in the manager's pool.
type BlockID int

var (
    // ErrNoBlockAvailable is returned when the pool is exhausted and no
    // evictable (refcount == 0) block exists. Allocation fails closed: the
    // caller's block table is left exactly as it was.
    ErrNoBlockAvailable = errors.New("kvblock: pool exhausted: no evictable block available")
    // ErrInvalidBlockID is returned for out-of-range block identifiers.
    ErrInvalidBlockID = errors.New("kvblock: invalid physical block id")
    // ErrSequenceReleased is returned when operating on a released sequence.
    ErrSequenceReleased = errors.New("kvblock: sequence has been released")
    // ErrInvalidPosition is returned for an out-of-range token index.
    ErrInvalidPosition = errors.New("kvblock: token position out of range")
    // ErrInvalidGeometry is returned by NewManager for non-positive sizes.
    ErrInvalidGeometry = errors.New("kvblock: blockSize and numBlocks must be positive")
)

// EvictHook is invoked when a cached block (refcount == 0 but still holding a
// valid payload) is evicted to make room for a new allocation. It receives the
// evicted block id and a private copy of its token payload so the caller can
// schedule recomputation of that prefix.
type EvictHook func(block BlockID, tokens []uint64)

type block struct {
    id        BlockID
    refs      int
    lastTouch int64
    valid     bool // payload is meaningful and may be cached
    data      []uint64
}

// Manager owns the fixed physical block pool and all live sequences.
type Manager struct {
    blockSize int
    numBlocks int
    blocks    []block
    clock     int64
    allocs    int64
    evictions int64
    seqs      map[int]*Sequence
    nextSeqID int
    onEvict   EvictHook
}

// NewManager builds a pool of numBlocks physical blocks each holding
// blockSize tokens. onEvict may be nil.
func NewManager(blockSize, numBlocks int, onEvict EvictHook) (*Manager, error) {
    if blockSize <= 0 || numBlocks <= 0 {
        return nil, ErrInvalidGeometry
    }
    m := &Manager{
        blockSize: blockSize,
        numBlocks: numBlocks,
        blocks:    make([]block, numBlocks),
        seqs:      make(map[int]*Sequence),
        onEvict:   onEvict,
    }
    for i := range m.blocks {
        m.blocks[i] = block{id: BlockID(i), data: make([]uint64, blockSize)}
    }
    return m, nil
}

func (m *Manager) tick() int64 { m.clock++; return m.clock }

// BlockSize reports the token capacity of one physical block.
func (m *Manager) BlockSize() int { return m.blockSize }

// NumBlocks reports the total number of physical blocks in the pool.
func (m *Manager) NumBlocks() int { return m.numBlocks }

// AllocationCount is the cumulative number of physical block reservations.
func (m *Manager) AllocationCount() int64 { return m.allocs }

// EvictionCount is the cumulative number of cached blocks reclaimed for reuse.
func (m *Manager) EvictionCount() int64 { return m.evictions }

// RefCount returns the live reference count of a physical block.
func (m *Manager) RefCount(id BlockID) int {
    if id < 0 || int(id) >= m.numBlocks {
        return -1
    }
    return m.blocks[id].refs
}

// InUse is the number of physical blocks currently referenced by sequences.
func (m *Manager) InUse() int {
    n := 0
    for i := range m.blocks {
        if m.blocks[i].refs > 0 {
            n++
        }
    }
    return n
}

// TotalRefs is the sum of every physical block's reference count. After all
// sequences have been released this must be zero for a leak-free run.
func (m *Manager) TotalRefs() int {
    n := 0
    for i := range m.blocks {
        n += m.blocks[i].refs
    }
    return n
}

// alloc reserves one physical block with refcount 1. It prefers the least
// recently touched evictable block. With no evictable block it returns
// ErrNoBlockAvailable without mutating anything.
func (m *Manager) alloc() (BlockID, error) {
    best := BlockID(-1)
    for i := range m.blocks {
        b := &m.blocks[i]
        if b.refs != 0 {
            continue
        }
        if best == -1 || b.lastTouch < m.blocks[best].lastTouch {
            best = b.id
        }
    }
    if best == -1 {
        return -1, ErrNoBlockAvailable
    }
    b := &m.blocks[best]
    if b.valid {
        m.evictions++
        if m.onEvict != nil {
            cp := make([]uint64, len(b.data))
            copy(cp, b.data)
            m.onEvict(best, cp)
        }
    }
    for i := range b.data {
        b.data[i] = 0
    }
    b.valid = false
    b.refs = 1
    b.lastTouch = m.tick()
    m.allocs++
    return best, nil
}

// releaseBlock drops one reference; the block is never freed while another
// sequence still holds a reference. At zero references the block becomes
// evictable (its payload stays cached until reclaimed).
func (m *Manager) releaseBlock(id BlockID) {
    b := &m.blocks[id]
    if b.refs <= 0 {
        return
    }
    b.refs--
    if b.refs == 0 {
        b.lastTouch = m.tick()
    }
}

// Sequence is one logical request's block table plus token length.
type Sequence struct {
    m        *Manager
    id       int
    table    []BlockID
    tokens   int
    released bool
}

// NewSequence creates an empty sequence with no blocks.
func (m *Manager) NewSequence() *Sequence {
    s := &Sequence{m: m, id: m.nextSeqID}
    m.nextSeqID++
    m.seqs[s.id] = s
    return s
}

// ID is the manager-unique sequence identifier.
func (s *Sequence) ID() int { return s.id }

// Len is the number of tokens currently held by the sequence.
func (s *Sequence) Len() int { return s.tokens }

// Released reports whether Release has been called.
func (s *Sequence) Released() bool { return s.released }

// Table returns a copy of the logical -> physical block mapping.
func (s *Sequence) Table() []BlockID {
    return append([]BlockID(nil), s.table...)
}

// Fork creates a child sharing the parent's entire prefix block table COW.
// Every shared block's reference count is incremented.
func (s *Sequence) Fork() (*Sequence, error) {
    if s.released {
        return nil, ErrSequenceReleased
    }
    child := &Sequence{
        m:      s.m,
        id:     s.m.nextSeqID,
        tokens: s.tokens,
        table:  append([]BlockID(nil), s.table...),
    }
    s.m.nextSeqID++
    for _, id := range s.table {
        s.m.blocks[id].refs++
        s.m.blocks[id].lastTouch = s.m.tick()
    }
    s.m.seqs[child.id] = child
    return child, nil
}

// Append grows the sequence by len(vals) tokens, allocating and appending
// blocks as needed. If the write lands in a shared partial final block it is
// copied-on-write so the other sharers are never mutated. All required blocks
// are reserved before any state changes, so a pool-exhaustion error leaves the
// table exactly as it was (fail closed).
func (s *Sequence) Append(vals ...uint64) error {
    if s.released {
        return ErrSequenceReleased
    }
    if len(vals) == 0 {
        return nil
    }
    m := s.m
    bs := m.blockSize
    start := s.tokens
    end := start + len(vals)
    needBlocks := (end + bs - 1) / bs

    // Will the first appended token overwrite a shared partial tail?
    lastShared := false
    if start%bs != 0 && len(s.table) > 0 {
        last := s.table[len(s.table)-1]
        if m.blocks[last].refs > 1 {
            lastShared = true
        }
    }

    missing := needBlocks - len(s.table)
    if missing < 0 {
        missing = 0
    }
    reserve := missing
    if lastShared {
        reserve++
    }

    // Reserve everything up front; roll back cleanly on exhaustion.
    reserved := make([]BlockID, 0, reserve)
    for i := 0; i < reserve; i++ {
        id, err := m.alloc()
        if err != nil {
            for _, r := range reserved {
                m.releaseBlock(r)
            }
            return err
        }
        reserved = append(reserved, id)
    }

    // Commit (cannot fail from here on).
    idx := 0
    if lastShared {
        old := s.table[len(s.table)-1]
        nb := reserved[idx]
        idx++
        copy(m.blocks[nb].data, m.blocks[old].data)
        m.blocks[nb].valid = m.blocks[old].valid
        s.table[len(s.table)-1] = nb
        m.releaseBlock(old)
    }
    for len(s.table) < needBlocks {
        s.table = append(s.table, reserved[idx])
        idx++
    }

    for i, v := range vals {
        pos := start + i
        b := &m.blocks[s.table[pos/bs]]
        b.data[pos%bs] = v
        b.valid = true
        b.lastTouch = m.tick()
    }
    s.tokens = end
    return nil
}

// BlockForToken returns the physical block backing a token index.
func (s *Sequence) BlockForToken(pos int) (BlockID, error) {
    if s.released {
        return -1, ErrSequenceReleased
    }
    if pos < 0 || pos >= s.tokens {
        return -1, ErrInvalidPosition
    }
    return s.table[pos/s.m.blockSize], nil
}

// TokenAt returns the value stored at a token index.
func (s *Sequence) TokenAt(pos int) (uint64, error) {
    id, err := s.BlockForToken(pos)
    if err != nil {
        return 0, err
    }
    return s.m.blocks[id].data[pos%s.m.blockSize], nil
}

// Release drops every reference held by the sequence. Reference counts only
// decrement; a block is never destroyed while another sequence still uses it.
func (s *Sequence) Release() {
    if s.released {
        return
    }
    s.released = true
    for _, id := range s.table {
        s.m.releaseBlock(id)
    }
    s.table = nil
    s.tokens = 0
    delete(s.m.seqs, s.id)
}

// CheckInvariants recomputes every live sequence's block coverage and every
// physical refcount from scratch and compares them to stored state. It returns
// the first inconsistency found, or nil when the manager is consistent.
func (m *Manager) CheckInvariants() error {
    want := make([]int, m.numBlocks)
    for _, s := range m.seqs {
        if s.released {
            return fmt.Errorf("kvblock: released sequence %d still registered", s.id)
        }
        expectBlocks := (s.tokens + m.blockSize - 1) / m.blockSize
        if len(s.table) != expectBlocks {
            return fmt.Errorf("kvblock: seq %d has %d tokens, %d blocks, want %d",
                s.id, s.tokens, len(s.table), expectBlocks)
        }
        for i, id := range s.table {
            if id < 0 || int(id) >= m.numBlocks {
                return fmt.Errorf("kvblock: seq %d block slot %d invalid id %d", s.id, i, id)
            }
            want[id]++
        }
    }
    for i := range m.blocks {
        if m.blocks[i].refs != want[i] {
            return fmt.Errorf("kvblock: block %d refcount=%d, want %d",
                i, m.blocks[i].refs, want[i])
        }
    }
    return nil
}

manager_test.go

package kvblock

import (
    "errors"
    "math/rand"
    "reflect"
    "testing"
)

func newTestManager(t *testing.T, bs, nb int, hook EvictHook) *Manager {
    t.Helper()
    m, err := NewManager(bs, nb, hook)
    if err != nil {
        t.Fatalf("NewManager: %v", err)
    }
    return m
}

func mustAppend(t *testing.T, s *Sequence, vals ...uint64) {
    t.Helper()
    if err := s.Append(vals...); err != nil {
        t.Fatalf("append: %v", err)
    }
}

func mustToken(t *testing.T, s *Sequence, pos int, want uint64) {
    t.Helper()
    got, err := s.TokenAt(pos)
    if err != nil {
        t.Fatalf("TokenAt(%d): %v", pos, err)
    }
    if got != want {
        t.Fatalf("TokenAt(%d)=%d, want %d", pos, got, want)
    }
}

// TestAppendPartialBlockGrowth checks that a partial tail block keeps accepting
// tokens before a new physical block is appended.
func TestAppendPartialBlockGrowth(t *testing.T) {
    m := newTestManager(t, 4, 8, nil)
    s := m.NewSequence()
    mustAppend(t, s, 1, 2, 3)
    if s.Len() != 3 || len(s.Table()) != 1 {
        t.Fatalf("after 3 tokens: len=%d blocks=%d", s.Len(), len(s.Table()))
    }
    mustAppend(t, s, 4)
    if len(s.Table()) != 1 {
        t.Fatalf("filling partial block must not allocate: blocks=%d", len(s.Table()))
    }
    mustAppend(t, s, 5)
    if len(s.Table()) != 2 {
        t.Fatalf("spilling over must allocate: blocks=%d", len(s.Table()))
    }
    for i := 0; i < 5; i++ {
        mustToken(t, s, i, uint64(i+1))
    }
    if err := m.CheckInvariants(); err != nil {
        t.Fatal(err)
    }
    s.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak after release: total refs %d", m.TotalRefs())
    }
}

// TestCopyOnWriteSharedTail asserts that appending into a shared partial final
// block clones it, leaving the parent untouched and refcounts balanced.
func TestCopyOnWriteSharedTail(t *testing.T) {
    m := newTestManager(t, 4, 8, nil)
    parent := m.NewSequence()
    mustAppend(t, parent, 10, 20, 30)

    child, err := parent.Fork()
    if err != nil {
        t.Fatal(err)
    }
    shared := parent.Table()[0]
    if m.RefCount(shared) != 2 {
        t.Fatalf("shared refcount=%d, want 2", m.RefCount(shared))
    }

    // Child writes the 4th token into the shared partial block -> COW.
    mustAppend(t, child, 40)
    if m.RefCount(shared) != 1 {
        t.Fatalf("after COW parent refcount=%d, want 1", m.RefCount(shared))
    }
    if child.Table()[0] == parent.Table()[0] {
        t.Fatal("child still points at shared block after COW")
    }
    mustToken(t, child, 3, 40)
    if _, err := parent.TokenAt(3); !errors.Is(err, ErrInvalidPosition) {
        t.Fatalf("parent sees child token: %v", err)
    }
    mustToken(t, parent, 2, 30)
    if err := m.CheckInvariants(); err != nil {
        t.Fatal(err)
    }

    parent.Release()
    child.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

// TestSharedFullBlockNoCow asserts a full shared block is not cloned when the
// append starts a fresh logical block.
func TestSharedFullBlockNoCow(t *testing.T) {
    m := newTestManager(t, 2, 8, nil)
    parent := m.NewSequence()
    mustAppend(t, parent, 1, 2) // full block
    child, _ := parent.Fork()

    mustAppend(t, child, 3) // starts block 1, no COW of block 0
    if m.RefCount(parent.Table()[0]) != 2 {
        t.Fatalf("full shared block refcount=%d, want 2", m.RefCount(parent.Table()[0]))
    }
    if child.Table()[0] != parent.Table()[0] {
        t.Fatal("unexpected COW of a full shared block")
    }
    parent.Release()
    child.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

// TestLRUEvictionAndRecomputeHook verifies the least recently touched cached
// block is reclaimed first and the hook sees its payload.
func TestLRUEvictionAndRecomputeHook(t *testing.T) {
    type ev struct {
        id     BlockID
        tokens []uint64
    }
    var evicted []ev
    m := newTestManager(t, 1, 2, func(id BlockID, tok []uint64) {
        evicted = append(evicted, ev{id, tok})
    })
    s1 := m.NewSequence()
    mustAppend(t, s1, 100, 200) // block0=100 (older), block1=200 (newer)
    s1.Release()                // both cached; block0 has smaller lastTouch

    s2 := m.NewSequence()
    mustAppend(t, s2, 999) // must evict LRU cached block
    if len(evicted) != 1 {
        t.Fatalf("hook calls=%d, want 1", len(evicted))
    }
    if evicted[0].id != 0 {
        t.Fatalf("evicted block %d, want LRU block 0", evicted[0].id)
    }
    if len(evicted[0].tokens) != 1 || evicted[0].tokens[0] != 100 {
        t.Fatalf("evicted payload=%v, want [100]", evicted[0].tokens)
    }
    if m.EvictionCount() != 1 {
        t.Fatalf("eviction count=%d, want 1", m.EvictionCount())
    }
    s2.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

// TestFailClosedOnExhaustion checks allocation returns the typed error and
// never corrupts an existing table.
func TestFailClosedOnExhaustion(t *testing.T) {
    m := newTestManager(t, 1, 2, nil)
    s1 := m.NewSequence()
    mustAppend(t, s1, 7, 8)

    s2 := m.NewSequence()
    if err := s2.Append(9); !errors.Is(err, ErrNoBlockAvailable) {
        t.Fatalf("err=%v, want ErrNoBlockAvailable", err)
    }
    if s2.Len() != 0 || len(s2.Table()) != 0 {
        t.Fatalf("failed append mutated table: len=%d blocks=%d", s2.Len(), len(s2.Table()))
    }
    mustToken(t, s1, 0, 7)
    mustToken(t, s1, 1, 8)
    if s1.Len() != 2 {
        t.Fatalf("existing sequence changed: len=%d", s1.Len())
    }
    if err := m.CheckInvariants(); err != nil {
        t.Fatal(err)
    }

    // Releasing the blocker makes room.
    s1.Release()
    if err := s2.Append(9); err != nil {
        t.Fatalf("append after release: %v", err)
    }
    mustToken(t, s2, 0, 9)
    s2.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

// TestForkSavesAllocations measures that prefix sharing allocates strictly
// fewer physical blocks than independent construction.
func TestForkSavesAllocations(t *testing.T) {
    const (
        bs    = 4
        pre   = 10 // 3 blocks
        nKids = 5
    )

    // Baseline: every sequence grows the prefix itself.
    base := newTestManager(t, bs, 256, nil)
    for i := 0; i < nKids; i++ {
        s := base.NewSequence()
        for j := 0; j < pre; j++ {
            if err := s.Append(uint64(j)); err != nil {
                t.Fatal(err)
            }
        }
    }
    baseAllocs := base.AllocationCount()

    // Shared: one parent grows the prefix, the rest fork it.
    shared := newTestManager(t, bs, 256, nil)
    root := shared.NewSequence()
    for j := 0; j < pre; j++ {
        if err := root.Append(uint64(j)); err != nil {
            t.Fatal(err)
        }
    }
    for i := 0; i < nKids; i++ {
        if _, err := root.Fork(); err != nil {
            t.Fatal(err)
        }
    }
    sharedAllocs := shared.AllocationCount()

    if sharedAllocs >= baseAllocs {
        t.Fatalf("prefix sharing did not help: shared=%d base=%d", sharedAllocs, baseAllocs)
    }
    t.Logf("allocations: shared=%d baseline=%d", sharedAllocs, baseAllocs)
}

// TestRandomizedInterleavings drives random fork/append/release/evict traffic
// and checks invariants plus a leak-free finish.
func TestRandomizedInterleavings(t *testing.T) {
    for seed := int64(0); seed < 40; seed++ {
        rng := rand.New(rand.NewSource(seed))
        m := newTestManager(t, 1+rng.Intn(4), 8, nil)
        var live []*Sequence

        step := func(ok bool, err error) {
            if err != nil && !errors.Is(err, ErrNoBlockAvailable) {
                t.Fatalf("seed=%d unexpected err: %v", seed, err)
            }
            if err := m.CheckInvariants(); err != nil {
                t.Fatalf("seed=%d invariant: %v", seed, err)
            }
        }

        for i := 0; i < 400; i++ {
            if len(live) == 0 || rng.Intn(4) == 0 {
                s := m.NewSequence()
                if rng.Intn(3) > 0 {
                    err := s.Append(randVals(rng, 1+rng.Intn(6))...)
                    step(true, err)
                    if err == nil {
                        live = append(live, s)
                    } else {
                        s.Release()
                    }
                } else {
                    live = append(live, s)
                }
                continue
            }
            k := rng.Intn(len(live))
            s := live[k]
            switch rng.Intn(3) {
            case 0:
                err := s.Append(randVals(rng, 1+rng.Intn(6))...)
                step(true, err)
            case 1:
                c, err := s.Fork()
                if err != nil {
                    t.Fatalf("seed=%d fork: %v", seed, err)
                }
                live = append(live, c)
            case 2:
                s.Release()
                live = append(live[:k], live[k+1:]...)
            }
        }

        for _, s := range live {
            s.Release()
        }
        if err := m.CheckInvariants(); err != nil {
            t.Fatalf("seed=%d final invariant: %v", seed, err)
        }
        if m.TotalRefs() != 0 || m.InUse() != 0 {
            t.Fatalf("seed=%d leak: totalRefs=%d inUse=%d", seed, m.TotalRefs(), m.InUse())
        }
        // Every token of every surviving table mapped to a valid block.
        for _, s := range live {
            if len(s.Table()) != 0 || s.Len() != 0 {
                t.Fatalf("seed=%d released sequence retained state", seed)
            }
        }
    }
}

// TestFailClosedRollsBackPartialReservation exercises the case where a COW plus
// a new block are both required but the pool can only satisfy the first
// reservation: the partial reservation must be rolled back and the table left
// untouched.
func TestFailClosedRollsBackPartialReservation(t *testing.T) {
    m := newTestManager(t, 2, 3, nil)

    parent := m.NewSequence()
    mustAppend(t, parent, 1) // block0 partial, tokens=1
    child, err := parent.Fork()
    if err != nil {
        t.Fatal(err)
    }

    // Pin one more block so only a single evictable block remains.
    pinner := m.NewSequence()
    mustAppend(t, pinner, 5)

    shared := parent.Table()[0]
    before := child.Table()

    // Needs COW (block0 shared) + one new block, but only one block is free.
    if err := child.Append(2, 3); !errors.Is(err, ErrNoBlockAvailable) {
        t.Fatalf("err=%v, want ErrNoBlockAvailable", err)
    }
    if child.Len() != 1 {
        t.Fatalf("child len=%d, want 1", child.Len())
    }
    if len(child.Table()) != 1 || child.Table()[0] != shared {
        t.Fatalf("child table changed after failed append: %v", child.Table())
    }
    if m.RefCount(shared) != 2 {
        t.Fatalf("shared refcount=%d, want 2", m.RefCount(shared))
    }
    if m.RefCount(2) != 0 {
        t.Fatalf("partial reservation leaked: block2 refcount=%d", m.RefCount(2))
    }
    if !reflect.DeepEqual(before, child.Table()) {
        t.Fatalf("table mutated: before=%v after=%v", before, child.Table())
    }
    if err := m.CheckInvariants(); err != nil {
        t.Fatal(err)
    }

    // Once the parent releases its reference, the COW append fits.
    parent.Release()
    if err := child.Append(2, 3); err != nil {
        t.Fatalf("append after room: %v", err)
    }
    mustToken(t, child, 1, 2)
    mustToken(t, child, 2, 3)
    child.Release()
    pinner.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

func randVals(rng *rand.Rand, n int) []uint64 {
    v := make([]uint64, n)
    for i := range v {
        v[i] = uint64(rng.Intn(1 << 20))
    }
    return v
}

// TestEveryTokenMapsToValidBlock stress-checks token->block resolution.
func TestEveryTokenMapsToValidBlock(t *testing.T) {
    m := newTestManager(t, 3, 32, nil)
    root := m.NewSequence()
    for i := 0; i < 7; i++ {
        mustAppend(t, root, uint64(i))
    }
    kids := []*Sequence{root}
    for i := 0; i < 4; i++ {
        c, err := kids[len(kids)-1].Fork()
        if err != nil {
            t.Fatal(err)
        }
        kids = append(kids, c)
    }
    for _, s := range kids {
        for pos := 0; pos < s.Len(); pos++ {
            id, err := s.BlockForToken(pos)
            if err != nil {
                t.Fatalf("seq %d pos %d: %v", s.ID(), pos, err)
            }
            if m.RefCount(id) < 1 {
                t.Fatalf("seq %d pos %d -> unreferenced block %d", s.ID(), pos, id)
            }
            mustToken(t, s, pos, uint64(pos))
        }
    }
    if err := m.CheckInvariants(); err != nil {
        t.Fatal(err)
    }
    for _, s := range kids {
        s.Release()
    }
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

Verification

Run from the module directory:

go vet ./...
go test -race -count=1 -v ./...

Observed result (Go 1.26, -race):

=== RUN   TestAppendPartialBlockGrowth
--- PASS: TestAppendPartialBlockGrowth (0.00s)
=== RUN   TestCopyOnWriteSharedTail
--- PASS: TestCopyOnWriteSharedTail (0.00s)
=== RUN   TestSharedFullBlockNoCow
--- PASS: TestSharedFullBlockNoCow (0.00s)
=== RUN   TestLRUEvictionAndRecomputeHook
--- PASS: TestLRUEvictionAndRecomputeHook (0.00s)
=== RUN   TestFailClosedOnExhaustion
--- PASS: TestFailClosedOnExhaustion (0.00s)
=== RUN   TestForkSavesAllocations
    manager_test.go:237: allocations: shared=3 baseline=15
--- PASS: TestForkSavesAllocations (0.00s)
=== RUN   TestRandomizedInterleavings
--- PASS: TestRandomizedInterleavings (0.01s)
=== RUN   TestFailClosedRollsBackPartialReservation
--- PASS: TestFailClosedRollsBackPartialReservation (0.00s)
=== RUN   TestEveryTokenMapsToValidBlock
--- PASS: TestEveryTokenMapsToValidBlock (0.00s)
PASS
ok      example.com/kvblock 0.008s

What each required property is proven by:

Requirement Test
Partial tail block keeps accepting tokens; new block only on spill TestAppendPartialBlockGrowth
COW clones a shared partial tail; parent unaffected; shared refcount returns to 1 TestCopyOnWriteSharedTail
Full shared block is not needlessly copied TestSharedFullBlockNoCow
LRU picks the oldest cached block; recompute hook receives its prefix payload TestLRUEvictionAndRecomputeHook
Typed ErrNoBlockAvailable, existing table unchanged, no partial reservation leak TestFailClosedOnExhaustion, TestFailClosedRollsBackPartialReservation
Prefix sharing allocates strictly fewer blocks than no-fork baseline (3 vs 15) TestForkSavesAllocations
Random fork/append/free/evict: invariants hold after every op; TotalRefs()==0/InUse()==0 at the end (no leaks) TestRandomizedInterleavings (40 seeds × 400 ops)
Every token index maps to a referenced, in-range physical block TestEveryTokenMapsToValidBlock + CheckInvariants in every test

The randomized suite additionally asserts CheckInvariants after each mutation, so any transient refcount or table-coverage corruption fails immediately rather than only at the end.

Evidence & signatures

# Evidence
- Problem class: go-paged-kv-cache-block-manager-cow-prefix-share
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-12T16:39:27.231Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a vLLM-style paged KV-cache block manager in Go for a transformer inference server: a fixed pool of physical blocks (given a block size in tokens and total block count), one block table per sequence, and append-only token growth that allocates and appends blocks while the last partial block keeps accepting tokens. Support sequence forking/sharing (beam search, parallel sampling) where the child's block table shares prefix blocks copy-on-write with reference counts, so any append to a shared final block must allocate a fresh block and clone only when refcount > 1, and freeing a sequence must decrement and never release a block still referenced elsewhere. Add eviction under pool exhaustion (LRU by last-touch logical time, with a recompute hook for the evicted prefix) and make allocation fail closed with a typed error instead of corrupting an existing table when no block can be evicted. Prove it with table-driven tests asserting refcounts return to zero and no physical block leaks after randomized fork/append/free/evict interleavings, that prefix sharing actually saves block allocations versus no-fork baselines, and that every token index maps to a valid physical block at all times.", "environment": "go1.26", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-paged-kv-cache-block-manager-cow-prefix-share", "provider": "openrouter", "solved_at": "2026-09-12T16:39:27.231Z", "version": "1.26"}

Answer 2

The complete solution is written to ~/kvcache/SOLUTION.md, with the verified code in ~/kvcache/manager.go and ~/kvcache/manager_test.go. Here is the solution.


vLLM-style Paged KV-Cache Block Manager — Diagnosis & Fix

Problem

Implement a fixed-pool paged KV-cache block manager in Go with:

Root-cause analysis

A naive implementation fails in five independent ways. Each maps to a concrete bug the fix must prevent:

  1. Immediate free on release. Treating a block as free as soon as one sequence releases it destroys prefix blocks still used by forks. Cause: no per-block reference count. Fix: reference-count every physical block; release only decrements and the block becomes evictable at zero.
  2. No COW on a shared partial tail. Appending into a partially filled tail that is shared by a fork mutates the parent (and every sibling). Cause: writes go straight into the current physical block. Fix: if the write lands in a shared tail (refs > 1), reserve a fresh block, copy the payload, swap the table slot, and drop the old reference. A full shared block needs no COW because the next token starts a new block.
  3. Mutate-then-allocate. Allocating the COW block first, then failing to allocate an additional block, leaves the table half-rewritten. Cause: allocation happens piecemeal inside the commit. Fix: compute the full reservation set up front (COW block + missing tail blocks), reserve all of it, and roll back reservations if any allocation fails — so the table is never touched on ErrNoBlockAvailable.
  4. Arbitrary / non-deterministic eviction. Picking any refcount-zero block (or a free-list pop) gives no temporal locality and no recompute signal. Cause: no recency metadata. Fix: assign a monotonic logical clock, touch blocks on every reference/append, and reclaim the minimum-lastTouch refcount-zero block; invoke the recompute hook with a copy of its payload before scrubbing.
  5. Silent exhaustion. Returning a sentinel -1/nil or reusing a referenced block corrupts live tables. Cause: no typed error path. Fix: ErrNoBlockAvailable when no refcount-zero block exists, and an explicit rollback path.

An invariant checker (CheckInvariants) recomputes every refcount and the block coverage of every live sequence from scratch, which is what catches classes 1–3 during randomized testing.

The fix

Module example.com/kvblock. Two files: manager.go and manager_test.go.

manager.go

// Package kvblock implements a vLLM-style paged KV-cache block manager.
//
// A fixed pool of physical blocks (numBlocks, each holding blockSize tokens)
// is shared by many sequences. Every sequence owns a block table mapping
// logical block index -> physical BlockID. Appends grow the table; a partially
// filled final block keeps accepting tokens. Forked sequences share prefix
// blocks copy-on-write (COW) via reference counts. Blocks whose refcount drops
// to zero become cached/evictable and are recycled LRU-first when the pool is
// exhausted; if nothing is evictable the allocation fails closed with
// ErrNoBlockAvailable and leaves the caller's table untouched.
package kvblock

import (
    "errors"
    "fmt"
)

// BlockID identifies a physical block in the manager's pool.
type BlockID int

var (
    // ErrNoBlockAvailable is returned when the pool is exhausted and no
    // evictable (refcount == 0) block exists. Allocation fails closed: the
    // caller's block table is left exactly as it was.
    ErrNoBlockAvailable = errors.New("kvblock: pool exhausted: no evictable block available")
    // ErrInvalidBlockID is returned for out-of-range block identifiers.
    ErrInvalidBlockID = errors.New("kvblock: invalid physical block id")
    // ErrSequenceReleased is returned when operating on a released sequence.
    ErrSequenceReleased = errors.New("kvblock: sequence has been released")
    // ErrInvalidPosition is returned for an out-of-range token index.
    ErrInvalidPosition = errors.New("kvblock: token position out of range")
    // ErrInvalidGeometry is returned by NewManager for non-positive sizes.
    ErrInvalidGeometry = errors.New("kvblock: blockSize and numBlocks must be positive")
)

// EvictHook is invoked when a cached block (refcount == 0 but still holding a
// valid payload) is evicted to make room for a new allocation. It receives the
// evicted block id and a private copy of its token payload so the caller can
// schedule recomputation of that prefix.
type EvictHook func(block BlockID, tokens []uint64)

type block struct {
    id        BlockID
    refs      int
    lastTouch int64
    valid     bool // payload is meaningful and may be cached
    data      []uint64
}

// Manager owns the fixed physical block pool and all live sequences.
type Manager struct {
    blockSize int
    numBlocks int
    blocks    []block
    clock     int64
    allocs    int64
    evictions int64
    seqs      map[int]*Sequence
    nextSeqID int
    onEvict   EvictHook
}

// NewManager builds a pool of numBlocks physical blocks each holding
// blockSize tokens. onEvict may be nil.
func NewManager(blockSize, numBlocks int, onEvict EvictHook) (*Manager, error) {
    if blockSize <= 0 || numBlocks <= 0 {
        return nil, ErrInvalidGeometry
    }
    m := &Manager{
        blockSize: blockSize,
        numBlocks: numBlocks,
        blocks:    make([]block, numBlocks),
        seqs:      make(map[int]*Sequence),
        onEvict:   onEvict,
    }
    for i := range m.blocks {
        m.blocks[i] = block{id: BlockID(i), data: make([]uint64, blockSize)}
    }
    return m, nil
}

func (m *Manager) tick() int64 { m.clock++; return m.clock }

// BlockSize reports the token capacity of one physical block.
func (m *Manager) BlockSize() int { return m.blockSize }

// NumBlocks reports the total number of physical blocks in the pool.
func (m *Manager) NumBlocks() int { return m.numBlocks }

// AllocationCount is the cumulative number of physical block reservations.
func (m *Manager) AllocationCount() int64 { return m.allocs }

// EvictionCount is the cumulative number of cached blocks reclaimed for reuse.
func (m *Manager) EvictionCount() int64 { return m.evictions }

// RefCount returns the live reference count of a physical block.
func (m *Manager) RefCount(id BlockID) int {
    if id < 0 || int(id) >= m.numBlocks {
        return -1
    }
    return m.blocks[id].refs
}

// InUse is the number of physical blocks currently referenced by sequences.
func (m *Manager) InUse() int {
    n := 0
    for i := range m.blocks {
        if m.blocks[i].refs > 0 {
            n++
        }
    }
    return n
}

// TotalRefs is the sum of every physical block's reference count. After all
// sequences have been released this must be zero for a leak-free run.
func (m *Manager) TotalRefs() int {
    n := 0
    for i := range m.blocks {
        n += m.blocks[i].refs
    }
    return n
}

// alloc reserves one physical block with refcount 1. It prefers the least
// recently touched evictable block. With no evictable block it returns
// ErrNoBlockAvailable without mutating anything.
func (m *Manager) alloc() (BlockID, error) {
    best := BlockID(-1)
    for i := range m.blocks {
        b := &m.blocks[i]
        if b.refs != 0 {
            continue
        }
        if best == -1 || b.lastTouch < m.blocks[best].lastTouch {
            best = b.id
        }
    }
    if best == -1 {
        return -1, ErrNoBlockAvailable
    }
    b := &m.blocks[best]
    if b.valid {
        m.evictions++
        if m.onEvict != nil {
            cp := make([]uint64, len(b.data))
            copy(cp, b.data)
            m.onEvict(best, cp)
        }
    }
    for i := range b.data {
        b.data[i] = 0
    }
    b.valid = false
    b.refs = 1
    b.lastTouch = m.tick()
    m.allocs++
    return best, nil
}

// releaseBlock drops one reference; the block is never freed while another
// sequence still holds a reference. At zero references the block becomes
// evictable (its payload stays cached until reclaimed).
func (m *Manager) releaseBlock(id BlockID) {
    b := &m.blocks[id]
    if b.refs <= 0 {
        return
    }
    b.refs--
    if b.refs == 0 {
        b.lastTouch = m.tick()
    }
}

// Sequence is one logical request's block table plus token length.
type Sequence struct {
    m        *Manager
    id       int
    table    []BlockID
    tokens   int
    released bool
}

// NewSequence creates an empty sequence with no blocks.
func (m *Manager) NewSequence() *Sequence {
    s := &Sequence{m: m, id: m.nextSeqID}
    m.nextSeqID++
    m.seqs[s.id] = s
    return s
}

// ID is the manager-unique sequence identifier.
func (s *Sequence) ID() int { return s.id }

// Len is the number of tokens currently held by the sequence.
func (s *Sequence) Len() int { return s.tokens }

// Released reports whether Release has been called.
func (s *Sequence) Released() bool { return s.released }

// Table returns a copy of the logical -> physical block mapping.
func (s *Sequence) Table() []BlockID {
    return append([]BlockID(nil), s.table...)
}

// Fork creates a child sharing the parent's entire prefix block table COW.
// Every shared block's reference count is incremented.
func (s *Sequence) Fork() (*Sequence, error) {
    if s.released {
        return nil, ErrSequenceReleased
    }
    child := &Sequence{
        m:      s.m,
        id:     s.m.nextSeqID,
        tokens: s.tokens,
        table:  append([]BlockID(nil), s.table...),
    }
    s.m.nextSeqID++
    for _, id := range s.table {
        s.m.blocks[id].refs++
        s.m.blocks[id].lastTouch = s.m.tick()
    }
    s.m.seqs[child.id] = child
    return child, nil
}

// Append grows the sequence by len(vals) tokens, allocating and appending
// blocks as needed. If the write lands in a shared partial final block it is
// copied-on-write so the other sharers are never mutated. All required blocks
// are reserved before any state changes, so a pool-exhaustion error leaves the
// table exactly as it was (fail closed).
func (s *Sequence) Append(vals ...uint64) error {
    if s.released {
        return ErrSequenceReleased
    }
    if len(vals) == 0 {
        return nil
    }
    m := s.m
    bs := m.blockSize
    start := s.tokens
    end := start + len(vals)
    needBlocks := (end + bs - 1) / bs

    // Will the first appended token overwrite a shared partial tail?
    lastShared := false
    if start%bs != 0 && len(s.table) > 0 {
        last := s.table[len(s.table)-1]
        if m.blocks[last].refs > 1 {
            lastShared = true
        }
    }

    missing := needBlocks - len(s.table)
    if missing < 0 {
        missing = 0
    }
    reserve := missing
    if lastShared {
        reserve++
    }

    // Reserve everything up front; roll back cleanly on exhaustion.
    reserved := make([]BlockID, 0, reserve)
    for i := 0; i < reserve; i++ {
        id, err := m.alloc()
        if err != nil {
            for _, r := range reserved {
                m.releaseBlock(r)
            }
            return err
        }
        reserved = append(reserved, id)
    }

    // Commit (cannot fail from here on).
    idx := 0
    if lastShared {
        old := s.table[len(s.table)-1]
        nb := reserved[idx]
        idx++
        copy(m.blocks[nb].data, m.blocks[old].data)
        m.blocks[nb].valid = m.blocks[old].valid
        s.table[len(s.table)-1] = nb
        m.releaseBlock(old)
    }
    for len(s.table) < needBlocks {
        s.table = append(s.table, reserved[idx])
        idx++
    }

    for i, v := range vals {
        pos := start + i
        b := &m.blocks[s.table[pos/bs]]
        b.data[pos%bs] = v
        b.valid = true
        b.lastTouch = m.tick()
    }
    s.tokens = end
    return nil
}

// BlockForToken returns the physical block backing a token index.
func (s *Sequence) BlockForToken(pos int) (BlockID, error) {
    if s.released {
        return -1, ErrSequenceReleased
    }
    if pos < 0 || pos >= s.tokens {
        return -1, ErrInvalidPosition
    }
    return s.table[pos/s.m.blockSize], nil
}

// TokenAt returns the value stored at a token index.
func (s *Sequence) TokenAt(pos int) (uint64, error) {
    id, err := s.BlockForToken(pos)
    if err != nil {
        return 0, err
    }
    return s.m.blocks[id].data[pos%s.m.blockSize], nil
}

// Release drops every reference held by the sequence. Reference counts only
// decrement; a block is never destroyed while another sequence still uses it.
func (s *Sequence) Release() {
    if s.released {
        return
    }
    s.released = true
    for _, id := range s.table {
        s.m.releaseBlock(id)
    }
    s.table = nil
    s.tokens = 0
    delete(s.m.seqs, s.id)
}

// CheckInvariants recomputes every live sequence's block coverage and every
// physical refcount from scratch and compares them to stored state. It returns
// the first inconsistency found, or nil when the manager is consistent.
func (m *Manager) CheckInvariants() error {
    want := make([]int, m.numBlocks)
    for _, s := range m.seqs {
        if s.released {
            return fmt.Errorf("kvblock: released sequence %d still registered", s.id)
        }
        expectBlocks := (s.tokens + m.blockSize - 1) / m.blockSize
        if len(s.table) != expectBlocks {
            return fmt.Errorf("kvblock: seq %d has %d tokens, %d blocks, want %d",
                s.id, s.tokens, len(s.table), expectBlocks)
        }
        for i, id := range s.table {
            if id < 0 || int(id) >= m.numBlocks {
                return fmt.Errorf("kvblock: seq %d block slot %d invalid id %d", s.id, i, id)
            }
            want[id]++
        }
    }
    for i := range m.blocks {
        if m.blocks[i].refs != want[i] {
            return fmt.Errorf("kvblock: block %d refcount=%d, want %d",
                i, m.blocks[i].refs, want[i])
        }
    }
    return nil
}

manager_test.go

package kvblock

import (
    "errors"
    "math/rand"
    "reflect"
    "testing"
)

func newTestManager(t *testing.T, bs, nb int, hook EvictHook) *Manager {
    t.Helper()
    m, err := NewManager(bs, nb, hook)
    if err != nil {
        t.Fatalf("NewManager: %v", err)
    }
    return m
}

func mustAppend(t *testing.T, s *Sequence, vals ...uint64) {
    t.Helper()
    if err := s.Append(vals...); err != nil {
        t.Fatalf("append: %v", err)
    }
}

func mustToken(t *testing.T, s *Sequence, pos int, want uint64) {
    t.Helper()
    got, err := s.TokenAt(pos)
    if err != nil {
        t.Fatalf("TokenAt(%d): %v", pos, err)
    }
    if got != want {
        t.Fatalf("TokenAt(%d)=%d, want %d", pos, got, want)
    }
}

// TestAppendPartialBlockGrowth checks that a partial tail block keeps accepting
// tokens before a new physical block is appended.
func TestAppendPartialBlockGrowth(t *testing.T) {
    m := newTestManager(t, 4, 8, nil)
    s := m.NewSequence()
    mustAppend(t, s, 1, 2, 3)
    if s.Len() != 3 || len(s.Table()) != 1 {
        t.Fatalf("after 3 tokens: len=%d blocks=%d", s.Len(), len(s.Table()))
    }
    mustAppend(t, s, 4)
    if len(s.Table()) != 1 {
        t.Fatalf("filling partial block must not allocate: blocks=%d", len(s.Table()))
    }
    mustAppend(t, s, 5)
    if len(s.Table()) != 2 {
        t.Fatalf("spilling over must allocate: blocks=%d", len(s.Table()))
    }
    for i := 0; i < 5; i++ {
        mustToken(t, s, i, uint64(i+1))
    }
    if err := m.CheckInvariants(); err != nil {
        t.Fatal(err)
    }
    s.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak after release: total refs %d", m.TotalRefs())
    }
}

// TestCopyOnWriteSharedTail asserts that appending into a shared partial final
// block clones it, leaving the parent untouched and refcounts balanced.
func TestCopyOnWriteSharedTail(t *testing.T) {
    m := newTestManager(t, 4, 8, nil)
    parent := m.NewSequence()
    mustAppend(t, parent, 10, 20, 30)

    child, err := parent.Fork()
    if err != nil {
        t.Fatal(err)
    }
    shared := parent.Table()[0]
    if m.RefCount(shared) != 2 {
        t.Fatalf("shared refcount=%d, want 2", m.RefCount(shared))
    }

    // Child writes the 4th token into the shared partial block -> COW.
    mustAppend(t, child, 40)
    if m.RefCount(shared) != 1 {
        t.Fatalf("after COW parent refcount=%d, want 1", m.RefCount(shared))
    }
    if child.Table()[0] == parent.Table()[0] {
        t.Fatal("child still points at shared block after COW")
    }
    mustToken(t, child, 3, 40)
    if _, err := parent.TokenAt(3); !errors.Is(err, ErrInvalidPosition) {
        t.Fatalf("parent sees child token: %v", err)
    }
    mustToken(t, parent, 2, 30)
    if err := m.CheckInvariants(); err != nil {
        t.Fatal(err)
    }

    parent.Release()
    child.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

// TestSharedFullBlockNoCow asserts a full shared block is not cloned when the
// append starts a fresh logical block.
func TestSharedFullBlockNoCow(t *testing.T) {
    m := newTestManager(t, 2, 8, nil)
    parent := m.NewSequence()
    mustAppend(t, parent, 1, 2) // full block
    child, _ := parent.Fork()

    mustAppend(t, child, 3) // starts block 1, no COW of block 0
    if m.RefCount(parent.Table()[0]) != 2 {
        t.Fatalf("full shared block refcount=%d, want 2", m.RefCount(parent.Table()[0]))
    }
    if child.Table()[0] != parent.Table()[0] {
        t.Fatal("unexpected COW of a full shared block")
    }
    parent.Release()
    child.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

// TestLRUEvictionAndRecomputeHook verifies the least recently touched cached
// block is reclaimed first and the hook sees its payload.
func TestLRUEvictionAndRecomputeHook(t *testing.T) {
    type ev struct {
        id     BlockID
        tokens []uint64
    }
    var evicted []ev
    m := newTestManager(t, 1, 2, func(id BlockID, tok []uint64) {
        evicted = append(evicted, ev{id, tok})
    })
    s1 := m.NewSequence()
    mustAppend(t, s1, 100, 200) // block0=100 (older), block1=200 (newer)
    s1.Release()                // both cached; block0 has smaller lastTouch

    s2 := m.NewSequence()
    mustAppend(t, s2, 999) // must evict LRU cached block
    if len(evicted) != 1 {
        t.Fatalf("hook calls=%d, want 1", len(evicted))
    }
    if evicted[0].id != 0 {
        t.Fatalf("evicted block %d, want LRU block 0", evicted[0].id)
    }
    if len(evicted[0].tokens) != 1 || evicted[0].tokens[0] != 100 {
        t.Fatalf("evicted payload=%v, want [100]", evicted[0].tokens)
    }
    if m.EvictionCount() != 1 {
        t.Fatalf("eviction count=%d, want 1", m.EvictionCount())
    }
    s2.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

// TestFailClosedOnExhaustion checks allocation returns the typed error and
// never corrupts an existing table.
func TestFailClosedOnExhaustion(t *testing.T) {
    m := newTestManager(t, 1, 2, nil)
    s1 := m.NewSequence()
    mustAppend(t, s1, 7, 8)

    s2 := m.NewSequence()
    if err := s2.Append(9); !errors.Is(err, ErrNoBlockAvailable) {
        t.Fatalf("err=%v, want ErrNoBlockAvailable", err)
    }
    if s2.Len() != 0 || len(s2.Table()) != 0 {
        t.Fatalf("failed append mutated table: len=%d blocks=%d", s2.Len(), len(s2.Table()))
    }
    mustToken(t, s1, 0, 7)
    mustToken(t, s1, 1, 8)
    if s1.Len() != 2 {
        t.Fatalf("existing sequence changed: len=%d", s1.Len())
    }
    if err := m.CheckInvariants(); err != nil {
        t.Fatal(err)
    }

    // Releasing the blocker makes room.
    s1.Release()
    if err := s2.Append(9); err != nil {
        t.Fatalf("append after release: %v", err)
    }
    mustToken(t, s2, 0, 9)
    s2.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

// TestForkSavesAllocations measures that prefix sharing allocates strictly
// fewer physical blocks than independent construction.
func TestForkSavesAllocations(t *testing.T) {
    const (
        bs    = 4
        pre   = 10 // 3 blocks
        nKids = 5
    )

    // Baseline: every sequence grows the prefix itself.
    base := newTestManager(t, bs, 256, nil)
    for i := 0; i < nKids; i++ {
        s := base.NewSequence()
        for j := 0; j < pre; j++ {
            if err := s.Append(uint64(j)); err != nil {
                t.Fatal(err)
            }
        }
    }
    baseAllocs := base.AllocationCount()

    // Shared: one parent grows the prefix, the rest fork it.
    shared := newTestManager(t, bs, 256, nil)
    root := shared.NewSequence()
    for j := 0; j < pre; j++ {
        if err := root.Append(uint64(j)); err != nil {
            t.Fatal(err)
        }
    }
    for i := 0; i < nKids; i++ {
        if _, err := root.Fork(); err != nil {
            t.Fatal(err)
        }
    }
    sharedAllocs := shared.AllocationCount()

    if sharedAllocs >= baseAllocs {
        t.Fatalf("prefix sharing did not help: shared=%d base=%d", sharedAllocs, baseAllocs)
    }
    t.Logf("allocations: shared=%d baseline=%d", sharedAllocs, baseAllocs)
}

// TestRandomizedInterleavings drives random fork/append/release/evict traffic
// and checks invariants plus a leak-free finish.
func TestRandomizedInterleavings(t *testing.T) {
    for seed := int64(0); seed < 40; seed++ {
        rng := rand.New(rand.NewSource(seed))
        m := newTestManager(t, 1+rng.Intn(4), 8, nil)
        var live []*Sequence

        step := func(ok bool, err error) {
            if err != nil && !errors.Is(err, ErrNoBlockAvailable) {
                t.Fatalf("seed=%d unexpected err: %v", seed, err)
            }
            if err := m.CheckInvariants(); err != nil {
                t.Fatalf("seed=%d invariant: %v", seed, err)
            }
        }

        for i := 0; i < 400; i++ {
            if len(live) == 0 || rng.Intn(4) == 0 {
                s := m.NewSequence()
                if rng.Intn(3) > 0 {
                    err := s.Append(randVals(rng, 1+rng.Intn(6))...)
                    step(true, err)
                    if err == nil {
                        live = append(live, s)
                    } else {
                        s.Release()
                    }
                } else {
                    live = append(live, s)
                }
                continue
            }
            k := rng.Intn(len(live))
            s := live[k]
            switch rng.Intn(3) {
            case 0:
                err := s.Append(randVals(rng, 1+rng.Intn(6))...)
                step(true, err)
            case 1:
                c, err := s.Fork()
                if err != nil {
                    t.Fatalf("seed=%d fork: %v", seed, err)
                }
                live = append(live, c)
            case 2:
                s.Release()
                live = append(live[:k], live[k+1:]...)
            }
        }

        for _, s := range live {
            s.Release()
        }
        if err := m.CheckInvariants(); err != nil {
            t.Fatalf("seed=%d final invariant: %v", seed, err)
        }
        if m.TotalRefs() != 0 || m.InUse() != 0 {
            t.Fatalf("seed=%d leak: totalRefs=%d inUse=%d", seed, m.TotalRefs(), m.InUse())
        }
        // Every token of every surviving table mapped to a valid block.
        for _, s := range live {
            if len(s.Table()) != 0 || s.Len() != 0 {
                t.Fatalf("seed=%d released sequence retained state", seed)
            }
        }
    }
}

// TestFailClosedRollsBackPartialReservation exercises the case where a COW plus
// a new block are both required but the pool can only satisfy the first
// reservation: the partial reservation must be rolled back and the table left
// untouched.
func TestFailClosedRollsBackPartialReservation(t *testing.T) {
    m := newTestManager(t, 2, 3, nil)

    parent := m.NewSequence()
    mustAppend(t, parent, 1) // block0 partial, tokens=1
    child, err := parent.Fork()
    if err != nil {
        t.Fatal(err)
    }

    // Pin one more block so only a single evictable block remains.
    pinner := m.NewSequence()
    mustAppend(t, pinner, 5)

    shared := parent.Table()[0]
    before := child.Table()

    // Needs COW (block0 shared) + one new block, but only one block is free.
    if err := child.Append(2, 3); !errors.Is(err, ErrNoBlockAvailable) {
        t.Fatalf("err=%v, want ErrNoBlockAvailable", err)
    }
    if child.Len() != 1 {
        t.Fatalf("child len=%d, want 1", child.Len())
    }
    if len(child.Table()) != 1 || child.Table()[0] != shared {
        t.Fatalf("child table changed after failed append: %v", child.Table())
    }
    if m.RefCount(shared) != 2 {
        t.Fatalf("shared refcount=%d, want 2", m.RefCount(shared))
    }
    if m.RefCount(2) != 0 {
        t.Fatalf("partial reservation leaked: block2 refcount=%d", m.RefCount(2))
    }
    if !reflect.DeepEqual(before, child.Table()) {
        t.Fatalf("table mutated: before=%v after=%v", before, child.Table())
    }
    if err := m.CheckInvariants(); err != nil {
        t.Fatal(err)
    }

    // Once the parent releases its reference, the COW append fits.
    parent.Release()
    if err := child.Append(2, 3); err != nil {
        t.Fatalf("append after room: %v", err)
    }
    mustToken(t, child, 1, 2)
    mustToken(t, child, 2, 3)
    child.Release()
    pinner.Release()
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

func randVals(rng *rand.Rand, n int) []uint64 {
    v := make([]uint64, n)
    for i := range v {
        v[i] = uint64(rng.Intn(1 << 20))
    }
    return v
}

// TestEveryTokenMapsToValidBlock stress-checks token->block resolution.
func TestEveryTokenMapsToValidBlock(t *testing.T) {
    m := newTestManager(t, 3, 32, nil)
    root := m.NewSequence()
    for i := 0; i < 7; i++ {
        mustAppend(t, root, uint64(i))
    }
    kids := []*Sequence{root}
    for i := 0; i < 4; i++ {
        c, err := kids[len(kids)-1].Fork()
        if err != nil {
            t.Fatal(err)
        }
        kids = append(kids, c)
    }
    for _, s := range kids {
        for pos := 0; pos < s.Len(); pos++ {
            id, err := s.BlockForToken(pos)
            if err != nil {
                t.Fatalf("seq %d pos %d: %v", s.ID(), pos, err)
            }
            if m.RefCount(id) < 1 {
                t.Fatalf("seq %d pos %d -> unreferenced block %d", s.ID(), pos, id)
            }
            mustToken(t, s, pos, uint64(pos))
        }
    }
    if err := m.CheckInvariants(); err != nil {
        t.Fatal(err)
    }
    for _, s := range kids {
        s.Release()
    }
    if m.TotalRefs() != 0 {
        t.Fatalf("leak: total refs %d", m.TotalRefs())
    }
}

Verification

Run from the module directory:

go vet ./...
go test -race -count=1 -v ./...

Observed result (Go 1.26, -race):

=== RUN   TestAppendPartialBlockGrowth
--- PASS: TestAppendPartialBlockGrowth (0.00s)
=== RUN   TestCopyOnWriteSharedTail
--- PASS: TestCopyOnWriteSharedTail (0.00s)
=== RUN   TestSharedFullBlockNoCow
--- PASS: TestSharedFullBlockNoCow (0.00s)
=== RUN   TestLRUEvictionAndRecomputeHook
--- PASS: TestLRUEvictionAndRecomputeHook (0.00s)
=== RUN   TestFailClosedOnExhaustion
--- PASS: TestFailClosedOnExhaustion (0.00s)
=== RUN   TestForkSavesAllocations
    manager_test.go:237: allocations: shared=3 baseline=15
--- PASS: TestForkSavesAllocations (0.00s)
=== RUN   TestRandomizedInterleavings
--- PASS: TestRandomizedInterleavings (0.01s)
=== RUN   TestFailClosedRollsBackPartialReservation
--- PASS: TestFailClosedRollsBackPartialReservation (0.00s)
=== RUN   TestEveryTokenMapsToValidBlock
--- PASS: TestEveryTokenMapsToValidBlock (0.00s)
PASS
ok      example.com/kvblock 0.008s

What each required property is proven by:

Requirement Test
Partial tail block keeps accepting tokens; new block only on spill TestAppendPartialBlockGrowth
COW clones a shared partial tail; parent unaffected; shared refcount returns to 1 TestCopyOnWriteSharedTail
Full shared block is not needlessly copied TestSharedFullBlockNoCow
LRU picks the oldest cached block; recompute hook receives its prefix payload TestLRUEvictionAndRecomputeHook
Typed ErrNoBlockAvailable, existing table unchanged, no partial reservation leak TestFailClosedOnExhaustion, TestFailClosedRollsBackPartialReservation
Prefix sharing allocates strictly fewer blocks than no-fork baseline (3 vs 15) TestForkSavesAllocations
Random fork/append/free/evict: invariants hold after every op; TotalRefs()==0/InUse()==0 at the end (no leaks) TestRandomizedInterleavings (40 seeds × 400 ops)
Every token index maps to a referenced, in-range physical block TestEveryTokenMapsToValidBlock + CheckInvariants in every test

The randomized suite additionally asserts CheckInvariants after each mutation, so any transient refcount or table-coverage corruption fails immediately rather than only at the end.

Evidence & signatures

# Evidence
- Problem class: go-paged-kv-cache-block-manager-cow-prefix-share
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-12T16:39:27.231Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a vLLM-style paged KV-cache block manager in Go for a transformer inference server: a fixed pool of physical blocks (given a block size in tokens and total block count), one block table per sequence, and append-only token growth that allocates and appends blocks while the last partial block keeps accepting tokens. Support sequence forking/sharing (beam search, parallel sampling) where the child's block table shares prefix blocks copy-on-write with reference counts, so any append to a shared final block must allocate a fresh block and clone only when refcount > 1, and freeing a sequence must decrement and never release a block still referenced elsewhere. Add eviction under pool exhaustion (LRU by last-touch logical time, with a recompute hook for the evicted prefix) and make allocation fail closed with a typed error instead of corrupting an existing table when no block can be evicted. Prove it with table-driven tests asserting refcounts return to zero and no physical block leaks after randomized fork/append/free/evict interleavings, that prefix sharing actually saves block allocations versus no-fork baselines, and that every token index maps to a valid physical block at all times.", "environment": "go1.26", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-paged-kv-cache-block-manager-cow-prefix-share", "provider": "openrouter", "solved_at": "2026-09-12T16:39:27.231Z", "version": "1.26"}
Generated from the verified corpus · MIT licensedBack to the catalog