feat(ha): reference-counted ha_elect_ctx_t lifecycle (ha-elect-ctx-lifecycle)
Replace the deliberate election-carrier leak with an atomic refcount: a bias reference held by ha->elect_ctx plus one reference per captured vote endpoint, released via a new endpoint_t.on_fini teardown-completion hook (fired once, before ep->data is freed). Both real-election and PreVote capture sites (raft_cb_send_vote_request, raft_cb_send_pre_vote_request) increment on capture; both publish sites (ha_start_election_async, ha_start_prevote_async) now atomic_exchange the outgoing carrier and release it instead of leaking or freeing outright, so a still-outstanding vote endpoint keeps the superseded carrier alive until its own teardown completes. Verified: 758+ controller tests green, isolated LeakSanitizer run shows zero ha_elect_ctx_t leaks across many election/PreVote rounds, no premature-free/UAF under supersession, and a live 10-round HA soak (36 jobs, zero loss, all 3 nodes served as primary).
This commit is contained in:
parent
58e047f533
commit
6529dcf08f
14 changed files with 879 additions and 22 deletions
|
|
@ -955,6 +955,19 @@ int endpoint_set_on_connected(endpoint_t* ep, void (*cb)(endpoint_t*))
|
|||
return 0;
|
||||
}
|
||||
|
||||
int endpoint_set_on_fini(endpoint_t* ep, void (*cb)(endpoint_t*))
|
||||
{
|
||||
if (ep == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mylock_lock(&(ep->lock));
|
||||
ep->on_fini = cb;
|
||||
mylock_unlock(&(ep->lock));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int endpoint_enq(endpoint_t* ep, data_item_t* it)
|
||||
{
|
||||
int rc = 0;
|
||||
|
|
@ -1091,6 +1104,15 @@ int endpoint_is_tearing_down(endpoint_t* ep)
|
|||
void endpoint_fini(endpoint_t* ep)
|
||||
{
|
||||
dataq_fini(&(ep->outq));
|
||||
|
||||
/* ha-elect-ctx-lifecycle task 1.1: fire the completion hook (if set)
|
||||
* immediately before ep->data is freed, so a consumer can observe
|
||||
* teardown completion while ep->data is still valid. Does not change
|
||||
* teardown ordering/timing — same free happens right after, unconditionally. */
|
||||
if (ep->on_fini) {
|
||||
ep->on_fini(ep);
|
||||
}
|
||||
|
||||
FREEUP(ep->data);
|
||||
|
||||
if (ep->fd >= 0) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue