feat(controller): clusterconfig-schema-split task 2.1 — cluster_open_listener two-tier port fallback

Replaces the cluster_config->port fallback (dead after task 1.2) with:
--peers candidate match (unchanged, including single self-referencing
entries for a custom single-node port) -> hardcoded XCE_CONTROLLER_DEFAULT_PORT
(9990) when --peers was never passed at all. The --peers-given-but-local-
name-absent case still returns -EINVAL and refuses to start, unchanged.

Also folds in task 1.3's discovery (HashZArrayConfig/ResmgrConfig capnp
structs left orphaned by tasks 1.1/1.2, breaking codegen) into
requirements.md (new Req 2.5)/design.md/research.md/tasks.md, and fixes
a design.md citation error (validate_peer_count -> xce_parse_peers) found
during task 2.1's review.
This commit is contained in:
Rongsong Shen 2026-07-21 03:36:01 +00:00
parent 0205ac3cd2
commit 1229f9a945
5 changed files with 53 additions and 13 deletions

View file

@ -1213,6 +1213,14 @@ int cluster_init_phase1(cluster_t* c)
return 0;
}
/* Hardcoded fallback listen port, used only when --peers was never passed
* at all (true single-node mode, peers_cfg.candidates_count == 0). An
* operator who wants a non-default single-node port passes a single
* self-referencing --peers <name>=<host>:<port> entry instead, which
* resolves via the candidate-match branch below, not this constant.
* Matches the pre-schema-split ClusterConfig.port default value. */
#define XCE_CONTROLLER_DEFAULT_PORT 9990
int cluster_open_listener(cluster_t* c)
{
int rc;
@ -1224,9 +1232,21 @@ int cluster_open_listener(cluster_t* c)
if (c->ep.fd >= 0)
return 0;
/* Determine listen port: prefer per-candidate port from --peers list,
* fall back to cluster_config->port if config is already loaded. */
/* Determine listen port:
* 1. Search --peers candidates for the local name.
* - Matched with a nonzero port: bind to it (unchanged happy
* path; also how a single-node operator gets a custom port,
* via a single self-referencing --peers entry).
* - Matched with port == 0 (malformed --peers entry): falls
* through to the hardcoded default below, same as today's
* tolerated case.
* - Not matched at all, but --peers WAS passed (candidates_count
* > 0): likely operator misconfiguration (own name typo'd or
* omitted) -- refuse to start, unchanged from today.
* 2. --peers never passed at all (candidates_count == 0): true
* single-node mode, use the hardcoded default. Always succeeds. */
uint32_t my_port = 0;
bool matched = false;
{
const xce_cluster_config_t* pcfg = &c->myconf->peers_cfg;
for (int j = 0; j < pcfg->candidates_count; j++) {
@ -1235,19 +1255,20 @@ int cluster_open_listener(cluster_t* c)
: pcfg->candidates[j].hostname;
if (strncmp(key, c->myconf->name, XCE_MAXNAME_LEN - 1) == 0) {
my_port = pcfg->candidates[j].port;
matched = true;
break;
}
}
}
if (my_port == 0) {
if (c->myconf->cluster_config != NULL) {
my_port = (uint32_t)c->myconf->cluster_config->port;
} else {
ERROR("cluster_open_listener: no port in --peers and cluster_config "
"not yet loaded; specify port in --peers list");
if (!matched && pcfg->candidates_count > 0) {
ERROR("cluster_open_listener: local name '%s' not found in "
"--peers list; refusing to start", c->myconf->name);
return -EINVAL;
}
}
if (my_port == 0) {
my_port = XCE_CONTROLLER_DEFAULT_PORT;
}
rc = endpoint_init(&(c->ep), AF_INET, SOCK_STREAM, (int)my_port, 5);
if (rc < 0)