feat(scheduler-allocation): implement the unsatisfiable-resreq cache

Adds alloc_cache.c: xce_cache_key_t, cache_key_ops (the corrected
three-way, 0-means-equal .cmp -- an inverted-boolean version was a
real bug found during design review), and cache_lookup/insert/clear
against a real kvtab_t (constructed matching xce_select.c's
sel_node_table_init() precedent). Cache values are a boxed reason-
category int, not a bare hit/miss sentinel, satisfying Req 7 AC5's
requirement that a hit reproduce the original pend-reason category.
unsatisfiable_cache lives on xce_scheduler_t per Req 7 AC1.

Task 2.2 (scheduler-allocation spec). Requirements 7.1, 7.3, 7.4, 7.5.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYdtrEWWZfKRRGED7raEYg
This commit is contained in:
Rongsong Shen 2026-09-04 17:23:59 +00:00
parent d9831b0bc8
commit 86c86352d1
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
8 changed files with 871 additions and 1 deletions

View file

@ -30,7 +30,7 @@
- Observable: a passing test suite covers select-expression filtering, availability filtering, exhaustion signaling, and the too-small-then-fits-smaller-search case
- _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6_
- _Boundary: host_iter.c_
- [ ] 2.2 (P) Implement and test the unsatisfiable-resreq cache
- [x] 2.2 (P) Implement and test the unsatisfiable-resreq cache
- Implement the cache's key type and its hash/comparison/copy/release operations, backed by the existing keyed-table infrastructure, storing a reason category (not a bare present/absent marker) as each entry's value
- Implement lookup, insert, and clear operations against the cache
- Write a unit test proving a lookup on an identical fingerprint-plus-identity is a hit that returns the same reason category given at insert time, a lookup on any differing field is a miss, and clear empties all entries
@ -106,6 +106,7 @@
## Implementation Notes
- (2.2) `xce_scheduler_t.unsatisfiable_cache` (constructed in `sched_init()`/destroyed in `sched_fini()`, matching `xce_select.c`'s `sel_node_table_init()` construction convention exactly) lives on the outer `xce_scheduler_t`, per Req 7 AC1. Task 5.2's clear call site (`core_begin_session_internal()`, `core_session.c`) only receives `xce_sched_core_t* core` — since `core` is confirmed the first field of `xce_scheduler_t`, task 5.2 should recover the outer struct via `(xce_scheduler_t*)core` (valid, defined C behavior), not by widening the function's signature.
- (2.1) `xce_alloc_plan_t` gained a `ctx` field (`xce_sched_ctx_t*`) so `host_iter_init()` can reach `ctx->sched`/`ctx->primary->select`/`ctx->alloc_req.host` — `host_iter_init()` rejects a plan with `ctx == NULL` with `-EINVAL` rather than crashing. **Tasks 3.1 and 4.1 must set `plan->ctx = ctx` on every plan their plan-iterator returns from `next()`** (not just once) before constructing a `host_iter` from it — a plan-iterator that reuses one internal buffer across calls/jobs must refresh this field each time, since a stale-but-non-NULL pointer from a torn-down `ctx` is not caught by the NULL guard.
- (1.4) When a new scheduler test needs a real function from `schedobj.c`/`core.c` (e.g. `sched_ctx_get_uncomit_host()`), white-box `#include` the real source file rather than privately reimplementing its logic in the test — established precedent: `test_picker_config_fields.c`'s `#include "../src/core.c"` + `#include "../src/schedobj.c"` pairing. A private reimplementation may pass today but silently drifts from the real function with nothing to catch it later.
- (1.1) `xce_host_iter_t.next()` returns `xce_sched_worker_t*` (`sched/types.h`, carries `resvals`/`resInUse`/`host_eval_ctx`) — never `xce_worker_t*` (`xce/types.h`, the wire/config type `make_sched_worker()` converts FROM). requirements.md/design.md briefly had this wrong; fixed in commit `d1a3e158`. Task 2.1 (`host_iter.c`'s real implementation) and any later task touching worker candidates must use `xce_sched_worker_t*` from the start.