Skip to content

Latest commit

 

History

History
64 lines (49 loc) · 3.07 KB

File metadata and controls

64 lines (49 loc) · 3.07 KB

Bounded asset caches

shutter::Cache stores reusable binary data in a ShutterDB file and manages its size. Use it for previews, compiled assets and other data the application can regenerate.

#include <shutter/cache.hpp>

shutter::Cache cache("assets.shdb", {.max_bytes = 1024ULL * 1024 * 1024});
cache.put("asset:42", "generated bytes");
auto bytes = cache.get_string("asset:42");
cache.sync();

Link ShutterDB::ShutterDB. The preview example uses content hashes to reuse generated images across process restarts.

Budget and eviction

max_bytes defaults to 1 GiB and includes the main file's header, keys, values and obsolete records. After a successful write, removal or open, the main file is at or below that budget. The minimum budget is 32 bytes, enough for an empty file.

When an entry needs room, the cache removes the least recently used entries. Successful reads and writes update recency. After restarting, recency starts from the surviving records' write order; reads do not add bookkeeping records to the log.

When the append log exceeds the budget, the cache compacts it. Cleanup aims to leave one eighth of the usable budget free, so the next few writes do not each trigger a full rewrite. The value being inserted is protected from that cleanup. An entry too large for the whole budget returns false before changing or evicting anything.

Appending and compaction need space beyond the budget. Compaction retains the old file while writing the replacement. Its rollback backup shares the old file's bytes on filesystems with hard-link support; other filesystems need an additional full copy. Failed maintenance can leave sidecars or a file over budget; reopening recovers the file and reapplies the budget.

Opening an existing ShutterDB file as a cache can evict its records to meet the chosen budget. Use DB for records that must remain until the application explicitly deletes them.

API

Operation Result
put(key, bytes) or put(key, text) true when stored; false when too large for this cache
get(key) Owned byte vector, or an empty optional for a miss
get_string(key) Owned string, or an empty optional for a miss
remove(key) Whether the entry existed
stats() Storage statistics, budget, hits, misses and evictions
sync() Synchronize buffered writes
compact() Reclaim obsolete records immediately

Counters cover the current handle's lifetime. stats().storage contains the ordinary database statistics. Keys and values retain the DB limits. Calls on one cache handle are serialized, and that handle exclusively owns its file.

Cache writes are buffered by default. Call sync() at application checkpoints or set CacheOptions::storage.sync_writes = true for individually synchronized writes. Closing a handle does not synchronize buffered writes. Eviction and insertion are separate operations; a failed insertion can leave earlier evictions in place.

The CLI can inspect, verify and compact cache files. DB can open them when the cache handle is closed.