feat(scheduler-allocation): add lazy plan/host iterator contracts
Defines xce_alloc_plan_t (partition of a job's task count into per-host slot buckets), xce_alloc_plan_iter_t, and xce_host_iter_t (init/next/fini vtables, stack-allocate-then-init-in-place convention matching sched_ctx_init) as reusable abstractions any allocator can adopt. Proven usable by a trivial no-op reference implementation and a fresh-per-bucket host_iter composition test, no allocator wired in yet. Task 1.1 (scheduler-allocation spec). Requirements 2.1, 3.1. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XYdtrEWWZfKRRGED7raEYg
This commit is contained in:
parent
d1a3e158ae
commit
d5d2c1caf5
4 changed files with 482 additions and 1 deletions
140
src/scheduler/include/sched/alloc_iter.h
Normal file
140
src/scheduler/include/sched/alloc_iter.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
#if !defined(_SCHED_ALLOC_ITER_H_)
|
||||
|
||||
#define _SCHED_ALLOC_ITER_H_ 1
|
||||
|
||||
/*
|
||||
* alloc_iter.h - lazy allocation-plan and host-candidate iterator
|
||||
* contracts (scheduler-allocation spec, Req 2 AC 1-6 / Req 3 AC 1-6).
|
||||
*
|
||||
* This header defines two reusable abstractions any allocator plugin can
|
||||
* adopt:
|
||||
*
|
||||
* xce_alloc_plan_iter_t - generates candidate allocation plans (a
|
||||
* partition of a primary resreq's maxTasks into per-host slot buckets),
|
||||
* one per next() call, most-preferred first.
|
||||
*
|
||||
* xce_host_iter_t - for a given plan, generates candidate hosts (one
|
||||
* per next() call) matching the plan's select-expression + availability
|
||||
* filter.
|
||||
*
|
||||
* No allocator is wired onto these interfaces yet -- see
|
||||
* ../../testsuite/test_alloc_plan_iter.c for a trivial, no-op reference
|
||||
* implementation of each proving the contract shape compiles and is
|
||||
* usable.
|
||||
*/
|
||||
|
||||
#include <rtti.h>
|
||||
|
||||
#include "resreq.h"
|
||||
#include "scheduler.h"
|
||||
#include "xce/types.h"
|
||||
|
||||
/*
|
||||
* xce_alloc_plan_t - a candidate allocation plan: a partition of a
|
||||
* primary resreq's maxTasks into per-host slot buckets, e.g. for
|
||||
* maxTasks=3: [3], [2,1], [1,1,1] -- NOT a uniform (nhosts,
|
||||
* slots_per_host) pair, which cannot express uneven splits.
|
||||
*
|
||||
* Produced by xce_alloc_plan_iter_t.next(); the returned pointer is valid
|
||||
* only until the following next() or fini() call on that same iterator
|
||||
* (it is not independently heap-owned by the caller).
|
||||
*/
|
||||
typedef struct {
|
||||
int nbuckets; /* number of hosts this plan needs (==
|
||||
* len(bucket_slots)) */
|
||||
int* bucket_slots; /* partition of maxTasks; bucket_slots[i] = slots
|
||||
* needed on the i-th distinct host claimed for
|
||||
* this plan */
|
||||
/* host_filter: derived from primary_resreq->select, plus slot
|
||||
* availability -- consumed by xce_host_iter_t (Req 3), not exposed as
|
||||
* a separate field here. This interface does not mandate a
|
||||
* representation for it; each concrete plan-iterator implementation
|
||||
* carries whatever it needs to reconstruct the filter. */
|
||||
} xce_alloc_plan_t;
|
||||
|
||||
typedef struct xce_alloc_plan_iter_s xce_alloc_plan_iter_t;
|
||||
|
||||
/*
|
||||
* xce_alloc_plan_iter_t - lazy, cancel-safe candidate-plan generator (Req
|
||||
* 2). One instance is owned by a single allocator's job_alloc_fn for the
|
||||
* lifetime of one job's allocation attempt.
|
||||
*
|
||||
* Allocation convention: stack-allocated by the caller, then initialized
|
||||
* IN PLACE -- init() takes the iterator's own address as its first
|
||||
* argument, matching this codebase's existing sched_ctx_init(&ctx, ...)
|
||||
* convention (schedobj.c). This is NOT a heap-allocating factory
|
||||
* function:
|
||||
*
|
||||
* xce_alloc_plan_iter_t iter_storage;
|
||||
* xce_alloc_plan_iter_t* iter = &iter_storage;
|
||||
* xce_alloc_plan_t* plan;
|
||||
*
|
||||
* if (iter->init(iter, primary_resreq, sched) != 0) { ... }
|
||||
* while ((plan = iter->next(iter)) != NULL) { ... }
|
||||
* iter->fini(iter);
|
||||
*/
|
||||
struct xce_alloc_plan_iter_s {
|
||||
/* Initialize the iterator for a given primary resreq and scheduler
|
||||
* state. Returns 0 on success, nonzero on error. */
|
||||
int (*init)(xce_alloc_plan_iter_t* iter, xce_primary_resreq_t* resreq,
|
||||
xce_scheduler_t* sched);
|
||||
|
||||
/* Return the next candidate plan, or NULL when exhausted. Successive
|
||||
* calls return plans ordered most-preferred to least-preferred, per
|
||||
* the owning allocator's own preference policy; the NULL
|
||||
* end-of-iteration signal is stable across repeated calls once
|
||||
* exhausted. The returned plan pointer is valid until the next
|
||||
* next() or fini() call. Calls pthread_testcancel() (or an
|
||||
* equivalent real cancellation point) at least once per invocation. */
|
||||
xce_alloc_plan_t* (*next)(xce_alloc_plan_iter_t* iter);
|
||||
|
||||
/* Release all resources held by the iterator. The interface defines
|
||||
* no other required cleanup step. */
|
||||
void (*fini)(xce_alloc_plan_iter_t* iter);
|
||||
|
||||
/* Private state: current position, strategy-specific data. */
|
||||
void* private;
|
||||
};
|
||||
|
||||
typedef struct xce_host_iter_s xce_host_iter_t;
|
||||
|
||||
/*
|
||||
* xce_host_iter_t - lazy, cancel-safe candidate-host filter for one plan
|
||||
* bucket (Req 3). Shares the same stack-allocate-then-init-in-place
|
||||
* convention as xce_alloc_plan_iter_t above.
|
||||
*
|
||||
* Scoped PER PLAN BUCKET, not per plan: a multi-bucket plan requires a
|
||||
* fresh xce_host_iter_t instance (a new init() call) for each bucket --
|
||||
* never one instance shared across a plan's buckets. next() is a
|
||||
* forward-only cursor with no rewind; sharing one instance across buckets
|
||||
* would permanently drop a host an earlier, larger bucket tried and
|
||||
* rejected as too small, even when that same host exactly satisfies a
|
||||
* later, smaller bucket. Host exclusivity ACROSS buckets of the same plan
|
||||
* (is_claimed()) is the caller's responsibility, not this interface's --
|
||||
* this iterator only ever answers "does this select expression +
|
||||
* availability filter match," with no memory of prior buckets.
|
||||
*/
|
||||
struct xce_host_iter_s {
|
||||
/* Initialize the iterator for a given plan and worker set. Returns 0
|
||||
* on success, nonzero on error. */
|
||||
int (*init)(xce_host_iter_t* iter, xce_alloc_plan_t* plan, var workers);
|
||||
|
||||
/* Return the next candidate worker matching the plan's host filter,
|
||||
* or NULL when exhausted for this instance's bucket search --
|
||||
* exhaustion is scoped to this one instance, not to the plan as a
|
||||
* whole (see the per-bucket-freshness note above: a plan with more
|
||||
* buckets remaining requires a fresh host_iter instance). The
|
||||
* returned worker pointer is valid until the next next() or fini()
|
||||
* call. Calls pthread_testcancel() (or an equivalent real
|
||||
* cancellation point) at least once per invocation. */
|
||||
xce_sched_worker_t* (*next)(xce_host_iter_t* iter);
|
||||
|
||||
/* Release all resources held by the host iterator, independent of
|
||||
* the owning plan iterator's lifecycle. */
|
||||
void (*fini)(xce_host_iter_t* iter);
|
||||
|
||||
/* Private state: current position, filtering state. */
|
||||
void* private;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue