Skip to content

fix(storage): bound contiguous partition routing buffers - #1491

Merged
DecisionNerd merged 2 commits into
mainfrom
fix/1445-bound-partition-run
Sep 19, 2026
Merged

DecisionNerd merged 2 commits into
mainfrom
fix/1445-bound-partition-run

Conversation

@DecisionNerd

@DecisionNerd DecisionNerd commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Bounds PartitionRun at 64 KiB, flushing on byte capacity or partition change while preserving whole records, row counts and output order. Oversized individual records bypass the accumulator.

Three clean rotating-order S18 comparisons selected 64 KiB: median complete-ingest wall was 28.798 s against the unbounded baseline's 29.320 s. The selected candidate passes the recorded S18/S19/S20 throughput floors; contended observations are retained and excluded. The checked-in report and JSON contain the protocol, results, limitations and binary/input hashes. This establishes a bounded buffer without a material regression under the predeclared selection rule, not a throughput-improvement claim.

Validation:

  • Storage suite: 1,202 passed, six existing ignored tests; final-bound regressions also rerun.
  • API BDD: 118 scenarios passed; openCypher: 3,897 scenarios passed, zero regressions.
  • make pre-push-fast, gate-registry validation and formatting passed.
  • CodeRabbit reviewed record framing, output equivalence and durability interactions with no blocking findings: fix(storage): bound contiguous partition routing buffers #1491 (comment).

Closes #1445

Note

Bound contiguous partition routing buffers in PartitionRun to 64 KiB

  • Adds a byte bound to the PartitionRun accumulator in shape.rs, defaulting to 64 KiB in production and configurable for tests.
  • The push path flushes partial data before the buffer would exceed the bound and routes an individual record at or above the bound directly instead of buffering it; records are never split.
  • Adds tests in tests.rs covering fixed-width and compact records across multiple bound sizes, asserting byte-for-byte output equivalence with the unbounded path.
  • Adds benchmark evidence artifacts under docs/development/evidence/ documenting bound selection and correctness checks.
  • Risk: PartitionRun now retains at most the configured bound of buffered wire bytes; any caller assuming full-run buffering before flush will see earlier, partial flushes. The new bound is enforced in shape.rs push.

Macroscope summarized 7eb882f.

@coderabbitai

coderabbitai Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: CurateLabs/graphforge/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 64aed046-2d6f-4444-b248-4054c2ba6c76

📥 Commits

Reviewing files that changed from the base of the PR and between 44eb388 and 5c698b5.

📒 Files selected for processing (2)
  • crates/graphforge-storage/src/graph_construction/shape.rs
  • crates/graphforge-storage/src/graph_construction/shape/tests.rs

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

PartitionRun now bounds retained wire data, flushes on partition or capacity limits, and routes oversized records directly. New tests verify bounded buffering, whole-record handling, repeated flush behavior, row counts, and unchanged authenticated output.

Changes

Bounded PartitionRun buffering

Layer / File(s) Summary
Bounded accumulator behavior
crates/graphforge-storage/src/graph_construction/shape.rs
PartitionRun uses a 1 MiB default bound and supports custom bounds. push flushes on partition changes or insufficient space and routes oversized records directly.
Bounded buffering validation
crates/graphforge-storage/src/graph_construction/shape/tests.rs
Tests cover fixed-width and compact records across multiple bounds. They verify buffer limits, whole records, repeated flushes, row counts, and read-back wire output.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The implementation satisfies the byte-bound routing objective in #1445. PartitionRun flushes before a non-fitting record, preserves complete records, routes oversized records directly, and applies t… Run the BenchExec comparison for 64 KiB, 256 KiB, and 1 MiB. Report throughput and ingest RSS at S18, S19, and S20. Complete the determinism suite and TCK, then provide the results before treating #1445 as complete.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The changes are limited to PartitionRun in crates/graphforge-storage/src/graph_construction/shape.rs and regression tests in its test module. The implementation and tests directly support #1445 by…
Title check ✅ Passed The title clearly and concisely describes the main change: bounding contiguous partition routing buffers in storage.
Description check ✅ Passed The description clearly explains the implementation, record-preservation behavior, performance selection, validation results, linked issue, and review status. It omits several template sections and ch…
Full details: Linked Issues check

Explanation

The implementation satisfies the byte-bound routing objective in #1445. PartitionRun flushes before a non-fitting record, preserves complete records, routes oversized records directly, and applies the bound to fixed-width and identity routing. The added tests cover 64 KiB, 256 KiB, and 1 MiB bounds, compact records, output bytes, row totals, repeated flushes, and capacity. However, #1445 requires benchmark results for the three bounds, throughput and RSS measurements at S18, S19, and S20, and green determinism/TCK validation. The PR summary marks performance results and TCK as pending.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@DecisionNerd

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please focus on whether byte-bound flushes preserve record framing, partition transitions, row accounting and durable output, and whether the regression tests cover those contracts. The 1 MiB constant is provisional pending the requested 64 KiB / 256 KiB / 1 MiB quiet-host curve; no performance claim is ready yet.

@github-actions github-actions Bot added the core Core source code changes label Sep 19, 2026
@coderabbitai

coderabbitai Bot commented Sep 19, 2026 •

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Changed files ==='
git diff --name-status "$(git merge-base HEAD origin/main)" HEAD || git diff --name-status HEAD~1 HEAD

echo
echo '=== Diff stat ==='
git diff --stat "$(git merge-base HEAD origin/main)" HEAD || git diff --stat HEAD~1 HEAD

echo
echo '=== Rust outlines for changed files ==='
while IFS= read -r file; do
  case "$file" in
    *.rs)
      echo "--- $file ---"
      ast-grep outline "$file" --items all --type function,struct,impl,enum,trait 2>/dev/null || true
      ;;
  esac
done < <(git diff --name-only "$(git merge-base HEAD origin/main)" HEAD 2>/dev/null || git diff --name-only HEAD~1 HEAD)

Length of output: 1471


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="$(git merge-base HEAD origin/main 2>/dev/null || git rev-parse HEAD~1)"

echo '=== Patch ==='
git diff --find-renames --find-copies --unified=80 "$base" HEAD -- \
  crates/graphforge-storage/src/graph_construction/shape.rs \
  crates/graphforge-storage/src/graph_construction/shape/tests.rs

echo
echo '=== shape.rs outline ==='
ast-grep outline crates/graphforge-storage/src/graph_construction/shape.rs --items all --type function,struct,impl,enum,trait || true

echo
echo '=== tests.rs outline ==='
ast-grep outline crates/graphforge-storage/src/graph_construction/shape/tests.rs --items all --type function,struct,impl,enum,trait || true

Length of output: 16052


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Relevant definitions and call sites ==='
rg -n -C 8 --glob '*.rs' \
  'fn route_slice\b|fn finish_optional\b|fn balance\b|struct FixedRangePartitioner\b|fn run_record_bytes\b|fn read_run_record\b|PartitionRun::with_bound|route_fixed_run\b|route_identity_run\b' \
  crates/graphforge-storage/src/graph_construction

echo
echo '=== shape.rs relevant implementation ranges ==='
rg -n --glob '*.rs' 'struct FixedRangePartitioner\b|impl.*FixedRangePartitioner|fn route_slice\b|fn finish_optional\b|fn route_fixed_run\b|fn route_identity_run\b|struct PartitionRun\b|fn run_record_bytes\b|fn read_run_record\b' \
  crates/graphforge-storage/src/graph_construction/shape.rs

Length of output: 26302


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== FixedRangePartitioner routing and finalization ==='
sed -n '379,680p' crates/graphforge-storage/src/graph_construction/partition_shaping.rs

echo
echo '=== Fixed spill writer implementation ==='
rg -n -C 12 --glob '*.rs' 'struct FixedSpillWriter\b|impl.*FixedSpillWriter\b|fn append\b|fn seal\b' \
  crates/graphforge-storage/src/graph_construction/partition_shaping.rs

echo
echo '=== New-test context and available test helpers ==='
sed -n '1,180p' crates/graphforge-storage/src/graph_construction/shape/tests.rs
sed -n '700,810p' crates/graphforge-storage/src/graph_construction/shape/tests.rs

echo
echo '=== Existing end-to-end route test references ==='
rg -n -C 6 --glob '*.rs' \
  'route_fixed_run\(|route_identity_run\(|partition_rows|source content changed|source authority changed|finish_optional\(' \
  crates/graphforge-storage/src/graph_construction/shape/tests.rs \
  crates/graphforge-storage/src/graph_construction

Length of output: 62470


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== FixedRangePartitioner publication completion ==='
sed -n '650,745p' crates/graphforge-storage/src/graph_construction/partition_shaping.rs

echo
echo '=== DetailCodec wire and bytes contracts ==='
rg -n -C 10 --glob '*.rs' 'enum DetailCodec\b|impl DetailCodec\b|fn wire\b|fn bytes\b|fn read\b' \
  crates/graphforge-storage/src/graph_construction

echo
echo '=== Tests that cover source-routing authentication and session reopen ==='
rg -n -C 5 --glob '*.rs' \
  'content changed before partitioning|partition source content changed|shape_canonical_with_cancellation.*open|GraphConstructionSession::open\(|resumed' \
  crates/graphforge-storage/src/graph_construction/shape/tests.rs

Length of output: 14087


@DecisionNerd Reviewed with the requested focus. I found no blocking issues.

  • Record framing: PartitionRun appends complete run_record_bytes slices. It flushes before a non-fitting record. It routes oversized records as one direct slice. This preserves compact-record and fixed-record boundaries.
  • Partition transitions: A transition flushes the prior partition before the next partition receives data. A direct oversized record does not leave stale accumulator state.
  • Row accounting: Buffered flushes use the accumulated record count. Oversized records use records = 1. The partitioner records these counts, and final output accounting uses the number of emitted records.
  • Durable output: The existing finish_optional path seals partition spills, flushes and synchronizes the final file, creates its receipt, and publishes it. The change does not alter this lifecycle.
  • Regression tests: The new tests cover all three candidate production bounds, repeated byte-bound flushes, partition changes, compact variable-length records, oversized records, final flushes, empty flushes, exact output bytes, row totals, and accumulator capacity. Existing shape tests also cover reopening completed sessions.

I treated the 1 MiB value as provisional and did not assess performance claims.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@DecisionNerd
DecisionNerd force-pushed the fix/1445-bound-partition-run branch from 5c698b5 to 7eb882f Compare September 19, 2026 17:09
@DecisionNerd
DecisionNerd marked this pull request as ready for review September 19, 2026 17:09
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 19, 2026
@DecisionNerd
DecisionNerd added this pull request to the merge queue Sep 19, 2026
Merged via the queue into main with commit 5158bf3 Sep 19, 2026
23 checks passed
@DecisionNerd
DecisionNerd deleted the fix/1445-bound-partition-run branch September 19, 2026 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Core source code changes documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(storage): the PartitionRun accumulator is unbounded and grows with partition size

1 participant