Repository navigation
Layout F: index keys lead with the type; reads and merges bounded - #65
Merged
Merged
Conversation
…unded A leaf's index range was every type's records whose ids fell between its first and last: with Crossref's DOIs, a small type's leaf spans millions of journal-article entries, all read into memory at once. Keys are now (type, id, hash), so a leaf's records are one short range of its type's. Readers pass the tree's type (Leaf.type, RepoSource and RepoSink's type). - An index read takes four layers at a time, newest first, keeps only the keys it wants, and stops once all are found: memory is the keys and a few pages however many runs a large push leaves. - PackReader.lines takes each block's lines as it decodes it, 16 blocks a request at most: a scattered leaf never holds every block it touches. - Merges and reclaim read each input a share of a 16 MB budget (mergeRead). - A reclaim plans only at 32 runs or fewer (TooManyRunsError: merge, retry). - reclaimRewrite merges its packs in key order and writes as it goes. - Sync builds an F leaf's body a member per 256 records; fsck checks F leaves 256 records at a time.
tefkah
added a commit
that referenced
this pull request
Oct 20, 2026
…d entries count toward a writer's runs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An audit of layout F after #63 found where memory still grew with the collection. The worst was leaf reads. Index keys were (id, hash), so a leaf's index range held every type's records whose ids fell between its first and last. With Crossref's DOIs, a small type's leaf spans millions of journal-article entries, and the range was read into memory at once.
This changes F's stored format. Only staging test collections are on F; they'll be recreated.
Changes
recordKey(type, id, hash)), as record-storage-layout.md's candidate E has them. A leaf's records are one short range of its own type's. Readers pass the tree's type:Leaf.typeonRepo.bodyLines/linesAt/entryLine,RepoSource'stype, andRepoSink'stypeper tree (a sink shared by a build is told each tree's type).RecordWriter.add(type, entry, line). F throws if a read has no type.LayeredIndex.values) take four layers at a time, newest first, and keep only the keys wanted. They stop once every key is found. Before, every layer was read at once, which with the hundreds of runs a large push leaves meant 25 to 50 MB a read.PackReader.linestakes each block's lines as it decodes it and lets the block go. A request reads at most 16 blocks, and 8 requests run at once. A leaf scattered over many packs no longer holds every block it touches.mergeRead) instead of 1 MB each. A merge of 128 inputs was 128 MB of reads.TooManyRunsError, and the job queues a maintain and retries in 5 minutes.reclaimRewritemerges its packs in key order and writes as it goes. It had held every moved entry, plus the block text their keys were sliced from, until the end.recordRootsreturns{type, root}).Tests
Memory gate
scripts/memory.ts --layout f --records 400000 --small-every 2000 --read-ms 1 --max-mb 60.--small-everymakes adatasettype spread over the same DOI space;--max-mbfails the run if any job peaks over the cap. Peaks in MB:Both pass. A 1.2M run is going, to check the peaks stay flat.
refs.indexis today's reference index, not F, and is already filed as growing with the collection.Not here
Lists that hold one entry per pack (
registry.read,mirrorFiles, reclaim's bookkeeping) grow with pack count. That's around 100k packs, about 1 TB, before it matters. A follow-up will page them.Deploy
No migration. Both Workers. Recreate the staging F test collections afterwards; ones written before this can't be read.