Repository navigation
Conversation
serprex
self-requested a review
October 5, 2026 12:04
serprex
force-pushed
the
fix/source-shutdown-and-switchpoint-crossing
branch
from
October 5, 2026 12:45
bebb448 to
91ebd9a
Compare
serprex
marked this pull request as ready for review
October 5, 2026 12:45
WalSndDone exits once the reported position equals sentPtr, reading write when flush is invalid. Repeating the segment-aligned floor never reaches a mid-segment shutdown checkpoint, so the source's fast shutdown waited on walshadow until it stopped answering. Report flush only when it moves past what the connection confirmed, otherwise InvalidXLogRecPtr as pg_receivewal does. PostgreSQL moves a physical slot only on a valid flush, so restart_lsn still never passes the floor. Fixes ClickHouse#194 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
push() drained completed records once per chunk, then sealed finished segments. The walker stops at a segment end, so records a chunk carried past the boundary waited for the next push. When that chunk is the source's last, they never dispatch: with archive_mode on, shutdown switches segments before its checkpoint, so the checkpoint opens the fork segment, the idle ack stays at the XLOG_SWITCH, and the fork barrier waits on emitter_ack until a restart re-reads the segment. On a quiet source the same gap holds back a commit at a segment's head until more WAL arrives. Drain again after each seal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A clean switchover leaves the consumed frontier exactly at the descendant's switchpoint. Reconnect read that off the live chain before the pump's history did and refused it as past the fork, so the pump redialed forever. prove_branch now reports it as AtSwitchpoint and reconnect returns its connection in simple-query mode, so the crossing fetches history and proves the slot over it instead of dialing again. A frontier past the switchpoint still refuses. Refused reconnect proofs count in the switchover failure metrics alongside refused crossings. Adds e2e drills of an unpaused switchover under the default wal_sender_timeout, via repoint, with archiving on, and with the promoted standby taking over the source address. They cover this, the flush fix and the segment drain fix. Fixes ClickHouse#195 Co-Authored-By: serprex <159546+serprex@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
serprex
force-pushed
the
fix/source-shutdown-and-switchpoint-crossing
branch
from
October 5, 2026 12:58
91ebd9a to
4057975
Compare
serprex
approved these changes
Oct 5, 2026
Member
|
@timmclaughlin please sign CLA |
harshil-goel
approved these changes
Oct 5, 2026
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.
Fixes #194, fixes #195.
#194, source fast shutdown waits on walshadow.
send_statusrepeated the segment-aligned resume floor asflush.WalSndDoneonly exits once the reported position equalssentPtr, and a shutdown checkpoint ends mid-segment, so the walsender never exits. The postmaster waits until walshadow stops answering: 4m24s in a CloudNativePG in-place restart, and a CNPG switchover runs outswitchoverDelayand then immediate-stops the old primary. It's also why the switchover tests here tear walshadow down first.flushnow goes out only when it advances past what the connection last confirmed. Otherwise it isInvalidXLogRecPtr, the way pg_receivewal reports it. PostgreSQL moves a physical slot only on a valid flush (ProcessStandbyReplyMessage), sorestart_lsnstill never passes the floor.WalSndDonefalls back towrite, which already tracks the source's end of WAL. Between floor advances,pg_stat_replication.flush_lsnreads NULL for walshadow.#195, reconnect refuses a stream sitting exactly at the switchpoint. After a clean switchover, or a promotion with nothing in flight, the consumed frontier equals the descendant's switchpoint. The reconnect learns that switchpoint from the live chain before the pump's
historydoes.prove_branchrightly won't resume a branch there, sinceStartReplicationanswers a historic start at its switchpoint with the next timeline and no COPY. So the pump fell back to redial forever withconsumed frontier X sits past the fork X, and only a restart recovered it.resume_pointnow reports that case asAtSwitchpoint, and the pump hands it to the existing crossing, the same way it already does when its own chain shows the branch exhausted.prove_branchand its tests are unchanged, and a frontier past the switchpoint still refuses.Records past a segment a push seals waited for the next push.
WalStream::pushdrained completed records once per chunk, then sealed segments. The walker stops at a segment end, so a chunk crossing a boundary left the next segment's records buffered. Witharchive_modeon, shutdown switches segments before its checkpoint, so the source's final chunk carries the XLOG_SWITCH plus the checkpoint that opens the fork segment. The checkpoint never dispatched, the idle ack stayed at the switch, and the fork barrier waited onemitter_ackuntil a restart. Once the shutdown fix above lets a switchover end cleanly, this is what a CloudNativePG switchover hits. On a quiet source the same gap holds back a commit at a segment's head.pushnow drains again after each seal.Tests:
wire_flush_reports_only_advances,resume_point_hands_the_switchpoint_to_the_crossing,push_dispatches_records_past_a_segment_it_seals(unit)unpaused_switchover_stops_promptly_and_crosses_at_the_switchpoint(control_plane_e2e): no pause, defaultwal_sender_timeout, fast-stop the primary, promote, then repoint. On main it fails at the stop (pg_ctl: server does not shut down). Here it passes.archiving_switchover_crosses_a_fork_segment_with_no_transactions(control_plane_e2e): the same switchover witharchive_mode = on. Without the third commit it stalls at the fork barrier.Ran locally on PG 18.6 / ClickHouse 26.9 (arm64): fmt, clippy
-D warnings,cargo doc -D warnings, and the control_plane_e2e, source_on_promoted_timeline_e2e, bin_stream_e2e, backfill_gap_across_promotion and source_reconnect suites. Also ran on a CloudNativePG 1.28 cluster under write load (archive_mode on). An in-place primary restart stops in under a second and walshadow reconnects. A planned switchover and a primary kill both cross live with no daemon restart. ClickHouse matches the source after each.🤖 Generated with Claude Code