Skip to content

perf(serialization): optimize buffered tail reads - #11209

Merged
ReubenBond merged 1 commit into
dotnet:mainfrom
ReubenBond:rb-perf-durable-jobs-bound-journal-batches
Sep 8, 2026
Merged

ReubenBond merged 1 commit into
dotnet:mainfrom
ReubenBond:rb-perf-durable-jobs-bound-journal-batches

Conversation

@ReubenBond

@ReubenBond ReubenBond commented Sep 8, 2026 •

Copy link
Copy Markdown
Member

JSON journal framing validates the final payload byte of every entry. ArcBufferWriter.TryPeek currently reaches that byte by walking from the first unread page, so a large unflushed batch repeatedly traverses a growing prefix.

This change reads bytes in an owned buffer's current write page directly using an unread-relative offset. Reads from earlier pages and pinned slices retain the existing traversal. The fast path relies on the existing write-page and length invariants, including consumed prefixes, reserved pages, truncation, and reuse.

Payload validation, public APIs, encoded bytes, and batching policy remain unchanged. Focused regressions cover page boundaries, consumption, empty/reserved write pages, truncation and patching, growing-source pinned slices, reset/disposal, and missing-payload rejection with rollback after large or consumed journal prefixes.

Measured impact

In a task-scoped Windows experiment with a fully queued burst of 4,096 jobs, 4 KiB metadata per job, and fast in-memory journal storage, the normal validation-preserving writer's uncapped drain median decreased from 181.12 ms to 80.18 ms (~2.26× faster) over five measured rounds per version. Observed ranges were 177.17–222.59 ms before and 54.81–114.75 ms after. Both versions used one append of up to 18,276,352 encoded bytes, with essentially unchanged allocations. Per-request p99 medians decreased from 168.27 ms to 48.61 ms.

The finite 128-outstanding-call workload with injected storage latency was essentially unchanged: 997.37 ms versus 984.77 ms median drain time. The burst result is workload-specific; these measurements use simulated storage, a shared Windows machine, and sequential baseline/fixed processes. The requested 2 ms storage delay actually averaged about 15 ms in the latency-controlled case.

Both versions passed an encoding-equivalence check for 1,024 fixed records, and every measured round replayed all 4,097 jobs, including its seed, through the original reader. The improvement addresses the buffer traversal directly while preserving the existing mutation batch policy.

Microsoft Reviewers: Open in CodeFlow

Copilot AI lite review requested due to automatic review settings September 8, 2026 19:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The change is narrowly scoped to an internal fast path, preserves pinned-slice behavior, and is backed by comprehensive new regression tests covering edge cases and journaling integration expectations.

Review tier: Lite
Findings: None

What changed in this PR

Optimizes ArcBufferWriter.TryPeek to avoid repeatedly traversing from the read page when peeking bytes near the end of large, unflushed owned buffers (a hot path for JSON journal framing’s “final payload byte” validation), while preserving behavior for pinned slices and earlier-page reads.

Changes:

  • Add a fast-path in ArcBufferWriter.TryPeek which reads directly from the current write page using an unread-relative offset when the buffer is owned (non-pinned).
  • Add focused unit tests validating Peek correctness across page boundaries, consumption, truncation/patching, reserved/empty write pages, reset/reuse/disposal, and pinned-slice semantics.
  • Add journaling regression tests ensuring JSON empty-entry validation behavior is retained after large and/or consumed prefixes, including rollback behavior.
File Description
src/​Orleans.Serialization/​Buffers/​ArcBufferWriter.cs Adds an owned-buffer write-page fast-path for TryPeek to avoid tail-peek traversal.
test/​Orleans.Serialization.UnitTests/​ArcBufferWriterTests.cs Adds coverage for Reader.Peek across boundary and mutation scenarios, including pinned slices.
test/​Orleans.Journaling.Tests/​JournalBufferWriterOwnershipTests.cs Adds regressions for JSON empty-entry validation after large/consumed committed prefixes and across resets.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ReubenBond
ReubenBond merged commit 8d41994 into dotnet:main Sep 8, 2026
72 checks passed
@ReubenBond
ReubenBond deleted the rb-perf-durable-jobs-bound-journal-batches branch September 8, 2026 20:09
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