cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
big_dumb_reply.h File Reference

Auto-Caching Layer for repetitive requests. More...

#include <cwist/core/sstring/sstring.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdatomic.h>
#include <time.h>
#include <pthread.h>
Include dependency graph for big_dumb_reply.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  bdr_blob_t
 Refcount-free cached response blob, reclaimed via libttak EBR. More...
 
struct  bdr_entry_t
 Big Dumb Reply Entry. Holds an atomically swappable cached response blob. More...
 
struct  cwist_bdr_cursor
 
struct  cwist_bdr_t
 Big Dumb Reply Context. Lock-free read/learn paths; the mutex only serializes janitor work (sweep/trim/disk spill) and the disk-fallback path. More...
 

Macros

#define CWIST_BDR_CURSOR_PATH_MAX   128
 Per-connection cursor that turns repeated hits of the same route into a content-compare instead of a SipHash + bucket walk.
 

Typedefs

typedef struct bdr_blob_t bdr_blob_t
 Refcount-free cached response blob, reclaimed via libttak EBR.
 
typedef bool(* cwist_bdr_revalidate_fn) (void *arg, void **out_data, size_t *out_len, void(**out_free) (void *))
 Revalidation callback attached to a cache entry.
 
typedef struct bdr_entry_t bdr_entry_t
 Big Dumb Reply Entry. Holds an atomically swappable cached response blob.
 
typedef struct cwist_bdr_cursor cwist_bdr_cursor_t
 
typedef struct cwist_bdr_t cwist_bdr_t
 Big Dumb Reply Context. Lock-free read/learn paths; the mutex only serializes janitor work (sweep/trim/disk spill) and the disk-fallback path.
 

Functions

cwist_bdr_t * cwist_bdr_create (void)
 Creates a BDR context.
 
void cwist_bdr_destroy (cwist_bdr_t *bdr)
 Destroys a BDR context and frees all cached blobs.
 
const void * cwist_bdr_get (cwist_bdr_t *bdr, const char *method, const char *path, size_t *out_len)
 Try to find a cached response.
 
const void * cwist_bdr_get_pinned (cwist_bdr_t *bdr, const char *method, const char *path, size_t *out_len, bdr_blob_t **out_pin)
 Find a cached response and pin it for the duration of the serve.
 
const void * cwist_bdr_get_pinned_cursor (cwist_bdr_t *bdr, const char *method, const char *path, size_t path_len, size_t *out_len, bdr_blob_t **out_pin, cwist_bdr_cursor_t *cursor)
 cwist_bdr_get_pinned() with a per-connection fast path.
 
void cwist_bdr_unpin (bdr_blob_t *pin)
 Release a pin acquired by cwist_bdr_get_pinned().
 
void * cwist_bdr_copy_get (cwist_bdr_t *bdr, const char *method, const char *path, size_t *out_len)
 Copy a stable response from the cache for concurrent server use.
 
void cwist_bdr_put (cwist_bdr_t *bdr, const char *method, const char *path, const void *data, size_t len)
 Store a response in the cache (lock-free learn path).
 
void cwist_bdr_put_fixed (cwist_bdr_t *bdr, const char *method, const char *path, const void *data, size_t len)
 Immediately cache a fixed static response on request 1.
 
void cwist_bdr_put_revalidatable (cwist_bdr_t *bdr, const char *method, const char *path, const void *data, size_t len, cwist_bdr_revalidate_fn fn, void *arg)
 Cache a response whose backing value may change over time.
 
void cwist_bdr_set_limits (cwist_bdr_t *bdr, size_t max_bytes, time_t max_entry_age_sec, uint64_t revalidate_hits)
 Adjusts guard-rail policies for the in-memory cache.
 

Detailed Description

Auto-Caching Layer for repetitive requests.

Definition in file big_dumb_reply.h.

Macro Definition Documentation

◆ CWIST_BDR_CURSOR_PATH_MAX

#define CWIST_BDR_CURSOR_PATH_MAX   128

Per-connection cursor that turns repeated hits of the same route into a content-compare instead of a SipHash + bucket walk.

Keep-alive clients overwhelmingly repeat the same few routes; the cursor remembers the last served entry and its path, so the next lookup on the same connection only memcmps the path (usually a handful of bytes) and re-validates the entry state under the EBR epoch exactly like a full lookup. It holds no ownership: entries are tombstoned rather than freed, and every use re-checks retirement/stability, so a stale cursor degrades to a normal miss, never to a wrong serve.

