forked from lei.chen/myxce
feat(raft-apply-decoupling): resolve pending continuations on demotion/truncation (task 1.4)
commit_resolve_pending_above(ce, lsn_floor, rc) fails every registered continuation for lsn > lsn_floor, reusing commit_resolve()'s existing exactly-once/idempotent guarantee (no parallel bookkeeping path). Truncation: a new on_truncate/truncate_cb_ctx callback on persist_t (same inversion-of-control shape as the existing on_durable_advance hook) fires from persist_truncate_wal_above after releasing p->lock, only when entries were actually removed. This one wrapper covers all three real truncation call sites: raft_cb_become_leader's post-election truncate, the library's on_truncate_from conflict-reconcile, and ha_demotion_convergence_fn's post-demotion truncate. Demotion: raft_cb_become_follower calls commit_resolve_pending_above(&c->commit, 0, -XCE_ERR_STANDBY) -- lsn_floor=0 fails everything, since a demoted node can never authoritatively confirm anything still pending (CP posture). Without this, a demoted or truncated node would leave any pending async command permanently unresolved -- the requester would simply never get a reply, worse than today's bounded-timeout behavior. Also closes bug-1407 (pre-existing test_config_repl flake, unrelated to this feature) -- confirmed fixed as a side effect of prior tasks in this series, 70/70 passing across 3 independent runs.
This commit is contained in:
parent
530a02bda3
commit
9b4b805a27
9 changed files with 748 additions and 301 deletions
|
|
@ -179,6 +179,32 @@ int commit_submit_async(commit_engine_t* ce, uint64_t lsn,
|
|||
void commit_resolve(commit_engine_t* ce, uint64_t lsn, commit_outcome_t outcome,
|
||||
int rc);
|
||||
|
||||
/* raft-apply-decoupling task 1.4: resolve every currently pending registered
|
||||
* continuation whose lsn > lsn_floor as FAILED with rc, in one bounded pass --
|
||||
* the FAILED-outcome sibling of commit_resolve's internal majority-ack scan.
|
||||
* Two intended callers:
|
||||
* - log-tail truncation: lsn_floor = the new tail (cutoff_lsn) AFTER a
|
||||
* truncation actually removed entries above it. Those entries no longer
|
||||
* exist in the log and can never commit. A continuation registered AT OR
|
||||
* BELOW the new tail is UNAFFECTED and stays pending -- its entry is
|
||||
* still in the log and may still reach majority.
|
||||
* - demotion (loss of leadership): lsn_floor = 0. A demoted node can never
|
||||
* advance committed_lsn again for anything it had pending, so every
|
||||
* currently registered continuation fails, regardless of its lsn. lsn ==
|
||||
* 0 is never a real registration (the free-slot sentinel -- see
|
||||
* commit_continuation_t), so lsn_floor = 0 correctly means "all".
|
||||
* Snapshot-then-resolve, mirroring commit_resolve_pending's own pattern:
|
||||
* takes a bounded snapshot of matching lsns under ce->lock, then resolves
|
||||
* each from an unlocked context via the self-locking commit_resolve()
|
||||
* (dispatch-after-unlock ordering rule, design §Commit Engine Resolve).
|
||||
* Idempotent: a continuation already resolved by a concurrent caller (e.g.
|
||||
* the timeout-sweep thread winning a race) is a silent no-op via
|
||||
* commit_resolve's own exactly-once guarantee -- no continuation is ever
|
||||
* double-resolved. Safe to call from any thread that does NOT already hold
|
||||
* ce->lock. */
|
||||
void commit_resolve_pending_above(commit_engine_t* ce, uint64_t lsn_floor,
|
||||
int rc);
|
||||
|
||||
/* iomgr path: record standby ACK, evaluate majority, advance committed_lsn
|
||||
* contiguously, wake satisfied waiters. Never blocks. */
|
||||
void commit_on_ack(commit_engine_t* ce, int standby_idx, uint64_t acked_lsn);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue