8000 test(query): memory limit acceptance tests and measured figures (#549 PR 2) by adityamukho · Pull Request #681 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content

test(query): memory limit acceptance tests and measured figures (#549 PR 2) - #681

Merged
adityamukho merged 3 commits into
v3from
feat/549-acceptance
Oct 21, 2026
Merged

adityamukho merged 3 commits into
v3from
feat/549-acceptance

Conversation

@adityamukho
Copy link
Copy Markdown
Collaborator

#549 PR 2 (streaming engine 7/9 under #473): acceptance tests and measured figures, plan steps 11–13. PR 1 was #676.

What

  • tests/memory_limit_acceptance_test.rs (2 tests, ignored):
    • 1M groups: [:find ?g (count ?e) :where [?e :g ?g]] returns 1M rows. With query_memory_limit at 32 MiB it fails with QRY-012 naming Aggregate, and the database still answers afterwards.
    • Nightly fuzz failure (main) #575 cartesian, k = 13: 13 patterns that share no variable, over the fuzz harness's 3 facts. Draining the cursor counts 3^13 = 1,594,323 rows with peak RSS under 64 MiB. With a 64-byte limit it fails with QRY-012 naming HashJoin.
  • New smoke.yml job memory-limit-acceptance: --profile bench, without test-oracle, --test-threads=1 (peak RSS is per process).
  • meter_peak_against_rss (ignored engine test): prints the meter's peak against peak RSS for both shapes. It opens the engine directly because the executor oracle would run out of memory on the product. It uses a cfg(test) Minigraf::snapshot.
  • docs/BENCHMARKS.md gets the figures. CHANGELOG, TEST_COVERAGE, CLAUDE.md and README counts updated: 1725 tests (1711 passing, 14 ignored).

Figures (dedicated Linux server, one NUMA node, 3 runs)

Shape Rows Time Meter peak Peak RSS added
1M groups 1,000,000 3.5–3.6 s 435 MiB 542–549 MiB
#575 k = 13 1,594,323 2.6 s 4 KiB 9.6–9.7 MiB in a fresh process

The executor held more than 5.7 GB on #575 at k = 13.

Fix found by measuring (deviation from the plan)

The first measurement of 1M groups gave a meter peak of 282 MiB against 651 MiB of RSS, outside spec §3.2's factor of two. Aggregate::finish built its sorted Groups map (each group's values twice, plus its accumulators) without charging it, while the hash table and group rows were still alive. Now:

  • the map is charged as finished until every row is built;
  • the hash table is freed before the map is built, and the group charge is released after it;
  • sum-distinct members move from the group charge to the map's, so they are counted once and not dropped (Codex finding).

Result: 435 MiB metered against about 545 MiB of RSS (1.25×). The real peak also dropped, from 651 to 513 MiB on a laptop. Two unit tests cover this; both fail without the fix.

Spec deviations (both in the plan)

  • Test 1's limit is fixed at 32 MiB, not read from a first run's counters, because an integration test cannot read the meter.
  • :find ?v0 reads the first pattern's value.

Review

Codex found one issue: sum-distinct members were uncharged during finish. Fixed. Its other finding, that the charges stay after a failed finished.charge inside finish, is by design: Stream::next_rows closes the stream on any error, and that releases every Held. Codex's first pass confirmed this.

#549 stays open until this merges, then gets closed by hand. Binding PRs follow. Refs #549, #575, #473.

🤖 Generated with Claude Code

https://claude.ai/code/session_019kY61Y11gcRD91Y6b7jbGT

adityamukho and others added 3 commits October 21, 2026 14:39
…nting (#549)

Ignored acceptance tests (1M aggregate groups; #575 cartesian k = 13,
streamed in a few MiB), run nightly by smoke.yml without test-oracle, and
an ignored engine test printing the meter's peak against peak RSS.

Aggregate::finish built its sorted map of groups uncharged while the hash
table and group rows were still alive: 1M groups metered 282 MiB against
651 MiB of RSS. The map is now charged until every row is built, and the
table and rows go first (513 MiB RSS, 435 MiB metered).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019kY61Y11gcRD91Y6b7jbGT
…sh (#549)

Releasing the group charge after building the sorted map dropped the
sum-distinct members, which live on in the map until finish_groups. They
now move from the group charge to the sorted map's.

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

Codecov Report

❌ Patch coverage is 88.88889% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/db.rs 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@adityamukho
adityamukho merged commit df7282f into v3 Oct 21, 2026
24 of 25 checks passed
@adityamukho
adityamukho deleted the feat/549-acceptance branch October 21, 2026 12:30
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