Embed by value (zero-initialized) in per-connection state.

Definition at line 83 of file big_dumb_reply.h.

Typedef Documentation

◆ bdr_blob_t

Refcount-free cached response blob, reclaimed via libttak EBR.

Readers hold the blob between cwist_bdr_get_pinned() and cwist_bdr_unpin(); writers replace it with a single atomic exchange and retire the predecessor across an epoch boundary, so a swapped-out blob is never freed while a reader still serves it. mem is the backing allocation released with free_fn (cwist_free for internally learned blobs, a user-supplied releaser for callback-provided buffers).

◆ bdr_entry_t

Big Dumb Reply Entry. Holds an atomically swappable cached response blob.

◆ cwist_bdr_cursor_t

◆ cwist_bdr_revalidate_fn

typedef bool(* cwist_bdr_revalidate_fn) (void *arg, void **out_data, size_t *out_len, void(**out_free)(void *))

Revalidation callback attached to a cache entry.

Invoked on cache hits for entries registered through cwist_bdr_put_revalidatable(). Return false to keep serving the cached blob. Return true when the underlying value changed: *out_data must then point to the freshly serialized response (ownership moves to the cache — zero copy, only the pointer is swung), *out_len to its length, and *out_free to the releaser for that buffer (NULL means cwist_free).

Definition at line 43 of file big_dumb_reply.h.

◆ cwist_bdr_t

Big Dumb Reply Context. Lock-free read/learn paths; the mutex only serializes janitor work (sweep/trim/disk spill) and the disk-fallback path.

Function Documentation

◆ cwist_bdr_copy_get()

void * cwist_bdr_copy_get ( cwist_bdr_t *  bdr,
const char *  method,
const char *  path,
size_t *  out_len 
)

Copy a stable response from the cache for concurrent server use.

The caller owns the returned buffer and must release it with cwist_free().

Copy a stable response from the cache for concurrent server use.

Unlike cwist_bdr_get(), the returned buffer is allocated with cwist_alloc() and survives cache eviction; the caller frees it with cwist_free().

Parameters
bdrCache instance.
methodHTTP method; must be "GET".
pathNUL-terminated request path.
out_lenReceives the copy length on a hit (may be NULL).
Returns
Newly allocated copy of the reply, or NULL on miss/invalid input/allocation failure.

Definition at line 727 of file big_dumb_reply.c.

References cap, cwist_alloc(), cwist_bdr_get_pinned(), and cwist_bdr_unpin().

◆ cwist_bdr_create()

cwist_bdr_t * cwist_bdr_create ( void  )

Creates a BDR context.

Creates a BDR context.

Initializes the mutex, the bucket table, and the default tuning values (32 MiB byte budget, 300 s entry TTL, 100000 revalidate hits).

Returns
New cache instance on success, NULL on allocation or mutex failure.

Definition at line 475 of file big_dumb_reply.c.

References BDR_BUCKETS, BDR_DEFAULT_ENTRY_TTL, BDR_DEFAULT_MAX_BYTES, BDR_DEFAULT_REVALIDATE_HITS, cap, cwist_alloc(), cwist_alloc_array(), and cwist_free().

Referenced by cwist_app_create().

◆ cwist_bdr_destroy()

void cwist_bdr_destroy ( cwist_bdr_t *  bdr)

Destroys a BDR context and frees all cached blobs.

Destroys a BDR context and frees all cached blobs.

Frees every live and retired entry and its blob, the bucket table, and the disk fallback database (including the "cwist_bdr_fallback.db" file). Safe to call with NULL.

Parameters
bdrCache instance to destroy, or NULL.

Definition at line 511 of file big_dumb_reply.c.

References cap, cwist_free(), and bdr_entry_t::retire_next.

Referenced by cwist_app_destroy().

◆ cwist_bdr_get()

const void * cwist_bdr_get ( cwist_bdr_t *  bdr,
const char *  method,
const char *  path,
size_t *  out_len 
)

Try to find a cached response.

Parameters
bdrContext.
methodHTTP Method (only GET supported).
pathRequest path.
out_len[out] Length of the found blob.
Returns
Pointer to the blob if found, NULL otherwise.
Note
Legacy convenience wrapper: the returned pointer is not protected against concurrent replacement. New code that serves the blob should use cwist_bdr_get_pinned()/cwist_bdr_unpin().

