kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

runner.h (6483B)


      1 #ifndef KIT_BUILD_RUNNER_H
      2 #define KIT_BUILD_RUNNER_H
      3 
      4 #include <kit/core.h>
      5 #include <stddef.h>
      6 #include <stdint.h>
      7 
      8 #include "build.h"
      9 #include "cfg.h"
     10 #include "coord.h"
     11 #include "resolve.h"
     12 #include "trace.h"
     13 
     14 /*
     15  * Phase 3: running a recipe (the server side of the recipe protocol). Acquires
     16  * a job slot, stages a sandbox, spawns the recipe via the exec host, services
     17  * its protocol requests over the transport — logging each as a dependency —
     18  * then on success ingests the output directory into the CAS, writes BOTH trace
     19  * kinds, prepends them to the target record, installs the output in the tree
     20  * cache, and returns the result. A nonzero exit propagates failure and writes
     21  * NO trace.
     22  *
     23  * Writing both traces on every real build is what lets a later request take
     24  * whichever path fits the change it sees.
     25  */
     26 
     27 /* One submitted-but-not-yet-awaited need: the coordinator-assigned token, the
     28  * (overlay-id, argv-id) it was dispatched under, and the in-flight future.
     29  * Becomes a recorded dep edge only when AWAITED; un-awaited entries are
     30  * cancelled when the recipe exits. */
     31 typedef struct BuildPendingNeed {
     32   uint64_t token;
     33   char dep[BUILD_TARGET_MAX];
     34   uint8_t overlay_id[BUILD_HASH_LEN];
     35   uint8_t argv_id[BUILD_HASH_LEN];
     36   BuildTargetFuture* future; /* from build_coord_dispatch */
     37   int awaited;
     38   BuildResolved result;
     39 } BuildPendingNeed;
     40 
     41 /* The dependency log accumulated while servicing one recipe: the direct base
     42  * inputs and direct target-dep edges, plus each dep's resolved deepset node, plus
     43  * the live pending-needs table (submitted, not yet awaited). Converted on success
     44  * into a shallow trace (direct inputs + dep edges) and a deep trace (a single
     45  * pointer to the root deepset node, built by build_leafset_union over these direct
     46  * leaves + dep edges + child nodes). Sections hang off caller/arena storage (no VLAs). */
     47 typedef struct BuildDepLog {
     48   BuildConfigLeaf* configs; /* direct propagated-config observations */
     49   size_t n_configs, cap_configs;
     50   BuildSourceLeaf* sources; /* direct source reads (absent recorded) */
     51   size_t n_sources, cap_sources;
     52   BuildGlobLeaf* globs; /* direct globs */
     53   size_t n_globs, cap_globs;
     54   BuildBlobLeaf* blobs; /* direct hash-pinned blobs */
     55   size_t n_blobs, cap_blobs;
     56   BuildDepEdge* deps; /* AWAITED `need` edges (recorded) */
     57   size_t n_deps, cap_deps;
     58   const BuildLeafSet** child_leafsets; /* one deepset node per awaited dep */
     59   size_t n_children, cap_children;
     60   BuildPendingNeed* pending; /* submitted, not yet awaited */
     61   size_t n_pending, cap_pending;
     62   uint64_t next_token; /* monotonic per-recipe token allocator */
     63 } BuildDepLog;
     64 
     65 /* build_run_recipe — the Phase 3 entry, the continuation of build_resolve — is
     66  * declared in resolve.h (so resolve.c can call it without including runner.h)
     67  * and IMPLEMENTED in runner.c: it acquires a job slot, stages the sandbox,
     68  * spawns the recipe (process argv = `argv`, delivered as-is), services its
     69  * protocol connection via build_runner_service, and on success ingests the
     70  * output and records both trace kinds. The two helpers below are the pieces of
     71  * that flow split out so the in-process transport and the trace writer are
     72  * independently testable.
     73  *
     74  * Recipe environment is CLEAN: the recipe receives its COMPLETE environment from
     75  * the host (KitBuildExec.spawn does not inherit the coordinator's ambient env) —
     76  * the KIT_BUILD_* vars plus the build's declared pass-through, sourced from the
     77  * effective config's `env.` namespace (KIT_BUILD_ENV_PREFIX). Those keys are
     78  * ordinary tracked config, so a recipe's environment is hermetic and cache-
     79  * visible and replays/bundles like any other config. */
     80 
     81 /* Service one recipe connection until it exits: read framed requests and
     82  * dispatch them, appending each dependency to `log`. Drives the protocol.h
     83  * codec over the transport. `chain` is this recipe's chain frame (its dispatched
     84  * needs extend it). Commands:
     85  *   config-get/source/glob/blob — synchronous; log the dep, reply.
     86  *   need (fused)           — build_resolve inline on this thread; log the edge.
     87  *   need-submit            — build_coord_dispatch(dep) (concurrent, no block),
     88  *                            stash a BuildPendingNeed, reply a token. Cycles and
     89  *                            unknown targets fail fast here.
     90  *   need-await <token>     — release this recipe's job slot, await the pending
     91  *                            need's future, reacquire; THEN log the dep edge +
     92  *                            push its child node, and reply. The job slot is held
     93  *                            only while actively running, so a chain deeper than
     94  *                            `jobs` cannot deadlock (the same release/reacquire
     95  *                            applies to the fused `need`).
     96  * On EOF, any still-pending (submitted, never-awaited) needs are cancelled
     97  * (exec->kill) and recorded as NO dependency. Separated so the in-process
     98  * transport can reuse it. */
     99 int build_runner_service(KitBuildCoordinator*, KitBuildConn*, KitSlice target,
    100                          const BuildConfig* cfg, const BuildChainFrame* chain,
    101                          BuildDepLog* log);
    102 
    103 /* Convert a completed dep-log + output into the canonical persisted state:
    104  *  - build the root deepset node (build_leafset_union over the log's direct
    105  *    leaves + recipe-id + dep edges + child nodes), which stores it as a CAS blob and yields
    106  *    its deep-set-id;
    107  *  - emit + store the SHALLOW trace (direct inputs + dep edges, by hash) and the
    108  *    DEEP trace (scalars + the root deep-set-id), and prepend both to the target
    109  *    record.
    110  * Records the target's recipe-id and argv-id, its propagated-config
    111  * observations, and each dep edge's (overlay-id, argv-id). Returns the root
    112  * deepset node via *out_leafset so the caller can hand it back in
    113  * BuildResolved. */
    114 int build_runner_record_traces(KitBuildCoordinator*, KitSlice target,
    115                                const BuildArgv* argv, const BuildDepLog*,
    116                                const uint8_t output[BUILD_HASH_LEN],
    117                                const BuildLeafSet** out_leafset);
    118 int build_runner_record_test_traces(KitBuildCoordinator*, KitSlice target,
    119                                     const BuildArgv* argv,
    120                                     const BuildDepLog*,
    121                                     const uint8_t result[BUILD_HASH_LEN],
    122                                     const BuildLeafSet** out_leafset);
    123 
    124 #endif