Skip to content

feat(persistence): WAL group commit — coalesce concurrent appendfsync=always writes into one fsync#178

Merged
pilotspacex-byte merged 11 commits into
mainfrom
feat/wal-group-commit
Jun 15, 2026
Merged

feat(persistence): WAL group commit — coalesce concurrent appendfsync=always writes into one fsync#178
pilotspacex-byte merged 11 commits into
mainfrom
feat/wal-group-commit

Conversation

@pilotspacex-byte

@pilotspacex-byte pilotspacex-byte commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

WAL group commit — coalesce concurrent appendfsync=always writes into one fsync

v2-performance bottleneck #3. Under appendfsync=always the AOF writer used to flush()+sync_data() once per AppendSync (the ~11× write penalty). This batches concurrent pending writes via opportunistic drain: after one message, drain whatever else is queued into a bounded batch, write all, ONE fsync, ack all — amortizing the per-write fsync across write concurrency without weakening the fsync-before-ack contract, the C4 cross-shard fold, the H1-BARRIER, or the everysec/no paths.

⚠️ Stacked on #177 (feat/xshard-read-fastpath). This PR is based on that branch and will auto-retarget to main once #177 merges. Review the 9 commits 5058b76…8298eaa only.

What changed

  • New pure seam src/persistence/aof/group_commit.rs: collect_group_commit_batch (bounded drain, control messages defer — never batched) + commit_group_commit_batch (write-all → ONE fsync → ack-all) + GroupCommitSink + shared ack_batch (single-sourced ack-after-fsync ordering).
  • Wired into all four writer loops: {aof_writer_task TopLevel, per_shard_aof_writer_task} × {monoio sync, tokio async}. Control messages (Rewrite/RewriteSharded/RewritePerShard/Shutdown) route to deferred_controlbatch_straddles_control is structurally impossible.
  • Finding 2 fix (2750d1c): the tokio-TopLevel loop never carried the write_error torn-write latch (nor the MOON_TEST_AOF_FSYNC_FAIL injection) — a pre-existing gap the new contract (CommitOutcome.write_failed ⇒ latch must engage) made explicit. Now mirrors the other 3 loops; covered by the top_level SIGKILL test.

Verification (dual-runtime, VM-local clone)

  • seam unit 9/9 · AOF lib 94 tokio / 90 monoio
  • integration crash 4/4 ×both runtimes (incl. concurrent_writers_all_acked_survive_sigkill_top_level)
  • crash-matrix 5/5 ×both (crash_matrix_per_shard_aof + ..._bgrewriteaof)
  • consistency 197/197 @ 1/4/12 shards
  • clippy -D warnings ×2 + fmt clean · zero new unsafe · zero new cross-thread lock

Durability invariant preserved (M2)

acked ⇒ on disk: a waiter is acked Synced only after the covering batch fsync returns. The single batch fsync also makes every preceding fire-and-forget Append durable (H1-BARRIER ordered-channel property). A crash mid-batch leaves at most a torn tail record → existing replay truncates to the last valid record.

⚠️ M0/M1 throughput: deferred (instrument limitation, not a code gap)

