Exp 233: reject async checkpoint worker#250
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hypothesis
Resqlite's writer WAL hook runs a PASSIVE checkpoint synchronously when a
commit crosses 500 frames. Exp 029 showed that proactive checkpoints improve
write tails, but the threshold-crossing caller pays the checkpoint I/O before
its write future can complete. Friday's moonshot tested whether the policy
could stay intact while a dedicated writable connection performed that work
after the commit released the write lock.
The acceptance target was at least a 10% first-crossing improvement. The
declared kill conditions were a sustained-write p99 that failed to improve, a
foreground-read regression, or a WAL that failed to settle.
Approach
The archived prototype replaced the inline hook work with a mutex-protected
idle / requested / running / rerunrequest state. After a successfultop-level commit, the writer isolate claimed that state and woke a dedicated
checkpoint isolate owning a separately keyed writable connection. That worker
ran
SQLITE_CHECKPOINT_PASSIVE; close joined the writer and performed a finalunconditional drain so cross-sender message ordering could not strand a
claimed checkpoint.
The focused A/B paired exp 132's known 529-frame first crossing with 3,000
awaited 8 KiB writes, foreground reads every 100 writes, and immediate/250 ms
observational WAL samples. Full detail is in
experiments/233-async-checkpoint-worker.md.
The final PR is publication-only: all runtime code, worker-specific tests, and
the focused harness have been removed. The exact candidate remains at
archive/exp-233.Results
The mechanism works once: the first threshold crossing is roughly 2x
faster, and the WAL samples prove the writer replies before the background
checkpoint finishes. Under sustained writes, though, every central/tail metric
regresses by multiples and foreground reads slow in both orderings. The
candidate WAL grows to 12,377 frames; two candidate-first repeats remain 2,689
and 3,625 frames behind after 250 ms.
The root cause is architectural:
pages_in_wal >= 500is a level trigger. Oncecheckpoint work becomes asynchronous, later commits continue observing the
same true level and repeatedly request/rerun PASSIVE work. Coalescing bounds
messages but does not supply a WAL-generation or high-water re-arm rule, so the
worker contends with the foreground workload.
Outcome
Rejected. The prototype clears the one-shot ceiling and fails every
sustained kill condition. Shipping it would also retain a second connection,
isolate lifecycle, key propagation, FFI surface, four-state native scheduler,
and close protocol without representative evidence that inline checkpoint wall
is common enough to repay that complexity.
Reopen only with a reset-aware or high-water trigger that cannot remain armed
throughout a burst. The sustained write/read lane—not the attractive first
crossing—must be the load-bearing gate, and a downstream/release trace should
establish that synchronous checkpoint wall is materially user-visible.
Test plan
checkpoint/encryption/close integration tests 3/3
build-hook tests 101/101
origin/maindart run benchmark/finalize_experiment.dart --experiment=experiments/233-async-checkpoint-worker.mddart run benchmark/check_experiment_dispositions.dartdart analyze --fatal-infosgit diff --check