feat(ha-heartbeat-committed-propagation): add reconcile-free ha_observe_heartbeat_committed (task 2.1)
Strict-monotonic updater for a standby's learned committed position: advance last_known_committed_lsn only when strictly greater (zero/lower no-op), set the config tag together (tag-before-lsn release ordering for reader safety). No ha_rejoin_reconcile, no truncation, no other mutation (Req 2.1-2.3, 3.1, 3.3). 4 revert-detecting unit tests; controller suite 0 failures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
282a82ff7e
commit
8bfa861be2
6 changed files with 273 additions and 1 deletions
|
|
@ -4919,6 +4919,46 @@ void ha_on_heartbeat_received(ha_state_t *ha)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ha_observe_heartbeat_committed: reconcile-free monotonic learn of the
|
||||
* primary's committed position from a heartbeat (ha-heartbeat-committed-
|
||||
* propagation, Req 2.1, 2.2, 2.3, 3.1, 3.3).
|
||||
*
|
||||
* Single-receiver-thread path (controller request handling), so a relaxed
|
||||
* compare-then-store is sufficient. The config tag is written BEFORE the LSN
|
||||
* (both release-ordered) so a concurrent acquire-load reader that observes the
|
||||
* advanced LSN never pairs it with a stale tag.
|
||||
*
|
||||
* Advisory only: NO ha_rejoin_reconcile / NO WAL truncation / NO change to any
|
||||
* produced/persisted committed, role, term, or applied state. This is the
|
||||
* explicit distinction from cluster_apply_ctrlhello_reply (which truncates).
|
||||
*/
|
||||
void ha_observe_heartbeat_committed(cluster_t *c, uint64_t committed_lsn,
|
||||
uint64_t committed_config_tag)
|
||||
{
|
||||
if (!c) return;
|
||||
ha_state_t *ha = &c->ha;
|
||||
|
||||
uint64_t cur = atomic_load_explicit(&ha->last_known_committed_lsn,
|
||||
memory_order_acquire);
|
||||
/* Monotonic no-op: a zero (absent/liveness-only) or non-advancing LSN must
|
||||
* leave the learned position — and its config tag — untouched (Req 2.2). */
|
||||
if (committed_lsn == 0 || committed_lsn <= cur)
|
||||
return;
|
||||
|
||||
/* Tag moves with the LSN, never independently regressed (Req 2.3): publish
|
||||
* the tag first so the LSN's release store carries the matching tag. */
|
||||
atomic_store_explicit(&ha->last_known_committed_config_tag,
|
||||
committed_config_tag, memory_order_release);
|
||||
atomic_store_explicit(&ha->last_known_committed_lsn, committed_lsn,
|
||||
memory_order_release);
|
||||
/* Reconcile-free: nothing else is touched (Req 3.1, 3.3). */
|
||||
tlog(TLOG_DEBUG3,
|
||||
"HA: learned committed_lsn=%" PRIu64 " config_tag=%" PRIu64
|
||||
" from heartbeat (was %" PRIu64 ")",
|
||||
committed_lsn, committed_config_tag, cur);
|
||||
}
|
||||
|
||||
void ha_disarm_heartbeat_timeout_vtask(ha_state_t *ha)
|
||||
{
|
||||
(void)ha;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue