perf(docmodel): O(1) block lookups in isAncestor to cut hydrate CPU#859
perf(docmodel): O(1) block lookups in isAncestor to cut hydrate CPU#859juligasa wants to merge 1 commit into
Conversation
Document.Hydrate rebuilds tree state via treeOpSet.State() -> isAncestor, which did a comparator-heavy B-tree lookup per ancestor step. In a production CPU profile of the hyper.media daemon ~57% of all CPU was in that B-tree machinery (Less/hintsearch/nodeAscend). The #858 version cache cut how often we hydrate but not the per-hydrate cost, so cache misses (latest reads of just-synced docs) still saturate CPU. blockTreeState.blocks is point-lookup only (no ordered iteration), so switch it from *btree.Map[string,blockState] to a plain map[string]blockState. treeOpSet's ordered maps stay B-trees; no CRDT semantics change. Deep-doc hydrate 320.6ms -> 51.1ms (6.3x); flat 2.22ms -> 1.47ms. go test (incl -race) passes.
|
Claude Fable: Heads-up: I've merged this into #860 and combined it with a correctness fix, so #860 is now a superset of this PR (your map/O(1) optimization plus a bound on the The reason for combining: the production CPU fallover was actually an infinite loop — three documents contain a block that is its own parent ( Your optimization is great and kept in #860 as-is — this is purely additive. Suggest closing this in favor of #860 (details there: #860). Thanks! |
Problem
Document.Hydraterebuilds block-tree state viatreeOpSet.State() -> isAncestor, doing a comparator-heavy B-tree lookup per ancestor step. A production CPU profile of the hyper.media daemon (~330% CPU) showed ~57% of all CPU in that B-tree machinery (Less/hintsearch/nodeAscend). The #858 version cache reduced how often we hydrate but not the per-hydrate cost, so cache misses — unavoidable for "latest" reads of documents the daemon just synced — still saturate CPU.Change
blockTreeState.blocksis point-lookup only (no ordered iteration), so swap it from*btree.Map[string, blockState]to a plainmap[string]blockState.treeOpSets ordered maps (log,sublists) stay B-trees. No CRDT semantics change; ~12 call sites updated.Results (
RUN_HYDRATE_BENCH=1)Test plan
go test -race ./backend/api/documents/v3alpha/docmodel/— pass.