feat(raft-apply-decoupling): commit engine resolve primitive + majority-ack wiring (task 1.2)
commit_resolve() delivers a registered continuation's outcome exactly once (idempotent re-resolve), dispatched off-thread via vtask_enq_classified(VTASK_LIVE_BLOCK) so it never runs inline on the replication-ACK or iomgr path. Wired into all 6 commit.c-internal paths that can advance committed_lsn/writable_lsn. Review caught a real task-graph gap, not a defect: converting COMMIT_MODE_WAIT away from a blocking wait also removes the only mechanism that ever detected a commit timing out (the caller's own cond_timedwait deadline). Nothing yet arms an equivalent timeout for async-registered continuations, and nothing wires demotion/log-truncation detection to commit_resolve(FAILED, ...) -- left as-is, a pending async command during quorum loss would hang forever instead of failing, which is worse than today. Split into new tasks 1.3 (timeout arming) and 1.4 (demotion/truncation wiring), renumbered the old concurrency test to 1.5, and made 3.2 depend on both since its failure/timeout observable is meaningless without them. design.md's File Structure Plan updated to reflect that ha.c/persist.c need a narrow touch for 1.4's detection hooks.
This commit is contained in:
parent
10d157f8c5
commit
fd7a0746eb
5 changed files with 558 additions and 19 deletions
|
|
@ -127,6 +127,28 @@ int commit_submit(commit_engine_t* ce, uint64_t lsn, commit_mode_t mode,
|
|||
int commit_submit_async(commit_engine_t* ce, uint64_t lsn,
|
||||
commit_continuation_fn fn, void* ctx);
|
||||
|
||||
/* raft-apply-decoupling task 1.2: resolve lsn's registered continuation (if
|
||||
* any) with the given outcome/rc, exactly once. Called internally on the
|
||||
* majority-commit path (commit_advance_locked and its callers, via the
|
||||
* wait_done_locked predicate -- mirrors COMMIT_MODE_WAIT's own completion
|
||||
* check) and is also the PUBLIC failure-path hook: a future caller detecting
|
||||
* timeout, demotion, or log-tail truncation for a pending lsn calls this
|
||||
* directly with COMMIT_OUTCOME_FAILED and the appropriate rc (the existing
|
||||
* error-code vocabulary -- e.g. -ETIMEDOUT, -XCE_ERR_STANDBY). Idempotent: a
|
||||
* second resolve() for an lsn with no registered (or already-resolved)
|
||||
* continuation is a silent no-op -- lsn == 0 is the free-slot sentinel, so a
|
||||
* cleared slot never matches again. Never invokes the continuation inline on
|
||||
* the calling thread: dispatch happens off-thread via vtask_enq_classified
|
||||
* (VTASK_LIVE_BLOCK -- never admission-gated, so delivery cannot fast-reject
|
||||
* the way VTASK_REQ_BLOCK could at the pool's blocking cap), falling back to
|
||||
* an inline call ONLY if dispatch is unavailable (OOM, or no vtaskmgr pool
|
||||
* wired -- commit-only unit fixtures), because a continuation must never be
|
||||
* silently left unresolved (Req 9.4; "controllers never self-terminate" —
|
||||
* fail loud and complete the work rather than drop it). Safe to call from any
|
||||
* thread that does NOT already hold ce->lock. */
|
||||
void commit_resolve(commit_engine_t* ce, uint64_t lsn, commit_outcome_t outcome,
|
||||
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