skip to content
==> include/mesh/jobs/select.h <==
1/* @ajax/mesh-jobs-select: who gets a job's leases (jobs.rs `select`, `Pick`, `SchedCx`).
2 *
3 * A member is eligible if it is alive, in the job's members, runs one of the job's programs, and the
4 * fleet scheduler (F4: `sched::filter`, `score_terms`) passes and scores it. The scheduler is an
5 * interface here (`mj_sched`): @ajax/mesh-jobs-sched implements it over the fleet's scheduler model;
6 * without one (a single meshd) a member that runs the program and is alive is eligible, unscored.
7 * HTCondor's backoff: a member the owner policy holds busy gets no leases while an idle member runs
8 * the program. Picks come best score first, ties to the lower id, rejected members last. */
9#ifndef MESH_JOBS_SELECT_H
10#define MESH_JOBS_SELECT_H
11
12#include "mesh/jobs/frame.h"
13#include "mesh/jobs/spec.h"
14
15#include <stdbool.h>
16#include <stddef.h>
17#include <stdint.h>
18
19#define MJ_MEMBERS 32 /* member ids are bits of a u32 */
20
21/* A score and its explanation (sched::Score::explain). */
22typedef struct {
23    double total;
24    char *explain;
25} mj_score;
26
27/* The explanation of an unscored verdict (sched::Score::default().explain()). */
28#define MJ_SCORE_DEFAULT_EXPLAIN "0.000 = perf 0.00 load 0.00 mem 0.00 spread 0.00 (, cpu after 0.00)"
29
30/* One member's standing for a job's next lease. */
31typedef struct {
32    uint32_t member;
33    bool ok;        /* eligible (score) or rejected (why) */
34    mj_score score;
35    char *why;
36    bool busy;      /* eligible but held busy by the owner policy (only floor-sized leases) */
37} mj_pick;
38
39typedef struct {
40    mj_pick *v;
41    size_t n;
42} mj_picks;
43
44void mj_picks_free(mj_picks *p);
45mj_picks mj_picks_clone(const mj_picks *p);
46/* `pick system 0 eligible <explain>[ busy: ...]` or `pick system 3 rejected: <why>`. */
47char *mj_pick_line(const mj_pick *p);
48/* The pick of member m that is eligible, or NULL. */
49const mj_pick *mj_picks_ok(const mj_picks *p, uint32_t m);
50
51/* The job programs each member runs (from its F_JOB_AVAIL). */
52typedef struct {
53    bool has[MJ_MEMBERS];
54    mj_prog *v[MJ_MEMBERS];
55    size_t n[MJ_MEMBERS];
56} mj_member_progs;
57
58void mj_member_progs_free(mj_member_progs *p);
59void mj_member_progs_set(mj_member_progs *p, uint32_t k, mj_prog *progs, size_t n); /* takes progs */
60void mj_member_progs_remove(mj_member_progs *p, uint32_t k);
61
62/* The fleet scheduler, as select asks it. judge(k, prog) is asked for an alive member k that runs
63 * prog, when k < nmembers: 1 eligible (*score filled; *busy: the owner policy holds it), 0 rejected
64 * (*why), -1 no model for it (no needs for prog: eligible, unscored). busy_why(k): why the owner
65 * policy holds k busy (NULL if it doesn't); release frees ctx. */
66typedef struct mj_sched {
67    void *ctx;
68    uint32_t nmembers;
69    int (*judge)(void *ctx, uint32_t k, const char *prog, mj_score *score, bool *busy, char **why);
70    char *(*busy_why)(void *ctx, uint32_t k);
71    void (*release)(void *ctx);
72} mj_sched;
73
74/* Every member's verdict for job's next lease, best first. cx may be NULL (a single meshd). */
75mj_picks mj_select(const mj_spec *job, uint32_t alive, const mj_member_progs *progs, const mj_sched *cx);
76
77#endif