Try to find a cached response.

Convenience wrapper over cwist_bdr_get_pinned() that unpins immediately, so the returned pointer is only valid until the next janitor activity that could retire the entry; prefer the pinned API for anything but a memcpy.

Parameters
bdrCache instance.
methodHTTP method; must be "GET".
pathNUL-terminated request path.
out_lenReceives the reply length on a hit (may be NULL).
Returns
Reply bytes (unpinned), or NULL on miss/invalid input.

Definition at line 708 of file big_dumb_reply.c.

References cap, cwist_bdr_get_pinned(), and cwist_bdr_unpin().

Referenced by cwist_app_http_handler().

◆ cwist_bdr_get_pinned()

const void * cwist_bdr_get_pinned ( cwist_bdr_t *  bdr,
const char *  method,
const char *  path,
size_t *  out_len,
bdr_blob_t **  out_pin 
)

Find a cached response and pin it for the duration of the serve.

The pin is an EBR epoch: the blob stays valid until cwist_bdr_unpin(), even if a concurrent learn or revalidation swaps it out. Runs the entry's revalidation hook first when one is registered.

Parameters
bdrContext.
methodHTTP Method (only GET supported).
pathRequest path.
out_len[out] Length of the found blob.
out_pin[out] Opaque pin handle for cwist_bdr_unpin().
Returns
Pointer to the blob bytes if found, NULL otherwise.

Find a cached response and pin it for the duration of the serve.

Only GET requests are served, and only while the cache is in RAM mode. The caller must release the pin with cwist_bdr_unpin() once done reading.

Parameters
bdrCache instance.
methodHTTP method; must be "GET".
pathNUL-terminated request path.
out_lenReceives the reply length on a hit (may be NULL).
out_pinReceives the pin to pass to cwist_bdr_unpin().
Returns
Reply bytes pinned for the caller, or NULL on miss/invalid input.

Definition at line 616 of file big_dumb_reply.c.

References cap.

Referenced by cwist_bdr_copy_get(), and cwist_bdr_get().

◆ cwist_bdr_get_pinned_cursor()

const void * cwist_bdr_get_pinned_cursor ( cwist_bdr_t *  bdr,
const char *  method,
const char *  path,
size_t  path_len,
size_t *  out_len,
bdr_blob_t **  out_pin,
cwist_bdr_cursor_t *  cursor 
)

cwist_bdr_get_pinned() with a per-connection fast path.

Identical semantics to cwist_bdr_get_pinned() (same epoch pin, same revalidation hook, same stability checks), but when cursor remembers the same path the SipHash and bucket walk are skipped: the cached entry pointer is re-validated under the epoch instead. Falls back to the full lookup on any mismatch and refreshes the cursor on success. path_len must be the exact path length in bytes (no strlen is performed).

cwist_bdr_get_pinned() with a per-connection fast path.

When the cursor's cached entry still matches the request it is used as a lookup hint; a stale hint degrades to a full bucket walk. On a hit the cursor is refreshed to point at the served entry, so repeated reads of the same path skip the chain walk.

Parameters
bdrCache instance.
methodHTTP method; must be "GET".
pathRequest path bytes (not required to be NUL-terminated).
path_lenLength of path in bytes.
out_lenReceives the reply length on a hit (may be NULL).
out_pinReceives the pin to pass to cwist_bdr_unpin().
cursorReusable lookup cursor, updated on every call.
Returns
Reply bytes pinned for the caller, or NULL on miss/invalid input.

Definition at line 642 of file big_dumb_reply.c.

References cap, and CWIST_BDR_CURSOR_PATH_MAX.

◆ cwist_bdr_put()

void cwist_bdr_put ( cwist_bdr_t *  bdr,
const char *  method,
const char *  path,
const void *  data,
size_t  len 
)

Store a response in the cache (lock-free learn path).

Parameters
bdrContext.
methodHTTP Method.
pathRequest path.
dataSerialized response data.
lenLength of data.

Store a response in the cache (lock-free learn path).

Must be called only while the cache is in disk mode; takes the context mutex for the duration of the statement.

Parameters
bdrCache instance (disk_db must be open).
req_hPrecomputed request hash (primary key).
dataResponse bytes.
lenLength of data in bytes.

Learn a reply observation into the cache (lock-free fast path).

