forked from lei.chen/myxce
Dedicated-pthread pool isolated from the vtask pool; non-blocking slowlane_submit (0 enqueued / -EEXIST deduped / -EAGAIN cap-full-deferred), admission cap on running tasks, per-key in-flight dedup, run-exactly-once, drain+join fini. Wired into controller lifecycle (dormant; consumers land in 2.x/3.x). 7 unit tests, mutation-verified cap+dedup; full suite 194/0 green, 15x ASAN.
95 lines
3.9 KiB
C
95 lines
3.9 KiB
C
#pragma once
|
|
/*
|
|
* slowlane.h — SlowLane executor: a bounded pool of dedicated worker threads
|
|
* that runs long blocking I/O OFF the Raft drive threads (iomgr epoll loop,
|
|
* delaymgr timer), with admission control and per-key in-flight dedup.
|
|
*
|
|
* Service interface is verbatim from
|
|
* .kiro/specs/raft-drive-async/design.md (Components -> SlowLane).
|
|
*
|
|
* The lane owns scheduling/isolation, NOT the work content: the submitted
|
|
* `fn` (peer connect, snapshot transfer, config-push body) stays in its own
|
|
* module and is responsible for clearing any caller-side in-flight state on
|
|
* completion. `slowlane_submit` is non-blocking: a drive-thread caller
|
|
* enqueues and returns immediately, never waiting for `fn` to run.
|
|
*
|
|
* raft-drive-async task 1.2 — Requirements 3.1, 3.2, 3.3, 3.4, 1.5.
|
|
*/
|
|
#include <pthread.h>
|
|
#include <stdint.h>
|
|
|
|
typedef void (*slowlane_fn_t)(void *arg);
|
|
|
|
/*
|
|
* One queued unit of work. Allocated by the lane on submit, freed by the
|
|
* worker after `fn` returns. Held on the FIFO pending queue until a worker
|
|
* picks it up.
|
|
*/
|
|
typedef struct slowlane_task {
|
|
uint64_t key; /* dedup key; 0 disables dedup */
|
|
slowlane_fn_t fn;
|
|
void *arg;
|
|
struct slowlane_task *next; /* intrusive FIFO link */
|
|
} slowlane_task_t;
|
|
|
|
/*
|
|
* SlowLane executor state. All fields are lane-private and guarded by `lock`;
|
|
* callers touch the lane only through the API below. Bounded by design:
|
|
* - `n_workers` dedicated pthreads, isolated from the vtask request pool;
|
|
* - at most `max_inflight` tasks RUNNING concurrently (admission cap);
|
|
* - at most one in-flight task per non-zero key (dedup).
|
|
*/
|
|
typedef struct slowlane {
|
|
pthread_mutex_t lock;
|
|
pthread_cond_t cond; /* signalled when work or a slot frees up */
|
|
|
|
slowlane_task_t *q_head; /* FIFO pending queue (admission-deferred) */
|
|
slowlane_task_t *q_tail;
|
|
|
|
uint64_t *inflight_keys; /* running OR queued non-zero keys (dedup set) */
|
|
int n_inflight_keys;
|
|
int cap_inflight_keys;
|
|
|
|
int n_workers;
|
|
int max_inflight; /* admission cap on concurrently RUNNING tasks */
|
|
int n_running; /* tasks currently executing on a worker */
|
|
|
|
pthread_t *workers;
|
|
int started; /* worker threads created */
|
|
int stopping; /* fini requested: drain + join */
|
|
} slowlane_t;
|
|
|
|
/*
|
|
* Initialise the lane and start `n_workers` dedicated worker threads.
|
|
* `max_inflight` bounds the number of tasks RUNNING concurrently (excess is
|
|
* queued, never dropped, never run on a drive thread).
|
|
* Returns 0 on success, -EINVAL on a bad argument, -errno on a thread/alloc
|
|
* failure (lane left un-started).
|
|
*/
|
|
int slowlane_init(slowlane_t *sl, int n_workers, int max_inflight);
|
|
|
|
/*
|
|
* Submit `fn(arg)` to run exactly once on a lane worker. NON-BLOCKING: the
|
|
* caller (which may be a drive thread) returns immediately.
|
|
*
|
|
* Returns (per design SlowLane Service Interface):
|
|
* 0 enqueued AND a worker slot was free (running < max_inflight) —
|
|
* the task can start immediately
|
|
* -EEXIST `key` (non-zero) already in flight — deduped no-op, NOT enqueued
|
|
* -EAGAIN admission cap full at submit time (running >= max_inflight) — the
|
|
* task IS still queued/deferred (never dropped, never run on a drive
|
|
* thread); the caller is told it was deferred, not that it failed
|
|
* -errno allocation failure / lane stopping
|
|
*
|
|
* In all of {0, -EAGAIN} the work is enqueued and will run exactly once. Only
|
|
* -EEXIST and -errno mean the task was not enqueued.
|
|
*
|
|
* `key == 0` disables dedup (every key-0 submit is independent work).
|
|
*/
|
|
int slowlane_submit(slowlane_t *sl, uint64_t key, slowlane_fn_t fn, void *arg);
|
|
|
|
/*
|
|
* Drain the pending queue, stop and join all workers. Shutdown only.
|
|
* After return the lane is dormant; re-init to reuse.
|
|
*/
|
|
void slowlane_fini(slowlane_t *sl);
|