Artifact 11e64569ba4d8ed36a1934d89bc5f29e2946b2e36112c198ec8858a801136002:
- File
internal/content/export_test.go
— part of check-in
[1cb9e11a65]
at
2026-10-28 21:26:49
on branch perf/memo-tree-encoding
— perf(content): read the memo's trees with its graph, as interned id sets
The origin classification memo now reads the F cards of every tree in the store once, with its references, and extends them by appended check-ins (draft-fossil-horizon-00 ยง6.2, HZ-6.2-10). Blob names are interned to uint32 ids, each tree's file set is a sorted delta-varint id list, and a full manifest is kept as its symmetric difference from the previous full manifest read, at most 15 links from a piece kept whole, decoded through a 16-entry LRU per view. A store whose index would pass memoTreeBytes keeps none and falls back to the bounded cache of walked trees.
On a clone of fossil-scm.org the trees take 11 MiB (the walked-tree cache held 50 MiB for two horizons), the memo's retained heap halves and peak in-use heap drops from 345-524 MiB to about 170 MiB. Tracked in #463. (user: [email protected], size: 1829) [annotate] [blame] [check-ins using]
package content import ( "context" "maps" "slices" "github.com/danmestas/go-libfossil/db" ) // LoadAbsencesWithin is LoadAbsencesContext under injected budgets, and // reports what classification read. The tests that use it are an external // package: their fixtures need the manifest writer, which imports this one. func LoadAbsencesWithin( ctx context.Context, q db.Querier, refs ReferenceBudget, treePerCheckin int64, ) (*Absences, ReferenceWork, error) { treeMax := treePerCheckin << 10 if treeMax > defaultReferenceLimits.treeMax { treeMax = defaultReferenceLimits.treeMax } a, err := loadAbsences(ctx, q, referenceLimits{ refs: refs, treePerCheckin: treePerCheckin, treeMax: treeMax, }) if a == nil { return nil, ReferenceWork{}, err } return a, a.work, err } // LoadAbsencesWork is LoadAbsencesContext, reporting what classification // read under the default budgets. func LoadAbsencesWork(ctx context.Context, q db.Querier) (*Absences, ReferenceWork, error) { limits := defaultReferenceLimits return LoadAbsencesWithin(ctx, q, limits.refs, limits.treePerCheckin) } // TreesRead names the trees v's horizon walks read from the store, and // counts the reads. func (v *MemoView) TreesRead() (names []string, reads int) { return slices.Collect(maps.Keys(v.trees)), v.treeReads } // TreeBytes is what m charges for the trees it keeps: its store's tree // index, or the trees its walks read when the store keeps none. func (m *Memo) TreeBytes() int64 { m.mu.Lock() defer m.mu.Unlock() if m.store != nil && m.store.trees != nil { return m.store.trees.bytes } return m.trees.bytes } // LimitTrees sets the most m's store tree index may keep; past it, m's // walks read trees as they need them. func (m *Memo) LimitTrees(bytes int64) { m.mu.Lock() defer m.mu.Unlock() m.treeLimit = bytes }