feat(raft-drive-async): LivenessAdmission pool reservation + commit fold (tasks 1.6/1.7)

vtaskmgr gains vtask_class_t (LIVENESS/LIVE_BLOCK/REQ_BLOCK) + a pool-level
blocking reservation: REQ_BLOCK fast-rejects -XCE_ERR_NOT_READY past
n_vcpus-R; LIVENESS never gated (deadlock-freedom). commit_submit folds its
inflight_waits onto the pool via commit_set_pool; production wired in
cluster.c phase2 (vtaskmgr_set_liveness_reserved(R) + commit_set_pool).
Lock order p->lock->ce->lock->blk_lock. Dormant until 3.1. Commit suites
38/30/22/38 green; lib 282/0, controller 196/0, ASAN clean. Phase 1 done.
This commit is contained in:
Rongsong Shen 2026-06-26 07:43:19 +00:00
parent 0781c6c027
commit a36234a103
12 changed files with 721 additions and 22 deletions

View file

@ -3,6 +3,7 @@
#define _VTASKMGR_H_ 1
#include <pthread.h>
#include <stdatomic.h>
#include <stddef.h>
#include "dataq.h"
@ -15,6 +16,23 @@ typedef int (*vtask_func_t)(void*);
#define VTASK_IO 0x01
#define VTASK_GENERIC 0x02
/* raft-drive-async task 1.6: LivenessAdmission task classes.
*
* VTASK_LIVENESS never parks — WAL-ack/heartbeat/vote receipt+send.
* NEVER admission-gated, so >= VTASK_LIVENESS_RESERVED
* workers are always free for it (deadlock-freedom).
* VTASK_LIVE_BLOCK bounded mandatory park — vote-grant term fsync (R4.6).
* Runs in the reserved headroom; not gated by the
* REQ_BLOCK cap (it is short and bounded).
* VTASK_REQ_BLOCK may park seconds — commit-wait / config-ack wait.
* Admission-gated: rejected with -E_XCE_NOT_READY when
* admitting it would breach the reservation. */
typedef enum {
VTASK_LIVENESS = 0,
VTASK_LIVE_BLOCK,
VTASK_REQ_BLOCK
} vtask_class_t;
typedef struct {
int vtype;
union {
@ -29,6 +47,7 @@ typedef struct {
vtask_data_t* data;
int vcpu;
vtask_func_t entry;
vtask_class_t cls; /* LivenessAdmission class (task 1.6); default LIVENESS */
} vtask_t;
#define ITPTR_TO_VTASK(p) ((vtask_t*)(((char*)p) - offsetof(vtask_t, link)))
@ -55,6 +74,14 @@ typedef struct {
cbuf_t wbuf;
cbuf_t wtbuf; /* used to wake up vtaskmgr to check tasks */
dataq_t taskq;
/* LivenessAdmission (raft-drive-async task 1.6): pool-level reservation.
* liveness_reserved == 0 disables the gate (legacy: nothing gated).
* blocking_inflight counts in-flight *blocking-admission* holders
* (VTASK_REQ_BLOCK tasks + commit_submit waits folded onto this seam);
* capped at max(1, n_vcpus - liveness_reserved). */
int liveness_reserved;
int blocking_inflight;
pthread_mutex_t blk_lock; /* guards blocking_inflight check-and-increment */
} vtaskmgr_t;
extern vtask_t* vtask_alloc();
@ -64,6 +91,34 @@ extern void vtask_fini(vtask_t*);
extern int vtask_enq(vtaskmgr_t*, vtask_t*);
extern int vtask_handle_msg(vtaskmgr_t*, vtask_func_t, void* arg);
/* LivenessAdmission (raft-drive-async task 1.6) — pool-level reservation.
*
* vtaskmgr_set_liveness_reserved: set R, the count of vcpus reserved for
* never-gated VTASK_LIVENESS work. The controller resolves R via
* drive_async_liveness_reserved() (the single source of truth) and wires it
* here at init. R == 0 disables the gate (legacy behavior). */
extern void vtaskmgr_set_liveness_reserved(vtaskmgr_t*, int reserved);
/* Effective blocking-admission cap = max(1, n_vcpus - liveness_reserved)
* (the cap is floored at 1 so a commit can always run); returns n_vcpus when
* the gate is disabled (reserved == 0). */
extern int vtaskmgr_blocking_cap(const vtaskmgr_t*);
/* Acquire/release a blocking-admission slot. acquire returns 0 when admitted
* or -E_XCE_NOT_READY when admitting would breach the reservation (fast
* reject — never blocks). When the gate is disabled (reserved == 0) acquire
* always succeeds and is uncounted. This is the seam commit.c folds onto:
* commit_submit acquires before its blocking wait and releases on wake. */
extern int vtaskmgr_blocking_acquire(vtaskmgr_t*);
extern void vtaskmgr_blocking_release(vtaskmgr_t*);
/* Classified submit. VTASK_REQ_BLOCK is admission-gated: returns
* -E_XCE_NOT_READY (task NOT enqueued — caller still owns it) when admitting
* would breach the reservation. VTASK_LIVENESS / VTASK_LIVE_BLOCK are never
* gated (always enqueued). On success the task is enqueued and owned by the
* pool. */
extern int vtask_enq_classified(vtaskmgr_t*, vtask_t*, vtask_class_t);
extern int vtaskmgr_init(vtaskmgr_t*, int);
extern int vtaskmgr_start(vtaskmgr_t*);
extern void vtaskmgr_fini(vtaskmgr_t*);