Only GET replies are tracked. An entry stabilizes once the same response bytes are seen twice in a row; a content change under a stable entry demotes it back to candidate. In disk mode the observation is written to SQLite instead. Triggers the janitor tick periodically.

Parameters
bdrCache instance.
methodHTTP method; must be "GET".
pathNUL-terminated request path.
dataObserved response bytes.
lenLength of data in bytes.

Definition at line 784 of file big_dumb_reply.c.

References cap, bdr_entry_t::created_at, bdr_entry_t::hits, bdr_entry_t::is_stable, and bdr_entry_t::response_hash.

◆ cwist_bdr_put_fixed()

void cwist_bdr_put_fixed ( cwist_bdr_t *  bdr,
const char *  method,
const char *  path,
const void *  data,
size_t  len 
)

Immediately cache a fixed static response on request 1.

Immediately cache a fixed static response on request 1.

For responses that are known to be constant; stores the bytes and marks the entry stable in one shot. In disk mode the observation is written to SQLite instead. Triggers the janitor tick periodically.

Parameters
bdrCache instance.
methodHTTP method; must be "GET".
pathNUL-terminated request path.
dataResponse bytes to cache.
lenLength of data in bytes.

Definition at line 848 of file big_dumb_reply.c.

References cap, bdr_entry_t::created_at, bdr_entry_t::hits, bdr_entry_t::is_stable, and bdr_entry_t::response_hash.

◆ cwist_bdr_put_revalidatable()

void cwist_bdr_put_revalidatable ( cwist_bdr_t *  bdr,
const char *  method,
const char *  path,
const void *  data,
size_t  len,
cwist_bdr_revalidate_fn  fn,
void *  arg 
)

Cache a response whose backing value may change over time.

Behaves like cwist_bdr_put_fixed() (stable from the first request) but attaches fn to the entry. Every cache hit invokes fn first; when it reports a change, the new buffer it supplies is published with a single pointer exchange — no memcpy, no global lock — and the old blob is retired across an epoch boundary.

Cache a response whose backing value may change over time.

On every subsequent hit the hook is invoked and, if it reports fresh bytes, the entry's blob is swapped to the callback-provided buffer through one pointer exchange. The hook is published before the blob so a reader never observes a revalidatable blob without its hook. In disk mode the observation is written to SQLite instead (hook not persisted). Triggers the janitor tick periodically.

Parameters
bdrCache instance.
methodHTTP method; must be "GET".
pathNUL-terminated request path.
dataResponse bytes to cache.
lenLength of data in bytes.
fnRevalidation callback invoked on hits.
argOpaque argument passed to fn.

Definition at line 894 of file big_dumb_reply.c.

References cap, bdr_entry_t::created_at, bdr_entry_t::hits, bdr_entry_t::is_stable, bdr_entry_t::response_hash, bdr_entry_t::revalidate, and bdr_entry_t::revalidate_arg.

◆ cwist_bdr_set_limits()

void cwist_bdr_set_limits ( cwist_bdr_t *  bdr,
size_t  max_bytes,
time_t  max_entry_age_sec,
uint64_t  revalidate_hits 
)

Adjusts guard-rail policies for the in-memory cache.

Parameters
bdrContext.
max_bytesMaximum bytes to keep in RAM (0 keeps default).
max_entry_age_secTime-to-live for cached entries (<=0 keeps default).
revalidate_hitsForce relearning after this many hits (0 keeps default).

Adjusts guard-rail policies for the in-memory cache.

Takes the context mutex so the new limits are not torn against a running janitor tick.

Parameters
bdrCache instance.
max_bytesNew byte budget; 0 keeps the current value.
max_entry_age_secNew entry TTL in seconds; 0 keeps the current value.
revalidate_hitsNew stability hit threshold; 0 keeps the current value.

Definition at line 940 of file big_dumb_reply.c.

References cap.

Referenced by cwist_app_configure_bdr().

◆ cwist_bdr_unpin()

void cwist_bdr_unpin ( bdr_blob_t *  pin)

Release a pin acquired by cwist_bdr_get_pinned().

Release a pin acquired by cwist_bdr_get_pinned().

The pin is the EBR epoch itself, so this simply leaves the epoch.

Parameters
pinPin to release (ignored beyond symmetry with the get calls).

Definition at line 690 of file big_dumb_reply.c.

References cap.

Referenced by cwist_bdr_copy_get(), and cwist_bdr_get().