ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
edge_cache_sd.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file edge_cache_sd.h
6 * @brief CDN edge-cache tier - L2 SD persistence (PC_ENABLE_EDGE_CACHE && PC_ENABLE_DBM).
7 *
8 * The persistent second tier behind the bounded L1 RAM store (edge_cache): an evicted L1 entry is
9 * written back to a dbm key-value store on the WAL (services/storage/dbm, SD-card backed on device, a RAM WalDev
10 * for host tests), and an L1 miss is served by promoting the entry back from L2. Because the store is
11 * log-structured on the WAL, the cached set survives a reboot (dbm rebuilds its index by replaying the
12 * log on open).
13 *
14 * The L2 key is the entry's 32-byte SHA-256 digest (== PC_DBM_KEY_MAX), so no key is re-derived. The
15 * value is a compact, versioned, little-endian serialization of the entry's response metadata + body.
16 *
17 * These are pure functions over a caller-owned dbm handle and a caller-owned scratch buffer (no
18 * file-scope state); the proxy glue (edge_cache_proxy) owns the dbm and the buffer and installs the
19 * write-back / promote wiring.
20 *
21 * Reboot note: the monotonic insert time is meaningless across a reboot (no wall clock), so a promoted
22 * entry is always treated as stale by the caller and revalidated - which is why only entries carrying a
23 * validator (ETag / Last-Modified) are spilled: they are exactly the ones a cheap 304 can refresh.
24 *
25 * @author Douglas Quigg (dstroy0)
26 * @date 2026
27 */
28
29#ifndef PROTOCORE_EDGE_CACHE_SD_H
30#define PROTOCORE_EDGE_CACHE_SD_H
31
32#include "protocore_config.h"
33
34// The entry serialize/deserialize below is the shared byte codec for an EdgeEntry (used by both the L2 SD
35// tier and the mesh sibling link), so it compiles whenever the edge cache is on; the dbm-backed put/get/purge
36// helpers further down need the persistence tier and stay gated on PC_ENABLE_DBM.
37#if PC_ENABLE_EDGE_CACHE
38
40#include <stddef.h>
41#include <stdint.h>
42#if PC_ENABLE_DBM
43#include "services/storage/dbm/dbm.h" // dbm handle type for the L2 put/get/purge helpers below
44#endif
45
46/**
47 * @brief Worst-case serialized value size of one entry (every metadata string full + a max-size body).
48 *
49 * Size the scratch buffer with this. A serialized entry only fits in dbm when this (or the actual, often
50 * smaller, size) is <= PC_DBM_VAL_MAX - otherwise the entry stays L1-only (::edge_sd_put returns false).
51 */
52
53/**
54 * @brief Serialize @p e's response metadata + body into @p out (little-endian, versioned).
55 * @return the byte length written, or 0 if it would not fit @p cap. Freshness/age fields are intentionally
56 * not persisted (a promoted entry is force-revalidated, so they are always recomputed).
57 */
58size_t edge_sd_serialize(const EdgeEntry *e, uint8_t *out, size_t cap);
59
60/**
61 * @brief Rehydrate an entry from @p buf (as produced by ::edge_sd_serialize) into @p e.
62 *
63 * Fills only the content fields (key, digest, status, content-type, validators, encoding, Vary, body); the
64 * caller owns @p e's LRU linkage, used flag, and freshness (which it sets to force a revalidation).
65 * @return false on a short/corrupt/oversized buffer or a version mismatch (fails closed, no partial write
66 * of the body).
67 */
68bool edge_sd_deserialize(const uint8_t *buf, size_t len, EdgeEntry *e);
69
70#if PC_ENABLE_DBM
71
72/**
73 * @brief Write @p e back to the L2 store (keyed by its digest), using @p scratch to serialize.
74 * @return true if it was spilled; false if @p e carries no validator, or its serialization does not fit
75 * @p scratch / PC_DBM_VAL_MAX, or the dbm write fails (the entry simply stays L1-only).
76 */
77bool edge_sd_put(pc_dbm *db, const EdgeEntry *e, uint8_t *scratch, size_t scratch_cap);
78
79/**
80 * @brief Promote the entry stored under @p digest from L2 into @p e (via @p scratch).
81 * @return true on a hit that deserialized cleanly; false on an L2 miss or a corrupt value.
82 */
83bool edge_sd_get(pc_dbm *db, const uint8_t digest[32], EdgeEntry *e, uint8_t *scratch, size_t scratch_cap);
84
85/** @brief Drop the L2 entry stored under @p digest. @return true if one existed. */
86bool edge_sd_del(pc_dbm *db, const uint8_t digest[32]);
87
88/**
89 * @brief Drop every L2 entry whose stored request path begins with @p prefix (via @p scratch to read each
90 * value's canonical key). @return the number purged.
91 */
92uint32_t edge_sd_purge_prefix(pc_dbm *db, const char *path_prefix, uint8_t *scratch, size_t scratch_cap);
93
94/** @brief Drop every L2 entry. @return the number purged. */
95uint32_t edge_sd_purge_all(pc_dbm *db);
96
97#endif // PC_ENABLE_DBM
98
99#endif // PC_ENABLE_EDGE_CACHE
100
101#endif // PROTOCORE_EDGE_CACHE_SD_H
Log-structured hash key-value store on the WAL (PC_ENABLE_DBM, requires PC_ENABLE_WAL).
CDN edge-cache tier - pure engine (PC_ENABLE_EDGE_CACHE).
User-facing configuration for ProtoCore.