feat(component-failover-adoption): reconcile N_MAX_MASTERS with MAX_HA_CANDIDATES
N_MAX_MASTERS (client.h) now derives from config.h's MAX_HA_CANDIDATES instead of an independently-maintained literal (3 vs 4 previously). Fixes worker's and scheduler's hardcoded `> 3` startup checks to reference the constant symbolically, and updates the client-retry test fixture so it doesn't exercise an uninitialized 4th slot. Task 1.1 of component-failover-adoption (Requirement 1 AC7).
This commit is contained in:
parent
0df1cf5f8d
commit
fe8b4b86bf
5 changed files with 174 additions and 93 deletions
|
|
@ -6,6 +6,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "netio.h"
|
||||
#include "request.h"
|
||||
#include "xce/types.h"
|
||||
|
|
@ -25,7 +26,9 @@ typedef void* xcecli_ctx_t;
|
|||
*/
|
||||
typedef int (*xcecli_reconnect_cb)(xcecli_ctx_t ctx, void* arg);
|
||||
|
||||
#define N_MAX_MASTERS (3)
|
||||
/* N_MAX_MASTERS derives from config.h's MAX_HA_CANDIDATES so the two limits
|
||||
* can never silently diverge (Req 1 AC7, component-failover-adoption). */
|
||||
#define N_MAX_MASTERS MAX_HA_CANDIDATES
|
||||
|
||||
typedef struct {
|
||||
int nmasters;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,14 @@
|
|||
#include "xce/client_failover.h"
|
||||
#include "xce/errnox.h"
|
||||
|
||||
/* Req 1.7 (component-failover-adoption): client.h's N_MAX_MASTERS must derive
|
||||
* from config.h's MAX_HA_CANDIDATES, not be an independently-maintained
|
||||
* literal that can silently diverge from it (was 3 vs. 4). Compile-time so a
|
||||
* future re-divergence fails the build, not just a test run. */
|
||||
_Static_assert(N_MAX_MASTERS == MAX_HA_CANDIDATES,
|
||||
"N_MAX_MASTERS (client.h) must derive from MAX_HA_CANDIDATES "
|
||||
"(config.h), not be independently defined");
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════════════
|
||||
* Harness implementation
|
||||
* ════════════════════════════════════════════════════════════════════════ */
|
||||
|
|
@ -460,13 +468,17 @@ static void test_classify_unknown_is_terminal(void)
|
|||
* live connect path is covered by E2E task 6.2.
|
||||
* ════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* Build a 3-master client config (distinct host:port) the rotator selects over.
|
||||
* Strings are static-duration so the api_ctx may borrow them by pointer. */
|
||||
/* Build a full N_MAX_MASTERS-candidate client config (distinct host:port) the
|
||||
* rotator selects over. Strings are static-duration so the api_ctx may borrow
|
||||
* them by pointer. All N_MAX_MASTERS slots are genuinely initialized with
|
||||
* literal values -- do NOT let this list fall short of N_MAX_MASTERS entries,
|
||||
* or the copy loop below silently copies an uninitialized (NULL host, port 0)
|
||||
* slot once N_MAX_MASTERS is raised (Req 1 AC7, component-failover-adoption). */
|
||||
static void fo_make_client_masters(xce_client_config_t *conf)
|
||||
{
|
||||
static char *hosts[N_MAX_MASTERS] = { "10.30.0.1", "10.30.0.2",
|
||||
"10.30.0.3" };
|
||||
static int ports[N_MAX_MASTERS] = { 8001, 8002, 8003 };
|
||||
"10.30.0.3", "10.30.0.4" };
|
||||
static int ports[N_MAX_MASTERS] = { 8001, 8002, 8003, 8004 };
|
||||
|
||||
memset(conf, 0, sizeof(*conf));
|
||||
conf->nmasters = N_MAX_MASTERS;
|
||||
|
|
@ -485,6 +497,27 @@ static void fo_make_api_ctx(api_ctx_t *ac, xce_client_config_t *conf)
|
|||
ac->failover.cur_master = 0;
|
||||
}
|
||||
|
||||
/* Req 1.7: fo_make_client_masters() must genuinely initialize every one of
|
||||
* N_MAX_MASTERS slots -- not just leave conf->nmasters == N_MAX_MASTERS while
|
||||
* silently leaving a trailing slot at its NULL/0 memset default. Guards
|
||||
* against the exact regression this task fixed: N_MAX_MASTERS raised without
|
||||
* also extending the fixture's literal host/port list. */
|
||||
static void test_client_masters_hold_n_max_candidates(void)
|
||||
{
|
||||
xce_client_config_t conf;
|
||||
fo_make_client_masters(&conf);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(N_MAX_MASTERS, conf.nmasters);
|
||||
for (int i = 0; i < N_MAX_MASTERS; i++) {
|
||||
TEST_ASSERT_NOT_NULL(conf.masters[i]);
|
||||
TEST_ASSERT_TRUE(conf.master_ports[i] != 0);
|
||||
}
|
||||
TEST_ASSERT_EQUAL_STRING("10.30.0.4", conf.masters[N_MAX_MASTERS - 1]);
|
||||
TEST_ASSERT_EQUAL_INT(8004, conf.master_ports[N_MAX_MASTERS - 1]);
|
||||
|
||||
printf("test_client_masters_hold_n_max_candidates: PASS\n");
|
||||
}
|
||||
|
||||
static void fo_set_hint(api_ctx_t *ac, const char *host, uint16_t port)
|
||||
{
|
||||
strncpy(ac->ctx.redirect_hint_host, host, XCE_MAXHOSTNAME_LEN - 1);
|
||||
|
|
@ -550,7 +583,14 @@ static void test_next_target_rotates_and_wraps(void)
|
|||
TEST_ASSERT_EQUAL_INT(8003, port);
|
||||
TEST_ASSERT_EQUAL_INT(2, ac.failover.cur_master);
|
||||
|
||||
/* wrap back to master 0 */
|
||||
TEST_ASSERT_EQUAL_INT(0, xce_failover_next_target(&ac, host, sizeof(host),
|
||||
&port));
|
||||
TEST_ASSERT_EQUAL_STRING("10.30.0.4", host);
|
||||
TEST_ASSERT_EQUAL_INT(8004, port);
|
||||
TEST_ASSERT_EQUAL_INT(3, ac.failover.cur_master);
|
||||
|
||||
/* wrap back to master 0 once every configured candidate (N_MAX_MASTERS
|
||||
* of them) has been visited */
|
||||
TEST_ASSERT_EQUAL_INT(0, xce_failover_next_target(&ac, host, sizeof(host),
|
||||
&port));
|
||||
TEST_ASSERT_EQUAL_STRING("10.30.0.1", host);
|
||||
|
|
@ -1681,6 +1721,7 @@ void test_libxce_retry(void)
|
|||
RUN_TEST(test_classify_dup_replay_rule);
|
||||
RUN_TEST(test_classify_zero_is_success);
|
||||
RUN_TEST(test_classify_unknown_is_terminal);
|
||||
RUN_TEST(test_client_masters_hold_n_max_candidates);
|
||||
RUN_TEST(test_next_target_hint_first_then_consumed);
|
||||
RUN_TEST(test_next_target_rotates_and_wraps);
|
||||
RUN_TEST(test_next_target_hint_then_fallback_rotation);
|
||||
|
|
|
|||
|
|
@ -311,10 +311,10 @@ int main(int argc, char* argv[])
|
|||
"identity?).\n");
|
||||
return 1;
|
||||
}
|
||||
if (cluster_cfg.candidates_count > 3) {
|
||||
if (cluster_cfg.candidates_count > N_MAX_MASTERS) {
|
||||
WARN("xce_scheduler: --peers has %d candidates; "
|
||||
"only <=3 validated for HA",
|
||||
cluster_cfg.candidates_count);
|
||||
"only <=%d validated for HA",
|
||||
cluster_cfg.candidates_count, N_MAX_MASTERS);
|
||||
}
|
||||
INFO("HA cluster config: %d candidate(s), identity=%s",
|
||||
cluster_cfg.candidates_count, cluster_cfg.identity);
|
||||
|
|
|
|||
|
|
@ -411,11 +411,11 @@ int main(int argc, char* argv[])
|
|||
"Use -n.\n");
|
||||
return 1;
|
||||
}
|
||||
if (cluster_cfg.candidates_count > 3) {
|
||||
if (cluster_cfg.candidates_count > N_MAX_MASTERS) {
|
||||
fprintf(stderr,
|
||||
"xcecd: WARN: --peers has %d candidates; "
|
||||
"only <=3 validated for HA\n",
|
||||
cluster_cfg.candidates_count);
|
||||
"only <=%d validated for HA\n",
|
||||
cluster_cfg.candidates_count, N_MAX_MASTERS);
|
||||
}
|
||||
XCECD_LOG(XCE_LOG_INFO,
|
||||
"HA cluster config: %d candidate(s), identity=%s",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue