fix: capture am_i_primary() result once; set ha->role before phase2; cluster_init wrapper cleanup on failure

- myapp.c: capture am_i_primary() into is_primary (avoids redundant
  second probe call); after load_primary_config() succeeds, record
  CTRL_PRIMARY role via atomic_store_explicit so cluster_init_phase2()
  sees the correct role (ha_init() defaults to CTRL_STANDBY)
- myapp.c: add #include "ha.h" for CTRL_PRIMARY, atomic_store_explicit,
  and memory_order_release
- cluster.c: cluster_init() wrapper now calls cluster_fini(c) before
  returning on create_ssl_context failure, hook failure, and
  cluster_init_phase2 failure — prevents SSL ctx and phase1 resource leak
This commit is contained in:
Rongsong Shen 2026-05-13 17:32:32 +00:00
parent 6b06aa02d9
commit 93b8616f11
2 changed files with 20 additions and 4 deletions

View file

@ -785,6 +785,7 @@ int cluster_init(cluster_t* c)
c->myconf->keyfile); c->myconf->keyfile);
if (ssl_ctx == NULL) { if (ssl_ctx == NULL) {
ERROR("create_ssl_context failed"); ERROR("create_ssl_context failed");
cluster_fini(c);
return -errno; return -errno;
} }
c->ha.ssl_ctx = ssl_ctx; c->ha.ssl_ctx = ssl_ctx;
@ -794,11 +795,18 @@ int cluster_init(cluster_t* c)
if (c->myconf->cluster_config == NULL) { if (c->myconf->cluster_config == NULL) {
rc = xce_run_hooks(&(c->hooksys), XCE_CONTROLLER_HOOK_CLUSTER, rc = xce_run_hooks(&(c->hooksys), XCE_CONTROLLER_HOOK_CLUSTER,
HOOK_BEFORE_EVENT, HOOK_DETAIL_CLUSTER_INIT, c); HOOK_BEFORE_EVENT, HOOK_DETAIL_CLUSTER_INIT, c);
if (rc < 0) if (rc < 0) {
cluster_fini(c);
return rc; return rc;
}
} }
return cluster_init_phase2(c); rc = cluster_init_phase2(c);
if (rc != 0) {
cluster_fini(c);
return rc;
}
return 0;
} }
static int make_heartbeat(cluster_t* c, endpoint_t* ep) static int make_heartbeat(cluster_t* c, endpoint_t* ep)

View file

@ -6,6 +6,7 @@
#include <unistd.h> #include <unistd.h>
#include "cluster.h" #include "cluster.h"
#include "ha.h"
#include "myconf.h" #include "myconf.h"
#include "netio.h" #include "netio.h"
#include "xce/cluster_def.h" #include "xce/cluster_def.h"
@ -43,8 +44,10 @@ int myapp_run(myconf_t* myconf)
} }
c.ha.ssl_ctx = ssl_ctx; c.ha.ssl_ctx = ssl_ctx;
/* Election: determine role before loading config */ /* Election: determine role before loading config.
if (am_i_primary(&c)) { * Capture result once — am_i_primary() probes peers and is expensive. */
int is_primary = am_i_primary(&c);
if (is_primary) {
/* Primary: load config from conf/current (FATAL if missing) */ /* Primary: load config from conf/current (FATAL if missing) */
rc = load_primary_config(&c); rc = load_primary_config(&c);
if (rc != 0) { if (rc != 0) {
@ -52,6 +55,10 @@ int myapp_run(myconf_t* myconf)
myconf_fini(myconf); myconf_fini(myconf);
return rc; return rc;
} }
/* Record election outcome so cluster_init_phase2() sees CTRL_PRIMARY.
* ha_init() unconditionally defaults ha->role to CTRL_STANDBY. */
atomic_store_explicit(&c.ha.role, (int32_t)CTRL_PRIMARY,
memory_order_release);
} else { } else {
/* Standby: fetch config from primary before Phase 2 */ /* Standby: fetch config from primary before Phase 2 */
rc = fetch_config_from_primary(&c); rc = fetch_config_from_primary(&c);
@ -60,6 +67,7 @@ int myapp_run(myconf_t* myconf)
myconf_fini(myconf); myconf_fini(myconf);
return rc; return rc;
} }
/* Role stays CTRL_STANDBY — already set by ha_init(). */
} }
/* Phase 2: full init (requires cluster_config) */ /* Phase 2: full init (requires cluster_config) */