The coalescing mechanism (K AppendSync → 1 fsync) is proven by the deterministic seam test commit_one_fsync_many_acks. The empirical RPS ratio could not be measured on the OrbStack VM: its virtio fsync is near-free (always ≈ 0.9M RPS, not the 11× penalty), so the writer drains each AppendSync before the next arrives and a coalescing batch never forms (batch≈1; 0.98× ratio, no trend across a C∈{32,128,256,512} sweep). This was the §1 lowest-confidence perf flag (assumption #4), now confirmed. The before/after ratio needs a slow-fsync instrument (real disk / GCloud); tracked as the §7 OBSERVE monitor.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Improved AOF durability throughput when appendfsync=always is enabled by coalescing concurrent durable writes into batch commits, reducing the number of fsyncs while preserving ordering and crash safety.
    • Ensures acknowledgements are only issued after the batch durability step completes, with proper handling of deferred control actions.
  • Tests

    • Added a full suite validating batch collection rules, durability/ack outcomes under injected failures, and crash-recovery/in-rewrite scenarios.

New task wal-group-commit (v2-performance milestone, risk:high autonomy:conservative):
WAL group commit — coalesce concurrent appendfsync=always fsyncs via opportunistic
drain on both AOF writers, to collapse the ~11x write penalty (135K->12K).

Bundle frozen @ v1 (approved Tin Dang 2026-06-14):
- §1 SPECIFY: opportunistic drain, both writers, mixed-stream durability invariant
  (acked => on disk; one fsync per bounded batch; control msgs break the batch),
  grounded in the live AOF writer code (per-connection await yields => concurrent
  durable writes converge as queued AppendSync; channel mixes Append/AppendSync/control).
- §2 SCENARIOS: one per Must (M0-M4) + per Reject (5 codes), each with its unchanged-clause.
- §3 CONTRACT: collect_group_commit_batch (pure, cap-bounded, control-stopping seam) +
  commit_group_commit_batch (one fsync, ack-after-fsync); new module
  src/persistence/aof/group_commit.rs; a response for every reject code.
- §4 TESTS: unit batching seam + integration concurrent-writers SIGKILL crash test.

Freeze-flagged: mixed-stream drain must preserve C4-fold + H1-BARRIER + everysec
invariants exactly (silent-corruption risk) — mitigated by routing control msgs to
deferred_control so batch_straddles_control is structurally impossible.

author: Tin Dang
Failing-first (RED) suite for the frozen §3 group-commit contract. Compile-red
on the not-yet-existent moon::persistence::aof::group_commit module (the right
reason — missing implementation; harness otherwise compiles).

9 seam tests assert observable behavior, not internals:
- collect_group_commit_batch (pure): control-first → no batch; stop-at-control
  preserving order; max_batch cap; max_bytes soft cap.
- commit_group_commit_batch (durability invariant via a counting sink):
  one-fsync-many-acks + fsync-after-all-writes ordering; write-fail → WriteFailed,
  no Synced; fsync-fail → FsyncFailed, no Synced (proves ack-after-fsync);
  everysec do_fsync=false → no fsync; barrier covers preceding Appends (H1-BARRIER).

End-to-end durability (acked-survives-SIGKILL, rewrite-during-writes) is gated on
the integration crash-matrix + a new concurrent-writers crash test added at build —
a unit mock cannot prove on-disk survival across a real kill.

author: Tin Dang
Add `src/persistence/aof/group_commit.rs`, the pure, runtime-free batching seam
for WAL group commit (coalesce concurrent pending AOF writes into ONE fsync under
appendfsync=always). This is the §5 BUILD step 1 for the wal-group-commit task:
the seam the four writer loops will share.

- `collect_group_commit_batch`: pure opportunistic drain — pull queued data
  messages until the queue empties, a control message appears (deferred, never
  batched → `batch_straddles_control` structurally impossible), or a bounded cap
  (count `AOF_GROUP_COMMIT_MAX_BATCH`=1024 / bytes `AOF_GROUP_COMMIT_MAX_BYTES`=8 MiB)
  is hit. Channel order preserved exactly.
- `commit_group_commit_batch` over a `GroupCommitSink`: the durability invariant —
  write all bytes in order, ONE fsync after all writes (Always only), THEN ack
  every AppendSync `Synced`. Reject mappings: write error → all WriteFailed;
  fsync error → all FsyncFailed; ack_before_fsync unreachable by construction.
- `ack_batch` (pub(crate)): single source of the ack/durability ordering, shared
  by the sync commit path and the async/framed inline writer paths added next.

Registers `pub mod group_commit` so the §4 red suite pins the public seam.

Also fixes a use-after-consume defect in the frozen §4 test
`commit_write_fail_acks_write_failed`: it read `rx2.try_recv()` twice on a
single-use (flume bounded-1) ack channel, draining it before the second
assertion — unsatisfiable by any correct impl. Read each receiver once into a
local; the three assertions are unchanged (approved by Tin Dang 2026-06-14, the
minimal intent-preserving fix; not a weakening).

§4 red suite (9 seam tests) now GREEN. Writer-loop wiring + crash tests follow.

author: Tin Dang
Replace the per-message write+fsync+ack in every AOF writer loop with the
group-commit seam: receive one message, opportunistically drain the ready queue
into a bounded batch, write all records, make them durable with ONE
flush()+sync_data(), then ack every AppendSync `Synced`. Under appendfsync=always
with C>1 concurrent durable writers this amortizes the fsync across the batch
(the ~11× write penalty), without weakening the fsync-before-ack contract.

Loops wired (TopLevel/PerShard × monoio/tokio):
- TopLevel monoio: commits via the sync `commit_group_commit_batch` over a
  `FileGroupSink` (plain RESP bytes; the metric is recorded on the batch fsync).
- TopLevel tokio / PerShard tokio / PerShard monoio: replicate the same invariant
  inline (async I/O can't impl a sync sink; per-shard prepends the framed
  `[u64 lsn][u32 len]` header) and ack through the shared `group_commit::ack_batch`
  so the durability ordering is single-sourced and unit-tested via commit.

Invariants preserved exactly:
- M3 control safety: Rewrite/RewriteSharded/RewritePerShard/Shutdown are never
  absorbed into a batch — `collect_group_commit_batch` defers them to
  `deferred_control`, handled AFTER the batch is flushed (batch_straddles_control
  structurally impossible). The C4 per-shard fold + post-fold drain are unchanged.
- M2 H1-BARRIER: a zero-length AppendSync writes no record; the single batch fsync
  still proves all preceding Append bytes durable (ordered channel).
- M4 everysec/no: group commit engages only under Always (do_fsync = fsync==Always);
  AppendSync is enqueued only under Always (pool::try_send_append_durable /
  fsync_barrier), so everysec/no batches are Append-only and the 1s deadline /
  proactive fsync + bounded-recv paths are retained verbatim.
- Torn-write latch: a write_all failure latches `write_error` (stream may be torn)
  and fails every AppendSync waiter WriteFailed; the tokio TEST_FAIL_WRITE_AT
  torn-write injection is preserved (header-only write at the failing ordinal).
- Fault injection: MOON_TEST_AOF_FSYNC_FAIL resolves the batch FsyncFailed.

Behavioral refinement (flagged for verify): write_error now latches ONLY on a
write failure (torn stream), not on an fsync failure. A failed fsync leaves the
bytes intact-but-unsynced (not torn), so a transient fsync error is recoverable
on the next batch rather than permanently disabling the writer. Uniform across all
four loops; the reject contract (batch_fsync_failed) requires FsyncFailed acks,
not a latch. No crash-matrix test exercises a real fsync-fail-then-latch path.

Both runtimes: compile clean, clippy clean, AOF unit tests pass (74 tokio / 70
monoio incl. the tokio torn-write latch test), §4 seam suite green.

author: Tin Dang
… SIGKILL

Add the end-to-end durability scenarios the unit seam cannot prove (on-disk
survival across a real kill), spawning the release binary under
appendfsync=always with CONCURRENT durable writers — the cell group commit lives
in. `#[ignore]`; require ./target/release/moon + redis-cli; run on the VM.

- concurrent_writers_all_acked_survive_sigkill_top_level (shards=1) and
  _per_shard (shards=4): N=16 connections each drive 60 durable INCRs on distinct
  counters; all joined (every counted INCR acked ⇒ fsynced) before SIGKILL;
  recovery must show each counter == its acked count — every acked write durable,
  none lost, none double-applied (INCR is non-idempotent). shards=1 exercises the
  TopLevel commit_group_commit_batch path; shards=4 the per-shard framed path.
  [M2 every_acked_write_survives_crash + interrupted_batch clean reload]
- lone_writer_fsyncs_immediately (C=1): a lone durable writer is a batch of 1 —
  fsync immediate, ack Synced, no loss after SIGKILL. [M4 lone_writer_no_added_latency]
- rewrite_during_active_writes_no_loss: BGREWRITEAOF fired repeatedly while 12
  concurrent durable writers run; the Rewrite control must flush its in-progress
  batch BEFORE it is handled; post-rewrite replay loses no acked write.
  [M3 control_message_breaks_the_batch]

author: Tin Dang
… commit

The group-commit rewrite gave the tokio TopLevel AOF writer a per-iteration
local `write_failed` but no persistent `write_error` latch — unlike the other
three writer loops (monoio TopLevel, tokio/monoio PerShard), which all latch a
write failure for the writer's lifetime. After a torn batch write the tokio
TopLevel loop would keep appending on the next batch, risking a silent
durability claim past a partial record. This was a pre-existing gap that the
group_commit contract makes explicit: `CommitOutcome.write_failed` ⇒ "the
caller engages its write_error latch".

Mirror the monoio TopLevel exactly:
- declare a lifetime `write_error` latch; on a batch write failure, latch it and
  ack every AppendSync waiter WriteFailed (never ack into a corrupt stream);
- once latched, drop appends and fail all waiters until a successful rewrite,
  which replaces the file with a clean one and resets the latch;
- gate every final/deadline sync (cancel, disconnect, Shutdown, EverySec
  deadline, pre-rewrite) on `!write_error` — syncing past a tear cannot recover
  it and risks a false durability signal.

Also restore the MOON_TEST_AOF_FSYNC_FAIL injection on this path (it existed
only on monoio TopLevel before) so the AOF_FSYNC_ERR wire response is exercised
identically under both runtimes for shards=1 — making
`aof_fsync_err_propagates_before_subscribe_single_shard` valid against a tokio
binary, not just the default monoio one.

Defense-in-depth: a debug_assert that an everysec/no batch carries no
AppendSync (those are enqueued only under Always via
pool::try_send_append_durable / fsync_barrier) before acking Synced.

Both runtimes compile clean; clippy clean on both; the 9 group-commit seam
tests stay green.

author: Tin Dang
…marker

Record the phase transition (tests -> build) after the §4 red suite went
green, and rename the §3 freeze label to the engine-required marker phrase
("Least-sure flag surfaced at freeze:") with all frozen substance preserved
— a marker alignment, not a contract reshape.

author: Tin Dang
…rify

§6 VERIFY (dual-runtime, VM-local clone @12681b3):
- seam 9/9 · AOF lib 94 tokio/90 monoio · integration crash 4/4 ×both
  (incl. concurrent_writers_all_acked_survive_sigkill_top_level — covers the
  Finding-2 tokio-TopLevel latch) · crash-matrix 5/5 ×both · consistency 197/197
- WIRING + DEAD-CODE clean; clippy ×2 + fmt clean; zero new unsafe/locks
- one frozen §4 test got a human-approved intent-preserving fix (flume
  bounded(1) use-after-consume); CONTRACT unchanged

M0/M1 perf: the win's mechanism (K AppendSync -> 1 fsync) is proven by the
deterministic seam test, but the empirical RELATIVE throughput delta is NOT
resolvable on the OrbStack VM — its virtio fsync is near-free (always ~0.9M RPS,
no 11x penalty), so the writer drains each AppendSync before the next arrives
and a coalescing batch never forms (batch~1; 0.98x ratio, conc-sweep no-trend
within +/-10% VM noise). This is §1 assumption #4 (lowest-confidence perf flag)
confirmed: the VM is an invalid instrument for this metric; the M0/M1 ratio
needs a slow-fsync instrument (real disk / GCloud). Deferred to §7 OBSERVE.

GATE: PENDING — conservative autonomy stops for human decision (no auto-PASS).

author: Tin Dang
Human gate decision (conservative autonomy): PASS — defer the empirical M0/M1
RPS ratio to §7 OBSERVE. Correctness/durability (M2) · ordering (M3) ·
no-regression (M4) · all 5 Rejects proven green on both runtimes; the
coalescing-win mechanism proven by the deterministic seam test. The empirical
throughput ratio is un-measurable on the OrbStack VM (near-free fsync) and is
tracked as the OBSERVE monitor (real-disk / GCloud bench).

v2-performance: 2/2 tasks done (xshard-read-fastpath + wal-group-commit).

author: Tin Dang
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d463fb2d-18ad-4c8b-a6a7-c7099a03f98b

📥 Commits

Reviewing files that changed from the base of the PR and between bd16edf and b5dfb2b.

📒 Files selected for processing (1)
  • CHANGELOG.md
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md

📝 Walkthrough

Walkthrough

This PR introduces AOF group-commit batching. A new group_commit.rs module defines the GroupCommitBatch / GroupCommitSink / CommitOutcome contracts, a bounded collect_group_commit_batch drain, and a commit_group_commit_batch function that writes all payloads then performs exactly one sync() before acking waiters. All four AOF writer loops (monoio/tokio TopLevel and per-shard) are refactored to use this seam. A new test file validates the batching and durability invariants with unit tests and ignored SIGKILL integration tests. Task tracking and changelog entries document the feature.

Changes

WAL Group Commit Batching

Layer / File(s) Summary
Group commit seam: types, collection, and commit logic
src/persistence/aof/mod.rs, src/persistence/aof/group_commit.rs
Declares the group_commit submodule and defines all public contracts: GroupCommitBatch, GroupCommitSink trait, CommitOutcome, BatchAck enum, collect_group_commit_batch (bounded drain with control-message deferral), ack_batch, and commit_group_commit_batch (write-all → optional single sync → ack-all).
TopLevel writer loops: monoio and tokio integration
src/persistence/aof/writer_task.rs (lines 13–573)
Adds FileGroupSink monoio adapter with barrier semantics, test sync-fail injection, and flush()+sync_data() metrics; adds tokio TopLevel torn-write latch and fail_fsync_for_test env flag; replaces both TopLevel per-message loops with bounded collect→commit→deferred-control-dispatch including EverySec deadline logic and RewritePerShard routing-bug handling.
Per-shard writer loops: monoio and tokio integration
src/persistence/aof/writer_task.rs (lines 759–1305)
Converts the tokio per-shard loop to group-commit framed [lsn][len][RESP] writes with torn-write latch and zero-length AppendSync barrier semantics; converts the monoio per-shard loop to recv_timeout + group-commit batching with RewritePerShard fold followed by post-fold drain+sync and last_fsync back-dating.
Unit and integration test suite
tests/wal_group_commit.rs
Adds CountingSink test double; unit tests for collect_group_commit_batch (control deferral, caps) and commit_group_commit_batch (single-fsync ordering, write/fsync failure ack states, barrier semantics, do_fsync=false); ignored unix integration tests for SIGKILL crash recovery and BGREWRITEAOF-during-writes scenarios against a real binary.
Task tracking, specification, and changelog
.add/state.json, .add/tasks/wal-group-commit/TASK.md, CHANGELOG.md
Switches active_task to wal-group-commit, registers the task metadata, and adds the full TASK.md specifying feature rules, scenario matrix, frozen contract, test plan, build-phase constraints, verification outcomes, and M0/M1 throughput observation guidance; documents per-shard coalescing behavior in the changelog.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(100, 149, 237, 0.5)
    note over AofWriterLoop: Group Commit Batch Cycle
    AofWriterLoop->>collect_group_commit_batch: first_msg + try_next() + caps
    collect_group_commit_batch-->>AofWriterLoop: GroupCommitBatch{data, deferred_control}
  end

  rect rgba(144, 238, 144, 0.5)
    note over AofWriterLoop,GroupCommitSink: Write + Sync Phase
    AofWriterLoop->>commit_group_commit_batch: sink, batch, do_fsync
    loop each msg in batch.data
      commit_group_commit_batch->>GroupCommitSink: write_all(msg_body)
    end
    commit_group_commit_batch->>GroupCommitSink: sync() [if do_fsync]
    commit_group_commit_batch->>AppendSyncWaiters: AofAck(Synced|WriteFailed|FsyncFailed)
    commit_group_commit_batch-->>AofWriterLoop: CommitOutcome
  end

  rect rgba(255, 165, 0, 0.5)
    note over AofWriterLoop: Deferred Control Dispatch
    AofWriterLoop->>AofWriterLoop: match deferred_control
    alt Rewrite / RewriteSharded / RewritePerShard
      AofWriterLoop->>RewriteHandler: trigger rewrite flow
    else Shutdown
      AofWriterLoop->>AofWriterLoop: break loop
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 Hoppity-hop through the write queue I go,
Collecting my fsyncs all in a row.
One sync to commit them, one flush to bind,
No waiter left acking before it's been signed!
The batch drains and defers, control messages wait—
Group commit is open, step right through the gate! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: implementing WAL group commit to coalesce concurrent appendfsync=always writes into a single fsync, which is the core feature and performance optimization in this PR.
Description check ✅ Passed The PR description comprehensively covers the change (group commit implementation wired into all four writer loops), includes verification results (9/9 seam tests, crash tests, consistency checks), and discusses durability invariants and throughput measurement deferral. However, the description does not include explicit cargo fmt/clippy check confirmations and test run results as specified in the template checklist.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/wal-group-commit

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 and usage tips.

pilotspacex-byte and others added 2 commits June 15, 2026 13:35
The Lint CHANGELOG gate requires every PR to either touch CHANGELOG.md or
carry the skip-changelog label. WAL group commit is a shippable performance
feature, so it gets a real [Unreleased] entry rather than a skip label.

author: Tin Dang

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
.add/tasks/wal-group-commit/TASK.md (1)

231-231: 💤 Low value

Add language specifier to fenced code block.

Line 231 opens a code block without a language tag. This should be ```rust to properly render the syntax highlighting in markdown viewers.

-```
+```rust
 // ---- Bounds (design-for-failure: a drain is never unbounded) ----
 const AOF_GROUP_COMMIT_MAX_BATCH: usize   // hard cap on messages per batch (e.g. 1024)
 const AOF_GROUP_COMMIT_MAX_BYTES: usize   // hard cap on bytes buffered per batch (e.g. 8 MiB)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.add/tasks/wal-group-commit/TASK.md at line 231, The markdown code block at
line 231 is missing the language specifier for syntax highlighting. Change the
opening fence from ``` to ```rust to properly enable Rust syntax highlighting in
markdown viewers.
tests/wal_group_commit.rs (1)

256-260: ⚡ Quick win

Consider verifying r1 is WriteFailed for complete coverage.

The test verifies r2 is WriteFailed but only checks that r1 is not Synced. Per the contract in ack_batch, all waiters should receive WriteFailed. Adding the explicit assertion would strengthen the test.

🧪 Proposed fix
     let r1 = rx1.try_recv();
     let r2 = rx2.try_recv();
-    assert_ne!(r1, Ok(AofAck::Synced));
+    assert_eq!(r1, Ok(AofAck::WriteFailed), "first waiter must also be acked WriteFailed");
     assert_ne!(r2, Ok(AofAck::Synced));
     assert_eq!(r2, Ok(AofAck::WriteFailed));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/wal_group_commit.rs` around lines 256 - 260, The test in the try_recv
section checks that r1 is not Synced but does not explicitly verify it is
WriteFailed, while r2 has an explicit assertion for WriteFailed. Per the
contract in ack_batch, all waiters should receive WriteFailed. Add an explicit
assertion that r1 equals Ok(AofAck::WriteFailed) after the assert_ne check to
match the verification done for r2 and ensure complete test coverage.
src/persistence/aof/writer_task.rs (1)

882-886: 💤 Low value

Consider adding debug_assert for everysec/no invariant in per-shard paths (consistency with TopLevel).

The tokio TopLevel path (line 446-452) has a debug_assert! verifying that everysec/no batches contain no AppendSync messages. Both per-shard paths lack this assertion. While the pool code enforces this invariant, adding the same assertion maintains consistency and catches violations earlier during development.

  • src/persistence/aof/writer_task.rs#L882-L886: Add debug_assert before returning BatchAck::Synced in the tokio per-shard everysec/no branch.
  • src/persistence/aof/writer_task.rs#L1198-L1202: Add the same debug_assert in the monoio per-shard everysec/no branch.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/persistence/aof/writer_task.rs` around lines 882 - 886, Add a
debug_assert statement for the everysec/no invariant in both per-shard paths to
match the consistency check already present in the TopLevel path. At
src/persistence/aof/writer_task.rs lines 882-886 (tokio per-shard everysec/no
branch), add a debug_assert before returning BatchAck::Synced to verify that the
batch contains no AppendSync waiters. Apply the identical assertion at
src/persistence/aof/writer_task.rs lines 1198-1202 (monoio per-shard everysec/no
branch) in the same position. Both assertions should verify that the batch does
not contain any AppendSync messages, maintaining consistency with the existing
TopLevel path validation and catching potential invariant violations earlier
during development.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.add/tasks/wal-group-commit/TASK.md:
- Line 231: The markdown code block at line 231 is missing the language
specifier for syntax highlighting. Change the opening fence from ``` to ```rust
to properly enable Rust syntax highlighting in markdown viewers.

In `@src/persistence/aof/writer_task.rs`:
- Around line 882-886: Add a debug_assert statement for the everysec/no
invariant in both per-shard paths to match the consistency check already present
in the TopLevel path. At src/persistence/aof/writer_task.rs lines 882-886 (tokio
per-shard everysec/no branch), add a debug_assert before returning
BatchAck::Synced to verify that the batch contains no AppendSync waiters. Apply
the identical assertion at src/persistence/aof/writer_task.rs lines 1198-1202
(monoio per-shard everysec/no branch) in the same position. Both assertions
should verify that the batch does not contain any AppendSync messages,
maintaining consistency with the existing TopLevel path validation and catching
potential invariant violations earlier during development.

In `@tests/wal_group_commit.rs`:
- Around line 256-260: The test in the try_recv section checks that r1 is not
Synced but does not explicitly verify it is WriteFailed, while r2 has an
explicit assertion for WriteFailed. Per the contract in ack_batch, all waiters
should receive WriteFailed. Add an explicit assertion that r1 equals
Ok(AofAck::WriteFailed) after the assert_ne check to match the verification done
for r2 and ensure complete test coverage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3d91ecb5-c00c-4947-b38e-e706b503bca7

📥 Commits

Reviewing files that changed from the base of the PR and between 797d52d and bd16edf.

📒 Files selected for processing (6)
  • .add/state.json
  • .add/tasks/wal-group-commit/TASK.md
  • src/persistence/aof/group_commit.rs
  • src/persistence/aof/mod.rs
  • src/persistence/aof/writer_task.rs
  • tests/wal_group_commit.rs

@pilotspacex-byte pilotspacex-byte merged commit 82a2be2 into main Jun 15, 2026
11 checks passed
TinDang97 added a commit that referenced this pull request Jun 15, 2026
The cross-shard idle-gated reply-spin entry under [Unreleased] was the
only v2-performance changelog entry without its originating PR number,
while the sibling WAL group-commit (#178) and FT.SEARCH off-event-loop
(#179) entries both carry one. Add the "(PR #177)" tag so all three v2
stack entries are consistently attributable.

Documentation-only; no code, test, or behavior change.

author: Tin Dang

Co-authored-by: Tin Dang <tin.dang@trustifytechnology.com>
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.

2 participants