Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Multi-process WAL: PrepareTransactionAsync and the direct commit paths bypass the commit and cross-process writer locks

Open
#188 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 2 days

Nobody has claimed this yet.

  • #246 by @CaffeinatedCoder — closed without merging

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
csharp, databases

Research direction

Start with StorageEngine.PrepareTransactionAsync, CommitTransactionAsync(ulong), and MarkTransactionCommittedAsync(ulong), then compare their WAL append sequence with ProcessBatchAsync and the shared-WAL catch-up changes from #169. Trace how checkpoint truncation handles prepared transactions and how multi-process appends publish WAL offsets and the SHM page index. Done means prepared records survive until commit or abort, and direct commit records are safely appended and visible across processes, or these paths are rejected in multi-process mode.

Written by the indexing model from the issue text.

Description

bug package/core priority/P3 severity/low

Found during the review of #169.

StorageEngine.PrepareTransactionAsync (both overloads) writes Begin and Write records to the WAL without holding _commitLock or, in multi-process mode, the SHM writer lock. A checkpoint's WAL truncation (TryTruncateWalAsync) only excludes writers that hold _commitLock, so it can run between a prepare and the matching commit and drop the prepared transaction's records.

The in-library flow (Transaction.PrepareAsync then CommitAsync) rewrites all pages through group commit, so the commit itself survives today. But the prepared records are not durable the way a 2PC prepare should be, and after such a truncation recovery can't see a prepared-but-uncommitted transaction. Prepare records can also interleave with a group-commit batch in the WAL stream, because only the per-record WAL lock serialises them.

Related: the public direct commit paths CommitTransactionAsync(ulong) and MarkTransactionCommittedAsync(ulong) take _commitLock, but in multi-process mode they do not:

  • take the SHM writer lock;
  • catch up with the shared WAL and move to its end before appending, as group commit does since #169;
  • publish the new WAL end offset or the SHM page index, or advance _lastKnownWalEndOffset.

So their records can overwrite another process's records or stay invisible to other processes, and another process's truncation can discard them. Nothing in the library calls them, but they are public.

Possible fix: route prepare and the direct commit paths through the same locked append sequence as ProcessBatchAsync (_commitLock, SHM writer lock, TryCatchUpWithSharedWal, SeekToEnd, append, publish), and keep a prepared transaction's records from being truncated until it commits or aborts. Alternatively, reject these paths when AllowMultiProcessAccess is set.

Dominant language
C#
Stars
66
Forks
6
Avg merge
1d 2h
Merged PRs (30d)
58

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from EntglDb/BLite

All issues in EntglDb/BLite

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.