1/* @ajax/mesh-blobs-store: a member's blob store (blobs.rs `Store`): job items' payloads, off the job
2 * log, content-addressed by their sha256 and referenced per job. A job's blob is the file
3 * `<dir>/<job>/<sha256 hex>` (@ajax/mesh-blobs-durable writes it), so it is either whole under its
4 * name or absent. A read checks the bytes against the name: a corrupt file is removed and reads as
5 * absent.
6 *
7 * One blob, several jobs: two jobs that render the same scene compute byte-identical payloads. Each
8 * job holds its own reference (a hard link of the file another job's reference names, so the bytes
9 * are on disk once). Forgetting or evicting one job removes only its references; a blob goes when no
10 * job references it.
11 *
12 * Bounded: at most `cap` bytes (each blob counted once). Room is made only by evicting forgotten jobs'
13 * references; a store full of listed jobs' blobs refuses. Without a directory the blobs are kept in
14 * memory, under the same cap. */
15#ifndef MESH_BLOBS_STORE_H
16#define MESH_BLOBS_STORE_H
1718#include "mesh/jobs/id.h"
1920#include <stdbool.h>
21#include <stddef.h>
22#include <stdint.h>
2324/* A job's standing for eviction (from the committed job table). */
25typedef enum {
26 MB_LISTED, /* in the committed table (active or finished), or not known here yet: kept */
27 MB_FORGOTTEN, /* forgotten (`job forget`): its references may go */
28} mb_live;
2930typedef mb_live (*mb_live_fn)(void *ctx, mj_job_id job);
3132typedef struct {
33 mj_job_id job;
34 mj_hash h;
35} mb_ref;
3637typedef struct {
38 mb_ref *v;
39 size_t n;
40} mb_refs;
4142void mb_refs_free(mb_refs *r);
4344/* How a reserved reference is made durable: write the bytes (link false), or hard-link `path`
45 * (another job's whole file of the same bytes; "" in a store without a directory) under the new name. */
46typedef struct {
47 bool link;
48 char *path;
49 mb_refs evicted; /* the references evicted for room */
50} mb_reserved;
5152void mb_reserved_free(mb_reserved *r);
5354typedef struct mb_store mb_store;
5556/* Opens (creates) the store: every whole blob under dir indexed (a blob named in several job
57 * directories is one blob with several references), leftover .tmps removed. dir NULL: in memory.
58 * log (may be NULL) gets the store's error lines. */
59mb_store *mb_open(const char *dir, uint64_t cap, char **err);
60void mb_store_free(mb_store *s);
61void mb_set_log(mb_store *s, void (*log)(void *ctx, const char *line), void *ctx);
62uint64_t mb_cap(const mb_store *s);
6364bool mb_persisted(const mb_store *s);
65uint64_t mb_bytes(const mb_store *s); /* each blob once */
66size_t mb_count(const mb_store *s); /* blobs */
67uint64_t mb_refs_total(const mb_store *s); /* references (a blob of two jobs counts twice) */
68/* Whole and named under some job (its bytes can be read). */
69bool mb_has(const mb_store *s, const mj_hash *h);
70/* Job's reference is whole and named: this member's copy for that job. */
71bool mb_has_ref(const mb_store *s, mj_job_id job, const mj_hash *h);
72/* Job's reference is present or being made. */
73bool mb_known_ref(const mb_store *s, mj_job_id job, const mj_hash *h);
74/* Every reference present (job, hash). */
75mb_refs mb_all(const mb_store *s);
76/* A job's directory (NULL without one; the caller frees it). */
77char *mb_dir_of(const mb_store *s, mj_job_id job);
7879/* A reference for job to blob h of len bytes: pending until mb_written. A blob another job references
80 * already costs no room (a link when its file is whole); a new one may evict forgotten jobs'
81 * references. False with *err when the store is full of listed jobs' blobs. The reference must not
82 * exist yet. */
83bool mb_reserve(mb_store *s, mj_job_id job, mj_hash h, uint32_t len, mb_live_fn live, void *live_ctx, mb_reserved *out, char **err);
84/* A reserved reference was made (ok) or failed. A reference dropped meanwhile (its job forgotten
85 * while the writer ran): the file it left goes. */
86void mb_written(mb_store *s, mj_job_id job, const mj_hash *h, bool ok);
87/* Without a directory: the reserved reference's bytes kept in memory (present at once). */
88void mb_put_mem(mb_store *s, mj_job_id job, mj_hash h, const void *bytes, size_t n);
89/* A present blob's bytes (any job's reference), checked against its name; a file that doesn't match
90 * is removed, and every reference that named it reads as absent (mb_take_lost). NULL if none. */
91uint8_t *mb_get(mb_store *s, const mj_hash *h, size_t *n);
92/* References dropped by mb_get since the last call. */
93mb_refs mb_take_lost(mb_store *s);
94/* Every reference of a job removed (its directory with them): their hashes. */
95mb_refs mb_drop_job(mb_store *s, mj_job_id job);
96/* Jobs with references here, in id order. */
97size_t mb_jobs(const mb_store *s, mj_job_id **out);
9899#endif