feat(scheduler-core): define job picker plugin contract (task 1.1)

Add xce_job_picker_iface_t to plugin.h with all 13 hooks across
lifecycle/state-change/session/post-allocation/optional categories,
matching design.md's literal struct. Documents per-category thread
assignment, next_job() cancel-safety, and begin_session() session-reset
requirements. Forward-declares xce_sched_core_t (built in a later task).

Requirements: 1.2, 1.5, 2.6
This commit is contained in:
Rongsong Shen 2026-08-03 04:49:55 +00:00
parent 4153b35b22
commit 065025a3a6
4 changed files with 701 additions and 1 deletions

View file

@ -79,10 +79,118 @@ extern int plugin_end_session(void*);
extern int plugin_commit_decision(void*, xce_decision_t*);
extern int plugin_prepare_allocation(void*, xce_sched_ctx_t*);
extern int plugin_job_election(void*, xce_sched_job_t*);
extern int plugin_job_rusage_update(void*, xce_sched_job_t*, xce_job_rusages_t*);
extern int plugin_job_rusage_update(void*, xce_sched_job_t*,
xce_job_rusages_t*);
extern int register_fcfs(void*);
extern int register_limit(void*);
extern int register_seqjob_allocator(void*);
extern int register_parjob_allocator(void*);
/* ---------------------------------------------------------------------
* Job picker plugin interface (xce_job_picker_iface_t)
*
* scheduler-core spec, Req 1 AC 2 / AC 5, Req 2 AC 6.
*
* Supersedes plugin_job_election_hook_t / plugin_job_election_fn_t
* (job_elect_fn above) as the job-selection contract: the core scheduling
* loop calls picker->next_job(picker) to get the next schedulable job (or
* NULL) and carries zero knowledge of project/queue/job iteration or
* ordering — all of that lives behind this interface (Req 1 AC 1).
* job_elect_fn-only plugins keep working during the transition via a
* compatibility wrapper (registered in plugin.c, scheduler-core task 1.2);
* new pickers implement xce_job_picker_iface_t directly.
* --------------------------------------------------------------------- */
/* xce_sched_core_t is defined in core.h, added by the scheduler-core spec's
* Phase 2 core/driver extraction. Forward-declared here (same idiom as
* cluster_t in myconf.h/persist.h/ha.h) to avoid a circular include —
* init() below only ever holds/passes a pointer to it. */
typedef struct xce_sched_core_s xce_sched_core_t;
/*
* Hook categories and the thread each category runs in (Req 1 AC 3):
*
* Lifecycle hooks (MUST) — driver thread, at plugin register/teardown:
* init One-time setup; receives a core reference for state queries.
* Called exactly once, before any other hook.
* fini Teardown; frees all picker-owned resources.
*
* State-change hooks (MUST) — driver thread; called synchronously, only
* from inside core_push_events(), which itself is only invoked between
* sessions (picker thread blocked on cbuf_get(&wbuf), allocator thread
* blocked on cbuf_get(&jbuf)). No mid-session event injection:
* on_queue_update Add/update a queue in the picker's internal
* ordering. <- QUEUE_UPDATE event
* on_job_push Add a newly pending job to the candidate set.
* <- JOBS_PUSH event
* on_job_state_change Drop the job from candidates if it left pending;
* re-add if it returned to pending.
* <- JOB_STATE_CHANGE event
* on_job_update Reorder the job in candidates if its priority or
* queue changed. <- JOB_UPDATE event
*
* Session hooks (MUST) — picker thread, at scheduling-round boundaries:
* begin_session Reset the iteration cursor. Called at the start of
* every scheduling round. Session-aware requirement: a
* picker MUST reset all iteration state here — never
* carry it over from the previous session.
* next_job Return the next schedulable job per the picker's
* ordering, or NULL once exhausted. Cancel-safe
* requirement: next_job() runs in the dedicated picker
* thread, which is torn down via pthread_cancel — the
* iteration loop inside next_job() (and any blocking
* point it reaches, e.g. cbuf_get(&wbuf) between
* sessions) MUST have defined pthread_cancel
* cancellation points (pthread_testcancel() or an
* existing cancellation-point call).
* end_session End-of-round notification; called before the core
* sleeps between rounds.
*
* Post-allocation hooks (MUST) — allocator thread, after each allocation
* attempt for a job next_job() returned:
* on_dispatch Job was allocated; remove it from candidates
* permanently.
* on_pend Job was pended (or preempted back to pend); keep it for
* the next round, may deprioritize.
*
* Optional hooks (MAY be NULL) — same thread as the triggering event
* above (on_config: driver thread inside core_push_events(); on_job_rusage:
* driver thread inside core_push_events()):
* on_config Rebuild picker strategy from config. NULL if the
* picker is config-agnostic.
* on_job_rusage Track per-job resource usage. NULL if the picker is
* not resource-aware.
*
* Contract (Req 1 AC 5, Req 2 AC 6):
* - Cancel-safe: next_job() has defined pthread_cancel cancellation
* points.
* - Session-aware: begin_session() resets all iteration state.
* - Hook implementations never block indefinitely — the picker thread
* holds no lock the allocator thread needs.
* - next_job() never returns the same job twice within one session.
*
* Preconditions / postconditions:
* - init() is called exactly once before any other hook.
* - begin_session() precedes every next_job() sequence.
* - next_job() returns NULL exactly when no ready job remains for the
* current session.
*/
typedef struct {
int (*init)(void* picker, xce_sched_core_t* core);
void (*fini)(void* picker);
int (*begin_session)(void* picker);
xce_sched_job_t* (*next_job)(void* picker);
int (*end_session)(void* picker);
int (*on_dispatch)(void* picker, uint64_t jobid);
int (*on_pend)(void* picker, uint64_t jobid);
int (*on_queue_update)(void* picker, xce_sched_queue_t* queue);
int (*on_job_push)(void* picker, xce_sched_job_t* job);
int (*on_job_state_change)(void* picker, xce_sched_job_t* job,
uint32_t state);
int (*on_job_update)(void* picker, xce_sched_job_t* job);
int (*on_config)(void* picker, xce_conf4sched_t* config); /* MAY be NULL */
int (*on_job_rusage)(void* picker, xce_sched_job_t* job,
xce_job_rusages_t* rusages); /* MAY be NULL */
} xce_job_picker_iface_t;
#endif