fix(controller-status): primaryName from role (primary self-reports; standby=unknown) — ha->primary_host is vestigial (E2E finding, task 5.1)

This commit is contained in:
Rongsong Shen 2026-06-20 06:03:00 +00:00
parent 6747304184
commit ade0081609
2 changed files with 99 additions and 26 deletions

View file

@ -33,9 +33,19 @@
* Field sourcing:
* responderName / clusterName — own peerinfo / loaded cluster config
* responderRole / term — ha->role / ha->term atomics (Req 3.2, 6.1)
* primaryName — ha->primary_host under ha->lock; empty
* string when no primary is known (Req 1.3,
* 2.2, 2.3 — client renders empty as "unknown")
* primaryName — derived from role + voted_for_name (NOT the
* vestigial, never-written ha->primary_host):
* role==CTRL_PRIMARY → responder's OWN name
* (this node IS the primary; Req 2.1)
* role==CTRL_STANDBY → ha->voted_for_name
* (the elected leader it follows; Req 2.3),
* but only if it is a real peer name —
* empty or "self" → empty (Req 2.2)
* else (CTRL_ELECTING/CTRL_INIT) → empty —
* no confirmed primary (Req 2.2)
* read under ha->lock (guards voted_for_name);
* empty string ⇒ client renders "unknown"
* (Req 1.3)
* configVersion — loaded config_version_tag (Req 5.1)
* configChecksum — lowercase-hex of myconf->config_sha256[32]
* (64-char Text; Req 5.2 content checksum,
@ -79,11 +89,20 @@ void ctrlstatus_fill(cluster_t* c, xce_ctrlstatus_t* st)
memory_order_acquire);
st->term = atomic_load_explicit(&ha->term, memory_order_acquire);
/* primary identity — guarded by ha->lock (Req 2.2, 2.3) */
pthread_mutex_lock(&ha->lock);
st->primaryName = (ha->primary_host[0] != '\0') ? strdup(ha->primary_host)
: strdup("");
pthread_mutex_unlock(&ha->lock);
/* primary identity (Req 2.1/2.2/2.3). Only the PRIMARY can authoritatively
* name the primary — itself. The controller does NOT track the current
* primary's NAME on a standby: ha->primary_host is vestigial (never written)
* and ha->voted_for_name is "who I last voted for" (frequently this node
* itself), NOT the elected leader — using it makes a standby misreport
* itself as primary and misdirects the authoritative redirect. So a non-
* primary responder reports an empty primaryName ("unknown"); the client's
* authoritative path (xcecli_ctrlstatus_primary) then reaches the real
* primary by master rotation and gets the authoritative self-report. */
if (st->responderRole == (uint8_t)CTRL_PRIMARY) {
st->primaryName = strdup(st->responderName); /* this node IS the primary */
} else {
st->primaryName = strdup(""); /* unknown — not reliably known off-primary */
}
/* loaded config version (+ committed version) */
st->configVersion = mc ? mc->config_version_tag : 0;