Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/skade

.nornir/read-path-guide.md

The read path — guide

Class: guide · Function: read-path. The what is in read-path-design.md; the why in read-path-reasoning.md.

Pick the lightest read that answers your question

The caches are transparent — you never call them directly — but which catalog method you call decides how much work a warm hit does:

you need call warm hit does
"does this table exist?" table_exists(&ident) one L1 mirror lookup, no lock, no redb
the current metadata location resolve_metadata(&ident) then .metadata_location path L1 mirror
schema / snapshots / props resolve_metadata(&ident) L1 → L0 (Arc clone)
a full Table to scan load_table(&ident) L1 → L1.5 (Table clone)

Rule of thumb: don't call load_table if resolve_metadata answers you. Building a Table constructs iceberg's per-Table object cache; the handle cache amortises it, but resolving metadata skips it entirely.

Sizing the caches

Set budgets at build time (builder-guide):

RedbCatalogBuilder::default()
    .metadata_cache_bytes(256 * 1024 * 1024)   // L0: 256 MiB of parsed metadata
    .table_handle_cache_bytes(512 * 1024 * 1024) // L1.5: byte budget for resident Table handles
    // …

What you never have to worry about

There is no cache invalidation to call, no TTL to tune, no staleness window. Because each entry is keyed by its immutable metadata location, a commit that changes a table writes a new file at a new key — the old entry is simply never looked up again and eventually evicted. Reads after a commit see the new pointer immediately via the write-through mirror.