expires module implements active TTL expiration for RadishDB. While passive expiration happens inside ht_get and ht_ttl when a specific key is accessed, the active sweeper proactively removes expired entries in the background, preventing unbounded memory growth for keys that are never read again.
How expiration works
RadishDB uses a two-layer expiration strategy:| Layer | Where | Trigger |
|---|---|---|
| Passive | ht_get, ht_ttl | On each key access — expired keys are deleted before returning NULL or -2 |
| Active | expire_sweep | Called once per REPL/server loop iteration with max_checks = 10 |
max_checks entries per call. This amortizes the cost of expiration across many loop iterations rather than blocking on a full scan.
Functions
expire_init
Resets the module-level expiry cursor to the start of the bucket array.
The hash table the sweeper will operate on. Used to bound the cursor reset.
ht_load call. If you skip it after loading a snapshot, the cursor may point past the end of the new (potentially smaller) bucket array, causing undefined behavior.
expire_sweep
Advances the cursor and deletes any expired entries it encounters.
The hash table to sweep.
Maximum number of entries to examine in this call. The engine calls this with
10 on each loop iteration.Sweep behavior
- Starts at the current cursor position and advances through buckets.
- For each entry: if
expires_at != 0 && expires_at <= time(NULL), the entry is deleted immediately (key, value, andEntrystruct are freed). - After examining
max_checksentries, the sweep stops and the cursor position is saved for the next call. - The cursor wraps around to bucket
0after reaching the end of the array.
Entries with
expires_at == 0 are never deleted by the sweeper — they have no expiry.Full usage example
Integration with ht_load and ht_save
The expiry cursor is not serialized into .rdbx snapshots. After restoring from a snapshot, the cursor is in whatever state it was left in from the previous table, which is invalid for the new table. Always pair ht_load with expire_init: