feat: P2-5 repl_start/complete_catchup, repl_needs_snapshot — standby catch-up state
Implement the catch-up state machine as testable pure-logic functions: - repl_start_catchup(): marks standby in_catch_up=1, stores join_applied_lsn - repl_complete_catchup(): clears in_catch_up=0, broadcasts ack_cond so any blocked repl_wait_ack() re-checks the ACK condition immediately - repl_needs_snapshot(): pure predicate — returns 1 when standby LSN predates oldest surviving WAL segment (snapshot transfer required), 0 otherwise Also fixes pre-existing linker error: repl.c was missing from controller_src (xce_controller production binary), causing undefined references to repl_* symbols introduced in P2-4. 7 new TDD tests in test_repl_catchup.c — all pass. Existing tests green.
This commit is contained in:
parent
3563d7387b
commit
6e4fd1aa81
5 changed files with 196 additions and 0 deletions
|
|
@ -296,3 +296,49 @@ uint64_t repl_trim_lsn(replicator_t *r, uint64_t checkpoint_lsn,
|
|||
|
||||
return min_lsn;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Catch-up state management (P2-5)
|
||||
* ============================================================ */
|
||||
|
||||
void repl_start_catchup(replicator_t *r, repl_ep_t ep, uint64_t join_applied_lsn)
|
||||
{
|
||||
mylock_lock(&r->lock);
|
||||
for (int i = 0; i < MAX_STANDBYS; i++) {
|
||||
if (r->standbys[i].ep == ep) {
|
||||
r->standbys[i].join_applied_lsn = join_applied_lsn;
|
||||
atomic_store_explicit(&r->standbys[i].in_catch_up, 1,
|
||||
memory_order_release);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mylock_unlock(&r->lock);
|
||||
}
|
||||
|
||||
void repl_complete_catchup(replicator_t *r, repl_ep_t ep)
|
||||
{
|
||||
mylock_lock(&r->lock);
|
||||
for (int i = 0; i < MAX_STANDBYS; i++) {
|
||||
if (r->standbys[i].ep == ep) {
|
||||
atomic_store_explicit(&r->standbys[i].in_catch_up, 0,
|
||||
memory_order_release);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mylock_unlock(&r->lock);
|
||||
|
||||
/* Broadcast so any blocked repl_wait_ack() re-checks the ACK condition */
|
||||
pthread_mutex_lock(&r->ack_lock);
|
||||
pthread_cond_broadcast(&r->ack_cond);
|
||||
pthread_mutex_unlock(&r->ack_lock);
|
||||
}
|
||||
|
||||
int repl_needs_snapshot(replicator_t *r, uint64_t standby_lsn,
|
||||
uint64_t oldest_wal_lsn)
|
||||
{
|
||||
(void)r;
|
||||
/* No WAL at all: empty standby can start from LSN 0 without a snapshot */
|
||||
if (oldest_wal_lsn == 0) return 0;
|
||||
/* Standby LSN predates oldest surviving WAL segment — full snapshot required */
|
||||
return (standby_lsn < oldest_wal_lsn) ? 1 : 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue