1# lws_cache: Flexible single and multilevel caching 2 3lws_cache implements a single- or multi-level cache for generic payload items 4that are **keyed by a unique string**. 5 6![lws_cache overview](../doc-assets/lws_cache-1.png) 7 8L1 cache is always stored on heap, but it may be hooked up to additional levels 9of cache objects with different backing storage. The last level always contains 10a complete set of cached items, earlier levels may be empty or contain a partial 11set of objects. 12 13User code can define its own subclassed lws_cache objects with custom storage 14formats and media, while being able to take advantage of a suitably-sized L1 15heap cache to minimize the cost of repeated access. 16 17![lws_cache overview](../doc-assets/lws_cache-2.png) 18 19You can find examples of how to create, use and destroy single and multilevel 20caches in `minimal-examples/api-tests/api-test-lws_cache` 21 22## Cache size restriction, LRU and TTL 23 24The max heap footprint of its items and max number of items can be capped. LRU 25tracking is performed so the least recently relevant items are evicted first. 26It's also possible to limit the maximum size of any single payload. 27 28Time To Live (TTL) tracking is also performed automatically, so cached items 29auto-expire if a non-zero TTL is provided when the object is created. A user 30callback can be defined to get called when an item is about to be removed from 31a particular cache level, in case any housekeeping needed. 32 33## Atomicity 34 35Items in L1 can be accessed in heap casually and reliably if the following is 36borne in mind: 37 38 - Any return to the event loop may perform removal of cache items due to TTL 39expiry 40 41 - Any operation that writes new items may evict items from non-last 42cache levels which have limits to the footprint or item count to make room for 43it, using LRU ordering. 44 45In short process cache results before returning to the event loop or writing 46or removing items in the cache. 47 48## Cache creation 49 50Caches are created using an info struct `struct lws_cache_creation_info` 51that should be zeroed down. Most members are optional and can be left at zero, 52a pointer to the lws_context and a short cache name are mandatory. 53 54``` 55struct lws_cache_ttl_lru * 56lws_cache_create(const struct lws_cache_creation_info *info); 57``` 58 59How caches work is defined by an "ops struct" that the cache is bound to at 60creation time. `lws_cache_ops_heap` ops struct is provided by lws, you can 61define your own to implement your own specialized cache level. See 62`./include/libwebsockets/lws-cache-ttl.h` for the definition. 63 64## Cache destruction 65 66Created cache levels should be destroyed when you are finished with them. 67 68``` 69void 70lws_cache_destroy(struct lws_cache_ttl_lru **cache); 71``` 72 73For L1, in heap, this frees any allocations. For other levels, eg, with file 74storage for the items, this would close the file and leave any entries as they 75are. 76 77## Writethrough 78 79``` 80int 81lws_cache_write_through(struct lws_cache_ttl_lru *cache, 82 const char *specific_key, const uint8_t *source, 83 size_t size, lws_usec_t expiry, void **ppay); 84``` 85 86The combined caches are always accessed via the L1 cache, writing new items is 87done at L1 and writes through to each cache layer immediately, so new items go 88into the backing store without delay, but are available from heap for read. 89 90If existing keys are rewritten, the previous item of the same key is deleted 91from all levels of the cache before writing the new one. 92 93## Removal 94 95Removal also is performed at all cache levels at once. 96 97``` 98int 99lws_cache_item_remove(struct lws_cache_ttl_lru *cache, const char *wildcard_key); 100``` 101 102internally earlier cache levels can evict cached items just at their level, but 103this is triggered automatically and not by api. 104 105A wildcard key is supported, removing all items matching, eg "myitem*". 106 107## Get by key 108 109``` 110int 111lws_cache_item_get(struct lws_cache_ttl_lru *cache, const char *specific_key, 112 const void **pdata, size_t *psize); 113``` 114 115Apis are provided to get the blob related to a specific key, if it exists at 116any cache layer. Again this should use L1, it will bring a copy of the item 117into L1 if one is not already there, so it can be accessed from heap. 118 119## Lookup with wildcards 120 121``` 122int 123lws_cache_lookup(struct lws_cache_ttl_lru *cache, const char *wildcard_key, 124 const void **pdata, size_t *psize); 125``` 126 127lws_cache also supports **lookup** queries that contain wildcards or otherwise match 128on multiple keys according to cache-specific rules. These queries do not return 129a single item, instead they return lists of keys that match, in a blob of its 130own that is also cached in L1. 131 132The user can walk the lookup results blob using a provided helper api 133 134``` 135int 136lws_cache_results_walk(lws_cache_results_t *walk_ctx); 137``` 138 139After recovering each result key this way, the user code can use the _get api 140to access the blob for each indiviudally. 141 142The lookup results themselves are cached in L1, any new key that matches the 143wildcard lookup in any cached results, or any deletion of items with keys 144matching the cached wildcard lookup invalidate the affected cached lookup 145results so they will be regenerated next time. 146 147In the typical case after a lookup, at least for a while the lookup results blob 148and all items mentioned in the lookup results will already be in L1 and cheaply 149accessible. 150 151## Expunging 152 153An api is also provided to "expunge" or completely empty all cache levels and 154corresponding backing stores. 155 156``` 157int 158lws_cache_expunge(struct lws_cache_ttl_lru *cache); 159``` 160 161