fix(election-iomgr-refactor): Raft election, config decode, and RDHUP chain

- ha.c: self-vote in ha_start_election_async (Raft invariant)
- ha.c: heartbeat_timeout_ms for hb_timeout_thread (not election_timeout_ms)
- ha.c: clear voted_for before RDHUP jitter (stale vote from dead primary)
- ha.c: same-term voted_for check in RDHUP jitter
- config_repl.c/h: use xce_decode for upgradeConfig (capnp extraction before capn_free)
- cluster.c: fix upgradeConfig handler direction (standbys apply, primaries skip)
- cluster.c: remove raw_pkt_copy hack; use req directly
- join.c: push config to newly-joined standbys
- typemap.h/request.h/request.c: raw_sha256/raw_bytes fields for decoded upgradeConfig
- test_ha_failover.c: update heartbeat timeout test to use g_fast_cfg
This commit is contained in:
Rongsong Shen 2026-05-31 03:54:30 +00:00
parent 1ded1022fb
commit dbb750ebd3
8 changed files with 198 additions and 102 deletions

View file

@ -104,10 +104,19 @@ extern int xce_replconfig_reply_ssl_decode(SSL *ssl,
size_t *out_len);
/*
* xce_upgrade_config_req_extract: extract bytes from a decoded
* OP_upgradeConfig request. Returns -ENOTSUP — see request.c
* for the architectural finding. Use xce_upgrade_config_req_extract_raw
* with the raw packet buffer instead.
* xce_free_request: free an xce_request_t and all owned sub-fields,
* including the raw_sha256/raw_bytes fields on upgrade_config_req_t
* that the generated free_Request() does not know about.
* Use this everywhere instead of calling free_Request() directly.
*/
extern void xce_free_request(xce_request_t *req);
/*
* xce_upgrade_config_req_extract: extract sha256 + bytes from a decoded
* OP_upgradeConfig request. xce_decode() stores malloc'd copies in
* req->body.upgradeconfigrequestmsg->raw_sha256 / raw_bytes before
* capn_free() runs. Returns shallow pointers (owned by req); caller
* must NOT free them. Returns -EINVAL if fields are missing.
*/
extern int xce_upgrade_config_req_extract(const xce_request_t *req,
uint8_t **out_bytes,

View file

@ -348,8 +348,22 @@ struct repl_config_push_reply_s {
};
struct upgrade_config_req_s {
xce_data_t *sha256; /* 32-byte SHA-256 of proposed config */
xce_data_t *bytes; /* serialised ClusterConfig blob */
/* Legacy decoded fields — populated by generated decode_UpgradeConfigRequest()
* via decode_Data_ptr. These are structurally broken for List(UInt8) wire
* fields (decode_Data_ptr reads a discriminant and misinterprets the bytes),
* but must remain for the generated code to compile. Do NOT use these for
* actual byte extraction. */
xce_data_t *sha256; /* broken: always a bogus xce_jobs_data_t */
xce_data_t *bytes; /* broken: always a bogus xce_jobs_data_t */
/* Correct raw bytes extracted by xce_decode() before capn_free() runs,
* using UpgradeConfigRequest_get_sha256/bytes + capn_getv8.
* Both are malloc'd and owned here; freed by free_upgrade_config_req_raw()
* called from free_Request() after free_UpgradeConfigRequest().
* raw_sha256 is exactly 32 bytes when non-NULL. */
uint8_t *raw_sha256; /* 32-byte SHA-256, malloc'd, or NULL */
uint8_t *raw_bytes; /* serialised ClusterConfig blob, malloc'd, or NULL */
size_t raw_bytes_len; /* length of raw_bytes */
};
struct upgrade_config_reply_s {