pk

package
v0.0.15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 19, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package pk provides a lock-free MVCC primary key index.

The PK index maps auto-increment IDs to physical locations (SegmentID, RowID). It supports:

  • Wait-free reads via atomic.Pointer
  • Lock-free writes via CAS loops
  • MVCC for snapshot isolation
  • Time-travel queries

Architecture

The index uses a paged array structure:

Index
├── atomic.Pointer[pages] ────► []*page (growable slice)
│   ├── page[0] ────────────► entries[65536]entry
│   │   └── entry.head ─────► atomic.Pointer[version]
│   │       └── version ────► {lsn, location, deleted, next}
│   ├── page[1]
│   └── ...
├── count atomic.Int64
└── mu sync.RWMutex (for page slice growth only)

IDs are decomposed into (pageIndex, offset) using bit operations:

pageIndex = id >> 16  (65536 entries per page)
offset    = id & 0xFFFF

Concurrency Model

Reads are wait-free: load atomic page pointer, then load entry head. No locks are acquired on the read path.

Writes use CAS loops on the entry's version chain. The page slice is protected by RWMutex only during growth operations. A sync.Pool recycles version structs to minimize allocations during CAS retries.

Version chains are ordered by LSN (highest first). MVCC queries traverse the chain to find the latest version visible to a snapshot.

Persistence

Save() serializes only the HEAD version of each entry (not full history). Load() restores the index from a checkpoint. The binary format uses:

Magic: 0x504B4958 ("PKIX")
Version: 1

Usage

idx := pk.New()
idx.Upsert(id, location, lsn)        // Insert or update
loc, ok := idx.Get(id, snapshotLSN)  // MVCC read
idx.Delete(id, lsn)                  // Tombstone
idx.Scan(snapshotLSN)                // Iterator

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Index

type Index struct {
	// contains filtered or unexported fields
}

Index is a concurrent, paged, MVCC primary key index optimized for sequential IDs. It uses a dynamic array of fixed-size pages to provide O(1) access without hashing overhead.

func New

func New() *Index

New creates a new MVCC Index.

func (*Index) Count

func (idx *Index) Count() int

Count returns approximate number of active keys.

func (*Index) Delete

func (idx *Index) Delete(id model.ID, lsn uint64) (model.Location, bool)

Delete adds a tombstone.

func (*Index) Get

func (idx *Index) Get(id model.ID, snapshotLSN uint64) (model.Location, bool)

Get returns the location valid at the given snapshot LSN.

func (*Index) Load

func (idx *Index) Load(r io.Reader) error

Load restores the index from the writer. It assumes the index is empty.

func (*Index) MaxID

func (idx *Index) MaxID() uint64

MaxID returns the highest ID currently in the index. Used for recovery to initialize the auto-increment counter.

func (*Index) Save

func (idx *Index) Save(w io.Writer) error

Save persists the index specific to the current state (latest versions). It does NOT persist full MVCC history, only the latest version for each key. effectively creating a checkpoint at the current moment.

func (*Index) Scan

func (idx *Index) Scan(snapshotLSN uint64) iter.Seq2[model.ID, model.Location]

Scan returns an iterator over all items visible at snapshotLSN.

func (*Index) Upsert

func (idx *Index) Upsert(id model.ID, loc model.Location, lsn uint64) (model.Location, bool)

Upsert adds a new version and returns the previous active location and true if it existed.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL