8000 perf: decide net-assert on v8 index keys before building facts (#379) by adityamukho · Pull Request #459 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content

perf: decide net-assert on v8 index keys before building facts (#379) - #459

Merged
adityamukho merged 3 commits into
v3from
perf/379-live-keys
Oct 6, 2026
Merged

adityamukho merged 3 commits into
v3from
perf/379-live-keys

Conversation

@adityamukho
Copy link
Copy Markdown
Collaborator

Refs #379, part of #383.

What

  • CommittedReader::live_facts(scan, as_of) — committed facts of a scan (all / entity / entity+attr / attribute) that survive net-assert at as_of. Default impl = history → filter → net_asserted_facts (reference). OnDiskReader overrides it with a key walk:
    • a triple's history is contiguous and tx↓, so entries are taken one tx group at a time; a group holding a retraction hides everything older in the triple; otherwise the first assertion per (vf, vt) window wins;
    • hidden entries are passed over linearly, with seek(triple ‖ 0xFF) after 8 in a row (short histories pay no seek, long ones O(log));
    • only survivors are decoded and translated through DICT.
  • FactStorage::get_live_facts = pending (≤ as_of) + committed live. The executor uses it for (None, None) and :as-of N counter queries (selective and full scan). :as-of timestamps and the WriteTransaction overlay keep their path.
  • History reads (get_facts_by_*) are now #[cfg(test)]; LeafCursor::seek is used in production.

Why exact: the executor still net-asserts committed ∪ pending. Every pending fact is newer than every committed one, and net-assert only lets a newer record hide an older one, so a committed record hidden among committed records stays hidden in the union, and a dropped committed retraction could only hide already-hidden older assertions. Spec: docs/superpowers/specs/2026-10-06-live-key-scans-design.md.

Perf (point_query_chain_depth, checkpointed file; before = v3@74310ee)

Query Depth Before After
churned attribute 2000 4.61 ms 1.03 ms
attribute scan 2000 5.87 ms 1.24 ms
:as-of 2002 point (new bench row) 1 5.59 ms 23.4 µs
2000 8.55 ms 845 µs
depth-1 point queries 1 ~19–23 µs ~19–23 µs (A/B within noise)

Tests

1242 total (1233 passing, 9 ignored), +4:

  • triple_len ends exactly at tx↓ for every value type/index;
  • randomized histories (windows, retracts, re-asserts, multi-values, long values, 6 checkpoints): committed live read is exactly the net-asserted set for every scan × as_of, equivalent with pending on top, and after reopen. Mutation-checked: ignoring windows, skipping the as-of seek, and not resetting the tx group across triples all fail it;
  • a 2000× assert/retract triple: live read reads < ⅓ of the pages of a history read, with and without :as-of;
  • tests/live_reads_test.rs: same history in a checkpointed file DB vs in-memory → identical rows for point, attribute, full-scan, join, valid-time, :as-of and rule queries, before and after reopen.

cargo clippy --all-features -- -D warnings clean; wasm32 --features browser builds.

Note: touches net_asserted_facts semantics only by reusing them; #435 (one window per triple) will need to change the key walk alongside net_asserted_facts.

🤖 Generated with Claude Code

https://claude.ai/code/session_015GgLEs8YozJjYhwPEYgTUn

Committed reads for a query are reduced to the records that survive
net-assert while walking the index keys: the history of a triple is
contiguous and newest first, so a transaction holding a retraction hides
everything older (skipped, with a seek after a run of 8), and the first
assertion per valid-time window wins. Only survivors are decoded and
translated through the dictionary.

:as-of N counter queries now take the same selective index path, passing
over entries newer than N, instead of reading every fact in the file.

The executor still applies net_asserted_facts to committed and pending
facts together; prefiltering is exact because every pending fact is newer
than every committed one and a record can only be hidden by a newer one.
Randomized and differential (file vs in-memory) tests check this.

point_query_chain_depth at depth 2000: churned attribute 4.61 -> 1.03 ms,
attribute scan 5.87 -> 1.24 ms; :as-of point query 5.59 ms -> 23 us
(depth 1). Design: docs/superpowers/specs/2026-10-06-live-key-scans-design.md

Refs #379, #383

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GgLEs8YozJjYhwPEYgTUn
@codecov
codecov Bot commented Oct 6, 2026
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.75145% with 16 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/storage/mod.rs 0.00% 9 Missing ⚠️
src/storage/reader.rs 95.50% 4 Missing ⚠️
src/storage/keys.rs 91.17% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

adityamukho and others added 2 commits October 6, 2026 22:29
# Conflicts:
#	CLAUDE.md
#	README.md
#	ROADMAP.md
#	docs/TEST_COVERAGE.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GgLEs8YozJjYhwPEYgTUn
@adityamukho
adityamukho merged commit a4a1c6d into v3 Oct 6, 2026
19 checks passed
@adityamukho
adityamukho deleted the perf/379-live-keys branch October 6, 2026 17:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0