Skip to content

Publish the recovered log end as the first checkpoint's lsn - #92

Merged
venkat1701 merged 3 commits into
metacoglabs:mainfrom
Ujjwaljain16:fix/recovery-replay-window
Oct 14, 2026
Merged

venkat1701 merged 3 commits into
metacoglabs:mainfrom
Ujjwaljain16:fix/recovery-replay-window

Conversation

@Ujjwaljain16

@Ujjwaljain16 Ujjwaljain16 commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #91.

If recovery doesn't replay any commit, the first checkpoint after it put the old lsn back. That left the WAL records of a transaction that never committed inside the replay window. The next transaction can get the same id, and if the process is killed again before a checkpoint, recovery applies both as one commit.

So a node nobody ever got an ack for shows up, and a half-written transaction can delete committed data.

The fix is one line: start the Checkpointer from the lsn recovery already computed. When recovery does replay commits that's what was used anyway, so nothing changes there.

TxnIdReuseTest crashes mid-commit, reopens, commits something, crashes again and reopens. One test checks the never-committed node stays gone, the other that committed data survives. Both fail on main and pass now. ./mvnw install is green on JDK 25 (engine 170, db 35, server 15).

The same lsn also covered commits dropped by the durable-prefix rule: a commit made after recovery discarded a bad tail was lost on the next crash. commitsAfterADiscardedTailSurviveTheNextCrash in CrashRecoveryTest covers it, and fails on main too.

As suggested on the issue, recovery also raises the next transaction id above the highest id it finds in the log, so an id from a dead transaction is never handed out again (transactionIdsAreNotReusedAfterACrash).

When recovery replayed no commit, the first checkpoint put the old lsn
back, so WAL records of a transaction that never committed stayed in the
replay window. A new transaction could be handed the same id, and after a
second crash recovery applied both as one commit. That made a node that
was never acknowledged visible, and let a half-written transaction delete
committed data.

Start the checkpointer from the lsn recovery already computed.

Fixes metacoglabs#91
Covers the durable-prefix case of the same problem: after recovery drops
commits whose pages are missing, a commit made afterwards was lost on the
next unclean stop.

Refs metacoglabs#91
The next transaction id was only restored from Commit records, so the id
of a transaction that died before committing was handed out again while
its records were still in the log. Raise the recovered next id above the
highest id found in the log.

Refs metacoglabs#91

@venkat1701 venkat1701 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Checked: the three new tests fail on main and pass with the fix, full suite green. Thanks.

@venkat1701
venkat1701 merged commit 6713fae into metacoglabs:main Oct 14, 2026
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.

Recovery replays a never-acknowledged transaction after a second crash

2 participants