• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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