|
cwist
Modern C web framework with libttak runtime
|
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>

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. | |
Auto-Caching Layer for repetitive requests.
Definition in file big_dumb_reply.h.
| #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.
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).
Big Dumb Reply Entry. Holds an atomically swappable cached response blob.
| 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.
Big Dumb Reply Context. Lock-free read/learn paths; the mutex only serializes janitor work (sweep/trim/disk spill) and the disk-fallback path.
| 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().
| bdr | Cache instance. |
| method | HTTP method; must be "GET". |
| path | NUL-terminated request path. |
| out_len | Receives the copy length on a hit (may be NULL). |
Definition at line 727 of file big_dumb_reply.c.
References cap, cwist_alloc(), cwist_bdr_get_pinned(), and cwist_bdr_unpin().
| 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).
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().
| 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.
| bdr | Cache 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().
| 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.
| bdr | Context. |
| method | HTTP Method (only GET supported). |
| path | Request path. |
| out_len | [out] Length of the found blob. |
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.
| bdr | Cache instance. |
| method | HTTP method; must be "GET". |
| path | NUL-terminated request path. |
| out_len | Receives the reply length on a hit (may be NULL). |
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().
| 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.
| bdr | Context. |
| method | HTTP Method (only GET supported). |
| path | Request path. |
| out_len | [out] Length of the found blob. |
| out_pin | [out] Opaque pin handle for cwist_bdr_unpin(). |
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.
| bdr | Cache instance. |
| method | HTTP method; must be "GET". |
| path | NUL-terminated request path. |
| out_len | Receives the reply length on a hit (may be NULL). |
| out_pin | Receives the pin to pass to cwist_bdr_unpin(). |
Definition at line 616 of file big_dumb_reply.c.
References cap.
Referenced by cwist_bdr_copy_get(), and cwist_bdr_get().
| 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.
| bdr | Cache instance. |
| method | HTTP method; must be "GET". |
| path | Request path bytes (not required to be NUL-terminated). |
| path_len | Length of path in bytes. |
| out_len | Receives the reply length on a hit (may be NULL). |
| out_pin | Receives the pin to pass to cwist_bdr_unpin(). |
| cursor | Reusable lookup cursor, updated on every call. |
Definition at line 642 of file big_dumb_reply.c.
References cap, and CWIST_BDR_CURSOR_PATH_MAX.
| 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).
| bdr | Context. |
| method | HTTP Method. |
| path | Request path. |
| data | Serialized response data. |
| len | Length 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.
| bdr | Cache instance (disk_db must be open). |
| req_h | Precomputed request hash (primary key). |
| data | Response bytes. |
| len | Length 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.
| bdr | Cache instance. |
| method | HTTP method; must be "GET". |
| path | NUL-terminated request path. |
| data | Observed response bytes. |
| len | Length 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.
| 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.
| bdr | Cache instance. |
| method | HTTP method; must be "GET". |
| path | NUL-terminated request path. |
| data | Response bytes to cache. |
| len | Length 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.
| 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.
| bdr | Cache instance. |
| method | HTTP method; must be "GET". |
| path | NUL-terminated request path. |
| data | Response bytes to cache. |
| len | Length of data in bytes. |
| fn | Revalidation callback invoked on hits. |
| arg | Opaque 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.
| 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.
| bdr | Context. |
| max_bytes | Maximum bytes to keep in RAM (0 keeps default). |
| max_entry_age_sec | Time-to-live for cached entries (<=0 keeps default). |
| revalidate_hits | Force 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.
| bdr | Cache instance. |
| max_bytes | New byte budget; 0 keeps the current value. |
| max_entry_age_sec | New entry TTL in seconds; 0 keeps the current value. |
| revalidate_hits | New 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().
| 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.
| pin | Pin 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().