Skip to content

Stop allocating per frame when the WAL is opened - #67

Merged
venkat1701 merged 3 commits into
mainfrom
perf/wal-reader-buffers
Oct 11, 2026
Merged

venkat1701 merged 3 commits into
mainfrom
perf/wal-reader-buffers

Conversation

@venkat1701

@venkat1701 venkat1701 commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #58

I profiled an open of a clean scale-1 database with JFR. Most of what isn't JVM startup came from WriteAheadLog.restore. It scans the last segment frame by frame to find where valid data ends, and for every frame it:

  • allocated a new header and body ByteBuffer
  • fully decoded the record, copying each 16 KiB page image into a new array, then dropped it, since the scan only needs positioned.next()

Now each reader reuses one header buffer and one body buffer (growing the body only for a bigger frame), and the restore scan only checks headers and CRCs without decoding. Normal reads (read(from), used by recovery) still decode everything. Buffer reuse is safe because WalRecord.readPayload copies everything it keeps (getBytes copies; the rest are primitives).

Measured on the same data:

before after
fresh JVM, open only 110 MiB allocated 58 to 61 MiB
benchmark reopen (in-process close and open, same harness, 2 runs each) 140 to 176 MiB 38 to 39 MiB
WAL share of the open profile (JFR samples) 54 MiB 6.7 MiB

Open time didn't change (about 0.4 to 0.55 s); it's dominated by reading and checksumming. Neither version paused for GC in these reopen runs, so the 0.86 s pause in the issue didn't reproduce here.

The change-feed restore still allocates a payload array per frame (about 16 MiB here). Its frames hand the array to consumers, so reusing it isn't safe without a separate validate-only path. I left that out.

New WriteAheadLogTest, which passes on both the old and the new code:

  • 3,000 records with payloads from 0 to 20 KB across many 64 KiB segments, replayed byte for byte after reopen
  • a torn last frame is dropped and everything before it is kept
  • a small frame right after a 30 KB one reads back intact (the case buffer reuse could break)

CrashRecoveryTest (16 cases) passed three runs in a row, and the full ./mvnw install passes (95 tests).

Opening the log scans the last segment to find the end of the last valid
frame. The reader allocated a new header and body buffer for every frame
and decoded every record, copying page images it then threw away. It now
reuses its buffers and, for that scan, only checks frames.
@venkat1701
venkat1701 merged commit add3ca6 into main Oct 11, 2026
@venkat1701
venkat1701 deleted the perf/wal-reader-buffers branch October 11, 2026 09: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.

Reopen allocates 164 MiB

1 participant