feat(ha-single-leader-role): direct CTRL_PRIMARY promotion + own-term gate via shared sequence (task 2.2)
This commit is contained in:
parent
b7a69afa0b
commit
c089fb69f3
3 changed files with 177 additions and 59 deletions
|
|
@ -59,6 +59,27 @@
|
|||
* replaces these with the WAL_NOOP symbol once it lands. */
|
||||
#define WAL_NOOP_VALUE 40u
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Broadcast drop-hook (precedent: test_p2_integration.c:32/313, */
|
||||
/* test_commit_engine.c:1133/1308; hook defined in repl.c:21). */
|
||||
/* The lifecycle fixture registers fake int g_lc_eps[] endpoints via */
|
||||
/* repl_add_standby; the own-term WAL_NOOP append now broadcasts via */
|
||||
/* repl_broadcast → xce_wal_batch_req_raw(ep), which would dereference */
|
||||
/* ep->peer past the 4-byte int (ASAN global-buffer-overflow at */
|
||||
/* request.c). Installing this hook drops the wire send harmlessly. */
|
||||
/* ------------------------------------------------------------------ */
|
||||
#ifdef XCE_TESTING
|
||||
extern int (*repl_broadcast_send_hook)(void *ep,
|
||||
wal_catchup_entry_t **entries,
|
||||
int n_entries);
|
||||
static int lc_drop_send_hook(void *ep, wal_catchup_entry_t **entries,
|
||||
int n_entries)
|
||||
{
|
||||
(void)ep; (void)entries; (void)n_entries;
|
||||
return 0; /* pretend success, drop the data */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Test-local fixtures */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
|
@ -652,6 +673,12 @@ static uint64_t lifecycle_cluster_setup(const char *suffix, int n_peers,
|
|||
commit_engine_init(&g_lc.commit, &g_lc.persist, n_peers, n_vcpus));
|
||||
repl_set_commit_engine(&g_lc.persist.repl, &g_lc.commit);
|
||||
|
||||
/* Drop wire sends from the own-term WAL_NOOP broadcast — the fake int
|
||||
* endpoints have no real ep->peer (see lc_drop_send_hook above). */
|
||||
#ifdef XCE_TESTING
|
||||
repl_broadcast_send_hook = lc_drop_send_hook;
|
||||
#endif
|
||||
|
||||
/* delaymgr initialised but deliberately NOT started: promotion's heartbeat
|
||||
* arm is skipped (ha_start_primary_heartbeat guards on delaymgr.running),
|
||||
* so any task that appears in tasks.head was armed by promotion itself. */
|
||||
|
|
@ -662,6 +689,9 @@ static uint64_t lifecycle_cluster_setup(const char *suffix, int n_peers,
|
|||
|
||||
static void lifecycle_cluster_teardown(void)
|
||||
{
|
||||
#ifdef XCE_TESTING
|
||||
repl_broadcast_send_hook = NULL;
|
||||
#endif
|
||||
commit_engine_fini(&g_lc.commit);
|
||||
delaymgr_fini(&g_lc.delaymgr);
|
||||
persist_stop(&g_lc.persist);
|
||||
|
|
@ -841,10 +871,16 @@ static void test_promotion_appends_noop_and_arms_own_term_gate(void)
|
|||
* N=3 (current_lsn-1). Entries 1..3 are appended into the engine so a
|
||||
* waiter on entry M=1 has a target below the gate. */
|
||||
const uint64_t noop_lsn = 3;
|
||||
/* persist_wal_async post-increments current_lsn (persist.c:318), and
|
||||
* production derives noop_lsn = current_lsn - 1. The fixture primes
|
||||
* current_lsn = appended_lsn + 1, so passing appended_lsn = noop_lsn - 1
|
||||
* lands the no-op at exactly lsn = noop_lsn. */
|
||||
(void)lifecycle_cluster_setup("gate", /*n_peers=*/3, /*n_standbys=*/2,
|
||||
/*appended_lsn=*/noop_lsn, /*n_vcpus=*/8);
|
||||
/* Register appended entries 1..3 (RETAIN = lock-free bookkeeping). */
|
||||
for (uint64_t lsn = 1; lsn <= noop_lsn; lsn++)
|
||||
/*appended_lsn=*/noop_lsn - 1, /*n_vcpus=*/8);
|
||||
/* Register pre-existing entries strictly BELOW the gate (1..noop_lsn-1);
|
||||
* the no-op itself occupies noop_lsn. A waiter on M=1 still has a
|
||||
* target below the gate. */
|
||||
for (uint64_t lsn = 1; lsn < noop_lsn; lsn++)
|
||||
(void)commit_submit(&g_lc.commit, lsn, COMMIT_MODE_RETAIN, 0);
|
||||
|
||||
/* Act: drive the shared promotion sequence (appends WAL_NOOP + gate). */
|
||||
|
|
@ -921,9 +957,11 @@ static void test_pre_own_term_wait_has_no_third_path(void)
|
|||
{
|
||||
#ifdef XCE_TESTING
|
||||
const uint64_t noop_lsn = 3;
|
||||
/* appended_lsn = noop_lsn - 1 lands the no-op at lsn = noop_lsn (see
|
||||
* case 5 comment); entries 1..noop_lsn-1 sit strictly below the gate. */
|
||||
(void)lifecycle_cluster_setup("nothird", /*n_peers=*/3, /*n_standbys=*/2,
|
||||
/*appended_lsn=*/noop_lsn, /*n_vcpus=*/8);
|
||||
for (uint64_t lsn = 1; lsn <= noop_lsn; lsn++)
|
||||
/*appended_lsn=*/noop_lsn - 1, /*n_vcpus=*/8);
|
||||
for (uint64_t lsn = 1; lsn < noop_lsn; lsn++)
|
||||
(void)commit_submit(&g_lc.commit, lsn, COMMIT_MODE_RETAIN, 0);
|
||||
|
||||
/* Act: promotion (must arm gate = noop_lsn). */
|
||||
|
|
@ -982,10 +1020,11 @@ static void test_standalone_promotion_gate_opens_immediately(void)
|
|||
{
|
||||
#ifdef XCE_TESTING
|
||||
const uint64_t noop_lsn = 1; /* standalone: noop is the first entry */
|
||||
/* appended_lsn = 0 → current_lsn primed to 1 → the no-op lands at lsn=1
|
||||
* (= noop_lsn). No entries exist below the no-op, so there is no
|
||||
* pre-existing RETAIN submit. */
|
||||
(void)lifecycle_cluster_setup("solo", /*n_peers=*/1, /*n_standbys=*/0,
|
||||
/*appended_lsn=*/noop_lsn, /*n_vcpus=*/8);
|
||||
/* Register the appended entry the no-op occupies. */
|
||||
(void)commit_submit(&g_lc.commit, noop_lsn, COMMIT_MODE_RETAIN, 0);
|
||||
/*appended_lsn=*/0, /*n_vcpus=*/8);
|
||||
|
||||
/* Act */
|
||||
TEST_ASSERT_EQUAL_INT(0, ha_promote_to_primary(&g_lc));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue