feat: export gc_clear_marks + gc_mark_select_tree; remove clear from gc_sweep (phase 6)

- Add gc_clear_marks(): iterates intern table and zeroes all gc_mark bits
- Rename static gc_mark_tree → public gc_mark_select_tree (no attribute((unused)))
- Remove Phase 6 guard (live_jobs != NULL early return) from gc_sweep_select_nodes
- Remove the mark-clear loop from gc_sweep_select_nodes; add (void) casts for now-unused params
- Declare gc_clear_marks and gc_mark_select_tree in resreq.h with protocol comment
- Add TDD test test_gc_clear_marks_exported verifying the exported primitives
- Prefix all existing gc_sweep_select_nodes(NULL, 0) call sites in test_select.c with gc_clear_marks()
This commit is contained in:
Rongsong Shen 2026-04-30 03:40:24 +00:00
parent bb4a95ce37
commit 9a19a8f932
3 changed files with 1372 additions and 55 deletions

View file

@ -64,6 +64,25 @@ struct xce_select_node_ {
typedef struct select_eval_ctx_ select_eval_ctx_t;
typedef struct host_eval_ctx_ host_eval_ctx_t;
/* Host snapshot: per-resource numeric (incl. bool as 0.0/1.0) and string values */
struct host_eval_ctx_ {
int num_res;
const double* numvals; /* indexed by res_idx */
const char** strvals; /* indexed by res_idx */
};
/* Per-evaluation-session memoization context */
struct select_eval_ctx_ {
const host_eval_ctx_t* host;
uint8_t* bool_bits; /* 2 bits per node_id: NONE/TRUE/FALSE/ERROR */
uint32_t bool_bits_cap; /* capacity in nodes (each uses 2 bits) */
uint32_t node_count; /* snapshot of sel_node_next_id at init */
double* num_vals; /* numeric/bool leaf cache, indexed by node_id */
uint32_t num_vals_cap;
const char** str_vals; /* string leaf cache, indexed by node_id */
uint32_t str_vals_cap;
};
/* Scheduler job forward declaration for GC API */
typedef struct xce_sched_job_ xce_sched_job_t;
@ -92,8 +111,7 @@ extern int eval_select_simple(const xce_select_node_t* root,
const host_eval_ctx_t* host);
/* Eval context lifecycle */
extern void select_eval_ctx_init(select_eval_ctx_t* ctx,
const host_eval_ctx_t* host);
extern select_eval_ctx_t* select_eval_ctx_init(uint32_t max_node_id);
extern void select_eval_ctx_reset(select_eval_ctx_t* ctx,
const host_eval_ctx_t* host);
extern void select_eval_ctx_fini(select_eval_ctx_t* ctx);
@ -103,6 +121,12 @@ extern void gc_sweep_select_nodes(const xce_sched_job_t** live_jobs,
size_t njobs);
extern void recompact_node_ids(void);
/* GC mark primitives — called by scheduler to implement the mark phase.
* Protocol: gc_clear_marks() → gc_mark_select_tree(root) per live node
* → gc_sweep_select_nodes(NULL, 0) */
extern void gc_clear_marks(void);
extern void gc_mark_select_tree(xce_select_node_t* node);
/* Flatten AND/OR right-associative chains to left-associative form.
* Returns the new root (may differ from the input root).
* Sets *changed to 1 if any re-association took place, leaves it unchanged
@ -251,6 +275,8 @@ extern res_type_t valtype_to_res_type(int v);
* Returns 1 if a == b, 0 otherwise. Named for future wildcard extension. */
static inline int xce_str_match(const char* a, const char* b)
{
/* NULL means the resource has no value — treat as no-match */
if (a == NULL || b == NULL) return 0;
return strcmp(a, b) == 0;
}