fix(election-iomgr-refactor): config replication and RDHUP failover chain

- cluster.c: fix upgradeConfig handler (standbys apply, not primaries)
- cluster.c: fix raw_pkt_copy opcode peek (read scalar before capn_free)
- config_repl.h: enable CONF_ENABLE_UPGRADE_CONFIG=1
- config_repl.c: use client_ssl_ctx for outgoing config fetch connections
- config_repl.c: after config fetch, run cluster_init_phase2 + find_primary
- join.c: push config to newly-joined standbys on OPCode_join
- myapp.c: schedule fetch_config_from_primary after skipping own election
- ha.c: arm heartbeat timeout watchdog after find_and_connect_to_primary
This commit is contained in:
Rongsong Shen 2026-05-31 02:08:48 +00:00
parent 2f5a738b36
commit fd93997f78
6 changed files with 70 additions and 10 deletions

View file

@ -159,9 +159,10 @@ static int myreq_handler(vtask_t* task)
xce_request_t request;
xce_reply_t reply;
/* Peek at opcode to decide whether to save raw bytes before xce_decode()
* frees the capnp segment. OPCode_upgradeConfig requires the raw packet
* for xce_upgrade_config_req_extract_raw(). */
/* Capture raw packet bytes for OPCode_upgradeConfig before xce_decode()
* frees the capnp segment. xce_upgrade_config_req_extract_raw() needs
* the raw buffer to extract sha256+bytes via a fresh capn_init_mem context.
* Read opcode BEFORE capn_free to avoid accessing freed memory. */
uint8_t *raw_pkt_copy = NULL;
size_t raw_pkt_sz = 0;
{
@ -173,9 +174,12 @@ static int myreq_handler(vtask_t* task)
capn_init_mem(&peek_c, (const uint8_t *)pkt->data, (size_t)pkt->sz, 0);
peek_rp.p = capn_getp(capn_root(&peek_c), 0, 1);
read_Request(&peek_rq, peek_rp);
/* Read opcode (scalar) before capn_free — pointer fields in peek_rq
* become invalid after free, but opcode is a uint32_t field. */
int peek_opcode = (int)peek_rq.opcode;
capn_free(&peek_c);
if (peek_rq.opcode == OPCode_upgradeConfig) {
if (peek_opcode == OPCode_upgradeConfig) {
raw_pkt_copy = (uint8_t *)malloc((size_t)pkt->sz);
if (raw_pkt_copy) {
memcpy(raw_pkt_copy, pkt->data, (size_t)pkt->sz);
@ -314,8 +318,10 @@ static int myreq_handler(vtask_t* task)
break;
case OPCode_upgradeConfig:
#if CONF_ENABLE_UPGRADE_CONFIG
if (!ha_is_primary(&c->ha)) {
/* Standby cannot handle upgrade — send error reply */
/* OPCode_upgradeConfig is sent BY the primary TO standbys to push config.
* Standbys must apply it; only a primary sending this to itself is invalid. */
if (ha_is_primary(&c->ha)) {
/* Primary should not receive its own config push — ignore */
xce_reply_t ureply;
init_reply_by_req(&ureply, &request);
ureply.status = -EAGAIN;