#pragma once /* * repl.h — P2-1: Replicator structures and public API. * Fan-out TCP replication via existing iomgr/SSL endpoint pipeline. * ACKs processed in io_worker read callback (NOT vtaskmgr) to prevent deadlock. */ #include #include #include #include #include "config.h" #include "mylock.h" #include "wal_types.h" /* wal_entry_hdr_t — P2-4: use wal_types.h to break circular include */ /* Max queued-but-unacknowledged sends per standby before eviction to catch-up */ #define MAX_PENDING_ACKS 16 /* Endpoint is an opaque pointer — full type in netio.h (avoid heavy include) */ typedef void* repl_ep_t; /* Per-standby connection slot */ typedef struct { repl_ep_t ep; /* NULL = slot empty */ _Atomic uint64_t acked_lsn; /* Last WAL LSN ACKed (walAck) */ _Atomic uint64_t acked_config_lsn; /* Last config LSN ACKed (upgradeConfigAck) */ _Atomic int in_catch_up; /* Non-zero while catching up */ uint64_t join_applied_lsn; /* LSN standby reported on reconnect */ char host[XCE_MAXNAME_LEN]; uint32_t port; uint64_t last_disconnected_lsn; time_t last_disconnect_time; uint32_t pending_ack_count; /* Sends not yet ACKed; evict if > MAX_PENDING_ACKS */ } standby_conn_t; /* Replicator — embedded in persist_t or cluster_t (P2-4). * Named tag replicator_s matches the forward declaration in persist.h. */ typedef struct replicator_s { standby_conn_t standbys[MAX_STANDBYS]; int nstandbys; /* Active standby count */ mylock_t lock; /* Protects standbys[], nstandbys */ pthread_cond_t ack_cond; /* Signaled when any ACK arrives */ pthread_mutex_t ack_lock; /* Guards ack_cond */ } replicator_t; /* Lifecycle */ int repl_init(replicator_t *r); void repl_fini(replicator_t *r); /* Standby management */ int repl_add_standby(replicator_t *r, repl_ep_t ep, const char *host, uint32_t port); void repl_remove_standby(replicator_t *r, repl_ep_t ep); void repl_expire_disconnect_slots(replicator_t *r, time_t now_s, uint32_t snap_interval_s); /* Replication send (stub in P2-1; wired in P2-4) */ int repl_broadcast(replicator_t *r, const wal_entry_hdr_t *hdr, const void *payload, uint32_t payload_len); /* WAL ACK handling — call from io_worker read callback ONLY */ void repl_on_ack(replicator_t *r, repl_ep_t ep, uint64_t acked_lsn); /* Config ACK handling — call from io_worker read callback ONLY (task 8.1) */ void repl_on_config_ack(replicator_t *r, repl_ep_t ep, uint64_t acked_config_lsn); /* Sync replication (stub in P2-1; wired in P2-3) */ int repl_wait_ack(replicator_t *r, uint64_t target_lsn, uint32_t timeout_ms); /* Majority-quorum ACK wait (task 7.3) */ int repl_wait_majority_ack(replicator_t *r, uint32_t timeout_ms, uint8_t ack_op); /* WAL trim guard */ uint64_t repl_trim_lsn(replicator_t *r, uint64_t checkpoint_lsn, uint32_t snap_interval_s); /* Catch-up state management */ /* Mark standby as entering catch-up mode; stores join_applied_lsn */ void repl_start_catchup(replicator_t *r, repl_ep_t ep, uint64_t join_applied_lsn); /* Mark standby catch-up complete (called on OP_replCatchUpDone receipt) */ void repl_complete_catchup(replicator_t *r, repl_ep_t ep); /* Returns 1 if standby needs a full snapshot transfer (its LSN predates oldest WAL). * oldest_wal_lsn == 0 means no WAL exists — no snapshot needed for LSN 0 standbys. */ int repl_needs_snapshot(replicator_t *r, uint64_t standby_lsn, uint64_t oldest_wal_lsn);