1/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25/** \defgroup lws_cache_ttl Cache supporting expiry
26 * ##Cache supporting expiry
27 *
28 * These apis let you quickly and reliably implement caches of named objects,
29 * that have a "destroy-by date" and cache limits that will be observed.
30 *
31 * You can instantiate as many caches as you need. The first one must be an
32 * L1 / heap cache type, it can have parents and grandparents of other types
33 * which are accessible why writing / looking up and getting from the L1 cache.
34 * The outer "cache" layer may persistently store items to a backing store.
35 *
36 * Allocated object memory is entirely for the use of user code, up to the
37 * requested size.
38 *
39 * The key name for the listed objects may be any string chosen by the user,
40 * there is no special length limit as it is also allocated.
41 *
42 * Both expiry and LRU orderings are kept so it is easy to find out usage
43 * ordering and when the next object that will expire.
44 *
45 * Cached objects may be destroyed any time you go around the event loop, when
46 * you allocate new objects (to keep the whole cache under the specified limit),
47 * or when their expiry time arrives. So you shouldn't keep copies of pointers
48 * to cached objects after returning to the event loop.
49 */
50///@{
51
52
53struct lws_cache_ttl_lru;
54
55/**
56 * lws_cache_write_through() - add a new cache item object in all layers
57 *
58 * \param cache: the existing cache to allocate the object in
59 * \param specific_key: a key string that identifies the item in the cache
60 * \param source: optional payload for the cached item, NULL means caller will
61 * write the payload
62 * \param size: the size of the object to allocate
63 * \param expiry: the usec time that the object will autodestroy
64 * \param ppay: NULL, or a pointer to a void * to be set to the L1 payload
65 *
66 * If an item with the key already exists, it is destroyed before allocating a
67 * new one.
68 *
69 * Returns 0 if successful. The written entry will be scheduled to be auto-
70 * destroyed when \p expiry occurs.
71 *
72 * Adding or removing cache items may cause invalidation of cached queries.
73 */
74LWS_VISIBLE LWS_EXTERN int /* only valid until return to event loop */
75lws_cache_write_through(struct lws_cache_ttl_lru *cache,
76 const char *specific_key, const uint8_t *source,
77 size_t size, lws_usec_t expiry, void **ppay);
78
79typedef struct lws_cache_match {
80 lws_dll2_t list;
81 lws_usec_t expiry;
82 /* earliest expiry amongst results */
83 size_t payload_size;
84 /**< the payload is not attached here. This is a hint about what
85 * (*get)() will return for this tag name.
86 */
87 size_t tag_size;
88
89 /* tag name + NUL is overcommitted */
90} lws_cache_match_t;
91
92/**
93 * lws_cache_heap_lookup() - get a list of matching items
94 *
95 * \param cache: the cache to search for the key
96 * \param wildcard_key: the item key string, may contain wildcards
97 * \param pdata: pointer to pointer to be set to the serialized result list
98 * \param psize: pointer to size_t to receive length of serialized result list
99 *
100 * This finds all unique items in the final cache that match search_key, which
101 * may contain wildcards. It does not return the payloads for matching items,
102 * just a list of specific tags in the that match.
103 *
104 * If successful, results are provided in a serialized list format, in no
105 * particular order, each result has the following fields
106 *
107 * - BE32: payload size in bytes (payload itself is not included)
108 * - BE32: specific tag name length in bytes
109 * - chars: tag name with terminating NUL
110 *
111 * These serialized results are themselves cached in L1 cache (only) and the
112 * result pointers are set pointing into that. If the results are still in L1
113 * cache next time this api is called, the results will be returned directly
114 * from that without repeating the expensive lookup on the backup store. That
115 * is why the results are provided in serialized form.
116 *
117 * The cached results list expiry is set to the earliest expiry of any listed
118 * item. Additionally any cached results are invalidated on addition or
119 * deletion (update is done as addition + deletion) of any item that would
120 * match the results' original wildcard_key. For the typical case new items
121 * are rare compared to lookups, this is efficient.
122 *
123 * Lookup matching does not itself affect LRU or cache status of the result
124 * itsems. Typically user code will get the lookup results, and then perform
125 * get operations on each item in its desired order, that will bring the items
126 * to the head of the LRU list and occupy L1 cache.
127 *
128 * Returns 0 if proceeded alright, or nonzero if error. If there was an error,
129 * any partial results set has been deallocated cleanly before returning.
130 */
131LWS_VISIBLE LWS_EXTERN int
132lws_cache_lookup(struct lws_cache_ttl_lru *cache, const char *wildcard_key,
133 const void **pdata, size_t *psize);
134
135/**
136 * lws_cache_item_get() - bring a specific item into L1 and get payload info
137 *
138 * \param cache: the cache to search for the key
139 * \param specific_key: the key string of the item to get
140 * \param pdata: pointer to a void * to be set to the payload in L1 cache
141 * \param psize: pointer to a size_t to be set to the payload size
142 *
143 * If the cache still has an item matching the key string, it will be destroyed.
144 *
145 * Adding or removing cache items may cause invalidation of cached queries.
146 *
147 * Notice the cache payload is a blob of the given size. If you are storing
148 * strings, there is no NUL termination unless you stored them with it.
149 *
150 * Returns 0 if successful.
151 */
152LWS_VISIBLE LWS_EXTERN int
153lws_cache_item_get(struct lws_cache_ttl_lru *cache, const char *specific_key,
154 const void **pdata, size_t *psize);
155
156/**
157 * lws_cache_item_remove() - remove item from all cache levels
158 *
159 * \param cache: the cache to search for the key
160 * \param wildcard_key: the item key string
161 *
162 * Removes any copy of any item matching the \p wildcard_key from any cache
163 * level in one step.
164 *
165 * Adding or removing cache items may cause invalidation of cached queries
166 * that could refer to the removed item.
167 */
168LWS_VISIBLE LWS_EXTERN int
169lws_cache_item_remove(struct lws_cache_ttl_lru *cache, const char *wildcard_key);
170
171/**
172 * lws_cache_footprint() - query the amount of storage used by the cache layer
173 *
174 * \param cache: cache to query
175 *
176 * Returns number of payload bytes stored in cache currently
177 */
178LWS_VISIBLE LWS_EXTERN uint64_t
179lws_cache_footprint(struct lws_cache_ttl_lru *cache);
180
181/**
182 * lws_cache_debug_dump() - if built in debug mode dump cache contents to log
183 *
184 * \param cache: cache to dump
185 *
186 * If lws was built in debug mode, dump cache to log, otherwise a NOP.
187 */
188LWS_VISIBLE LWS_EXTERN void
189lws_cache_debug_dump(struct lws_cache_ttl_lru *cache);
190
191typedef struct lws_cache_results {
192 const uint8_t *ptr; /* set before using walk api */
193 size_t size; /* set before using walk api */
194
195 size_t payload_len;
196 size_t tag_len;
197 const uint8_t *tag;
198} lws_cache_results_t;
199
200/**
201 * lws_cache_results_walk() - parse next result
202 *
203 * \param walk_ctx: the context of the results blob to walk
204 *
205 * Caller must initialize \p walk_ctx.ptr and \p walk_ctx.size before calling.
206 * These are set to the results returned from a _lookup api call.
207 *
208 * The call returns 0 if the struct elements have been set to a result, or 1
209 * if there where no more results in the blob to walk.
210 *
211 * If successful, after the call \p payload_len is set to the length of the
212 * payload related to this result key (the payload itself is not present),
213 * \p tag_len is set to the length of the result key name, and \p tag is set
214 * to the result tag name, with a terminating NUL.
215 */
216LWS_VISIBLE LWS_EXTERN int
217lws_cache_results_walk(lws_cache_results_t *walk_ctx);
218
219typedef void (*lws_cache_item_destroy_cb)(void *item, size_t size);
220struct lws_cache_creation_info {
221 struct lws_context *cx;
222 /**< Mandatory: the lws_context */
223 const char *name;
224 /**< Mandatory: short cache name */
225 lws_cache_item_destroy_cb cb;
226 /**< NULL, or a callback that can hook cache item destory */
227 struct lws_cache_ttl_lru *parent;
228 /**< NULL, or next cache level */
229 const struct lws_cache_ops *ops;
230 /**< NULL for default, heap-based ops, else custom cache storage and
231 * query implementation */
232
233 union {
234 struct {
235 const char *filepath;
236 /**< the filepath to store items in */
237 } nscookiejar;
238 } u;
239 /**< these are extra configuration for specific cache types */
240
241 size_t max_footprint;
242 /**< 0, or the max heap allocation allowed before destroying
243 * lru items to keep it under the limit */
244 size_t max_items;
245 /**< 0, or the max number of items allowed in the cache before
246 * destroying lru items to keep it under the limit */
247 size_t max_payload;
248 /**< 0, or the max allowed payload size for one item */
249 int tsi;
250 /**< 0 unless using SMP, then tsi to bind sul to */
251};
252
253struct lws_cache_ops {
254 struct lws_cache_ttl_lru *
255 (*create)(const struct lws_cache_creation_info *info);
256 /**< create an instance of the cache type specified in info */
257
258 void
259 (*destroy)(struct lws_cache_ttl_lru **_cache);
260 /**< destroy the logical cache instance pointed to by *_cache, doesn't
261 * affect any NV backing storage */
262
263 int
264 (*expunge)(struct lws_cache_ttl_lru *cache);
265 /**< completely delete any backing storage related to the cache
266 * instance, eg, delete the backing file */
267
268 int
269 (*write)(struct lws_cache_ttl_lru *cache, const char *specific_key,
270 const uint8_t *source, size_t size, lws_usec_t expiry,
271 void **ppvoid);
272 /**< create an entry in the cache level according to the given info */
273 int
274 (*tag_match)(struct lws_cache_ttl_lru *cache, const char *wc,
275 const char *tag, char lookup_rules);
276 /**< Just tell us if tag would match wildcard, using whatever special
277 * rules the backing store might use for tag matching. 0 indicates
278 * it is a match on wildcard, nonzero means does not match.
279 */
280 int
281 (*lookup)(struct lws_cache_ttl_lru *cache, const char *wildcard_key,
282 lws_dll2_owner_t *results_owner);
283 /**+ add keys for search_key matches not already listed in the results
284 * owner */
285 int
286 (*invalidate)(struct lws_cache_ttl_lru *cache, const char *wildcard_key);
287 /**< remove matching item(s) from cache level */
288
289 int
290 (*get)(struct lws_cache_ttl_lru *cache, const char *specific_key,
291 const void **pdata, size_t *psize);
292 /**< if it has the item, fills L1 with item. updates LRU, and returns
293 * pointer to payload in L1 */
294
295 void
296 (*debug_dump)(struct lws_cache_ttl_lru *cache);
297 /**< Helper to dump the whole cache contents to log, useful for debug */
298};
299
300/**
301 * lws_cache_create() - create an empty cache you can allocate items in
302 *
303 * \param info: a struct describing the cache to create
304 *
305 * Create an empty cache you can allocate items in. The cache will be kept
306 * below the max_footprint and max_items limits if they are nonzero, by
307 * destroying least-recently-used items until it remains below the limits.
308 *
309 * Items will auto-destroy when their expiry time is reached.
310 *
311 * When items are destroyed from the cache, if \p cb is non-NULL, it will be
312 * called back with the item pointer after it has been removed from the cache,
313 * but before it is deallocated and destroyed.
314 *
315 * context and tsi are used when scheduling expiry callbacks
316 */
317LWS_VISIBLE LWS_EXTERN struct lws_cache_ttl_lru *
318lws_cache_create(const struct lws_cache_creation_info *info);
319
320/**
321 * lws_cache_destroy() - destroy a previously created cache
322 *
323 * \param cache: pointer to the cache
324 *
325 * Everything in the cache is destroyed, then the cache itself is destroyed,
326 * and *cache set to NULL.
327 */
328LWS_VISIBLE LWS_EXTERN void
329lws_cache_destroy(struct lws_cache_ttl_lru **cache);
330
331/**
332 * lws_cache_expunge() - destroy all items in cache and parents
333 *
334 * \param cache: pointer to the cache
335 *
336 * Everything in the cache and parents is destroyed, leaving it empty.
337 * If the cache has a backing store, it is deleted.
338 *
339 * Returns 0 if no problems reported at any cache layer, else nonzero.
340 */
341LWS_VISIBLE LWS_EXTERN int
342lws_cache_expunge(struct lws_cache_ttl_lru *cache);
343
344LWS_VISIBLE extern const struct lws_cache_ops lws_cache_ops_heap,
345 lws_cache_ops_nscookiejar;
346
347///@}
348
349