1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include <private-lib-core.h> 26d4afb5ceSopenharmony_ci#include "private-lib-misc-cache-ttl.h" 27d4afb5ceSopenharmony_ci 28d4afb5ceSopenharmony_ci#if defined(write) 29d4afb5ceSopenharmony_ci#undef write 30d4afb5ceSopenharmony_ci#endif 31d4afb5ceSopenharmony_ci 32d4afb5ceSopenharmony_cistatic void 33d4afb5ceSopenharmony_ciupdate_sul(lws_cache_ttl_lru_t_heap_t *cache); 34d4afb5ceSopenharmony_ci 35d4afb5ceSopenharmony_cistatic int 36d4afb5ceSopenharmony_cilws_cache_heap_invalidate(struct lws_cache_ttl_lru *_c, const char *key); 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_cistatic int 39d4afb5ceSopenharmony_cisort_expiry(const lws_dll2_t *a, const lws_dll2_t *b) 40d4afb5ceSopenharmony_ci{ 41d4afb5ceSopenharmony_ci const lws_cache_ttl_item_heap_t 42d4afb5ceSopenharmony_ci *c = lws_container_of(a, lws_cache_ttl_item_heap_t, list_expiry), 43d4afb5ceSopenharmony_ci *d = lws_container_of(b, lws_cache_ttl_item_heap_t, list_expiry); 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci if (c->expiry > d->expiry) 46d4afb5ceSopenharmony_ci return 1; 47d4afb5ceSopenharmony_ci if (c->expiry < d->expiry) 48d4afb5ceSopenharmony_ci return -1; 49d4afb5ceSopenharmony_ci 50d4afb5ceSopenharmony_ci return 0; 51d4afb5ceSopenharmony_ci} 52d4afb5ceSopenharmony_ci 53d4afb5ceSopenharmony_cistatic void 54d4afb5ceSopenharmony_ci_lws_cache_heap_item_destroy(lws_cache_ttl_lru_t_heap_t *cache, 55d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item) 56d4afb5ceSopenharmony_ci{ 57d4afb5ceSopenharmony_ci lwsl_cache("%s: %s (%s)\n", __func__, cache->cache.info.name, 58d4afb5ceSopenharmony_ci (const char *)&item[1] + item->size); 59d4afb5ceSopenharmony_ci 60d4afb5ceSopenharmony_ci lws_dll2_remove(&item->list_expiry); 61d4afb5ceSopenharmony_ci lws_dll2_remove(&item->list_lru); 62d4afb5ceSopenharmony_ci 63d4afb5ceSopenharmony_ci cache->cache.current_footprint -= item->size; 64d4afb5ceSopenharmony_ci 65d4afb5ceSopenharmony_ci update_sul(cache); 66d4afb5ceSopenharmony_ci 67d4afb5ceSopenharmony_ci if (cache->cache.info.cb) 68d4afb5ceSopenharmony_ci cache->cache.info.cb((void *)((uint8_t *)&item[1]), item->size); 69d4afb5ceSopenharmony_ci 70d4afb5ceSopenharmony_ci lws_free(item); 71d4afb5ceSopenharmony_ci} 72d4afb5ceSopenharmony_ci 73d4afb5ceSopenharmony_cistatic void 74d4afb5ceSopenharmony_cilws_cache_heap_item_destroy(lws_cache_ttl_lru_t_heap_t *cache, 75d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item, int parent_too) 76d4afb5ceSopenharmony_ci{ 77d4afb5ceSopenharmony_ci struct lws_cache_ttl_lru *backing = &cache->cache; 78d4afb5ceSopenharmony_ci const char *tag = ((const char *)&item[1]) + item->size; 79d4afb5ceSopenharmony_ci 80d4afb5ceSopenharmony_ci /* 81d4afb5ceSopenharmony_ci * We're destroying a normal item? 82d4afb5ceSopenharmony_ci */ 83d4afb5ceSopenharmony_ci 84d4afb5ceSopenharmony_ci if (*tag == META_ITEM_LEADING) 85d4afb5ceSopenharmony_ci /* no, nothing to check here then */ 86d4afb5ceSopenharmony_ci goto post; 87d4afb5ceSopenharmony_ci 88d4afb5ceSopenharmony_ci if (backing->info.parent) 89d4afb5ceSopenharmony_ci backing = backing->info.parent; 90d4afb5ceSopenharmony_ci 91d4afb5ceSopenharmony_ci /* 92d4afb5ceSopenharmony_ci * We need to check any cached meta-results from lookups that 93d4afb5ceSopenharmony_ci * include this normal item, and if any, invalidate the meta-results 94d4afb5ceSopenharmony_ci * since they have to be recalculated before being used again. 95d4afb5ceSopenharmony_ci */ 96d4afb5ceSopenharmony_ci 97d4afb5ceSopenharmony_ci lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 98d4afb5ceSopenharmony_ci cache->items_lru.head) { 99d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *i = lws_container_of(d, 100d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t, 101d4afb5ceSopenharmony_ci list_lru); 102d4afb5ceSopenharmony_ci const char *iname = ((const char *)&item[1]) + item->size; 103d4afb5ceSopenharmony_ci uint8_t *pay = (uint8_t *)&item[1], *end = pay + item->size; 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci if (*iname == META_ITEM_LEADING) { 106d4afb5ceSopenharmony_ci size_t taglen = strlen(iname); 107d4afb5ceSopenharmony_ci 108d4afb5ceSopenharmony_ci /* 109d4afb5ceSopenharmony_ci * If the item about to be destroyed makes an 110d4afb5ceSopenharmony_ci * appearance on the meta results list, we must kill 111d4afb5ceSopenharmony_ci * the meta result item to force recalc next time 112d4afb5ceSopenharmony_ci */ 113d4afb5ceSopenharmony_ci 114d4afb5ceSopenharmony_ci while (pay < end) { 115d4afb5ceSopenharmony_ci uint32_t tlen = lws_ser_ru32be(pay + 4); 116d4afb5ceSopenharmony_ci 117d4afb5ceSopenharmony_ci if (tlen == taglen && 118d4afb5ceSopenharmony_ci !strcmp((const char *)pay + 8, iname)) { 119d4afb5ceSopenharmony_ci#if defined(_DEBUG) 120d4afb5ceSopenharmony_ci /* 121d4afb5ceSopenharmony_ci * Sanity check that the item tag is 122d4afb5ceSopenharmony_ci * really a match for that meta results 123d4afb5ceSopenharmony_ci * item 124d4afb5ceSopenharmony_ci */ 125d4afb5ceSopenharmony_ci 126d4afb5ceSopenharmony_ci assert (!backing->info.ops->tag_match( 127d4afb5ceSopenharmony_ci backing, iname + 1, tag, 1)); 128d4afb5ceSopenharmony_ci#endif 129d4afb5ceSopenharmony_ci _lws_cache_heap_item_destroy(cache, i); 130d4afb5ceSopenharmony_ci break; 131d4afb5ceSopenharmony_ci } 132d4afb5ceSopenharmony_ci pay += 8 + tlen + 1; 133d4afb5ceSopenharmony_ci } 134d4afb5ceSopenharmony_ci 135d4afb5ceSopenharmony_ci#if defined(_DEBUG) 136d4afb5ceSopenharmony_ci /* 137d4afb5ceSopenharmony_ci * Sanity check that the item tag really isn't a match 138d4afb5ceSopenharmony_ci * for that meta results item 139d4afb5ceSopenharmony_ci */ 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ci assert (backing->info.ops->tag_match(backing, iname + 1, 142d4afb5ceSopenharmony_ci tag, 1)); 143d4afb5ceSopenharmony_ci#endif 144d4afb5ceSopenharmony_ci } 145d4afb5ceSopenharmony_ci 146d4afb5ceSopenharmony_ci } lws_end_foreach_dll_safe(d, d1); 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_cipost: 149d4afb5ceSopenharmony_ci _lws_cache_heap_item_destroy(cache, item); 150d4afb5ceSopenharmony_ci} 151d4afb5ceSopenharmony_ci 152d4afb5ceSopenharmony_cistatic void 153d4afb5ceSopenharmony_cilws_cache_item_evict_lru(lws_cache_ttl_lru_t_heap_t *cache) 154d4afb5ceSopenharmony_ci{ 155d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *ei; 156d4afb5ceSopenharmony_ci 157d4afb5ceSopenharmony_ci if (!cache->items_lru.head) 158d4afb5ceSopenharmony_ci return; 159d4afb5ceSopenharmony_ci 160d4afb5ceSopenharmony_ci ei = lws_container_of(cache->items_lru.head, 161d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t, list_lru); 162d4afb5ceSopenharmony_ci 163d4afb5ceSopenharmony_ci lws_cache_heap_item_destroy(cache, ei, 0); 164d4afb5ceSopenharmony_ci} 165d4afb5ceSopenharmony_ci 166d4afb5ceSopenharmony_ci/* 167d4afb5ceSopenharmony_ci * We need to weed out expired entries in the backing file 168d4afb5ceSopenharmony_ci */ 169d4afb5ceSopenharmony_ci 170d4afb5ceSopenharmony_cistatic void 171d4afb5ceSopenharmony_ciexpiry_cb(lws_sorted_usec_list_t *sul) 172d4afb5ceSopenharmony_ci{ 173d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t_heap_t *cache = lws_container_of(sul, 174d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t_heap_t, cache.sul); 175d4afb5ceSopenharmony_ci lws_usec_t now = lws_now_usecs(); 176d4afb5ceSopenharmony_ci 177d4afb5ceSopenharmony_ci lwsl_cache("%s: %s\n", __func__, cache->cache.info.name); 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci while (cache->items_expiry.head) { 180d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item; 181d4afb5ceSopenharmony_ci 182d4afb5ceSopenharmony_ci item = lws_container_of(cache->items_expiry.head, 183d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t, list_expiry); 184d4afb5ceSopenharmony_ci 185d4afb5ceSopenharmony_ci if (item->expiry > now) 186d4afb5ceSopenharmony_ci return; 187d4afb5ceSopenharmony_ci 188d4afb5ceSopenharmony_ci lws_cache_heap_item_destroy(cache, item, 1); 189d4afb5ceSopenharmony_ci } 190d4afb5ceSopenharmony_ci} 191d4afb5ceSopenharmony_ci 192d4afb5ceSopenharmony_ci/* 193d4afb5ceSopenharmony_ci * Let's figure out what the earliest next expiry is 194d4afb5ceSopenharmony_ci */ 195d4afb5ceSopenharmony_ci 196d4afb5ceSopenharmony_cistatic int 197d4afb5ceSopenharmony_ciearliest_expiry(lws_cache_ttl_lru_t_heap_t *cache, lws_usec_t *pearliest) 198d4afb5ceSopenharmony_ci{ 199d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item; 200d4afb5ceSopenharmony_ci 201d4afb5ceSopenharmony_ci if (!cache->items_expiry.head) 202d4afb5ceSopenharmony_ci return 1; 203d4afb5ceSopenharmony_ci 204d4afb5ceSopenharmony_ci item = lws_container_of(cache->items_expiry.head, 205d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t, list_expiry); 206d4afb5ceSopenharmony_ci 207d4afb5ceSopenharmony_ci *pearliest = item->expiry; 208d4afb5ceSopenharmony_ci 209d4afb5ceSopenharmony_ci return 0; 210d4afb5ceSopenharmony_ci} 211d4afb5ceSopenharmony_ci 212d4afb5ceSopenharmony_cistatic void 213d4afb5ceSopenharmony_ciupdate_sul(lws_cache_ttl_lru_t_heap_t *cache) 214d4afb5ceSopenharmony_ci{ 215d4afb5ceSopenharmony_ci lws_usec_t earliest; 216d4afb5ceSopenharmony_ci 217d4afb5ceSopenharmony_ci /* weed out any newly-expired */ 218d4afb5ceSopenharmony_ci expiry_cb(&cache->cache.sul); 219d4afb5ceSopenharmony_ci 220d4afb5ceSopenharmony_ci /* figure out the next soonest expiring item */ 221d4afb5ceSopenharmony_ci if (earliest_expiry(cache, &earliest)) { 222d4afb5ceSopenharmony_ci lws_sul_cancel(&cache->cache.sul); 223d4afb5ceSopenharmony_ci return; 224d4afb5ceSopenharmony_ci } 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ci lwsl_debug("%s: setting exp %llu\n", __func__, 227d4afb5ceSopenharmony_ci (unsigned long long)earliest); 228d4afb5ceSopenharmony_ci 229d4afb5ceSopenharmony_ci if (earliest) 230d4afb5ceSopenharmony_ci lws_cache_schedule(&cache->cache, expiry_cb, earliest); 231d4afb5ceSopenharmony_ci} 232d4afb5ceSopenharmony_ci 233d4afb5ceSopenharmony_cistatic lws_cache_ttl_item_heap_t * 234d4afb5ceSopenharmony_cilws_cache_heap_specific(lws_cache_ttl_lru_t_heap_t *cache, 235d4afb5ceSopenharmony_ci const char *specific_key) 236d4afb5ceSopenharmony_ci{ 237d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, d, cache->items_lru.head) { 238d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item = lws_container_of(d, 239d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t, 240d4afb5ceSopenharmony_ci list_lru); 241d4afb5ceSopenharmony_ci const char *iname = ((const char *)&item[1]) + item->size; 242d4afb5ceSopenharmony_ci 243d4afb5ceSopenharmony_ci if (!strcmp(specific_key, iname)) 244d4afb5ceSopenharmony_ci return item; 245d4afb5ceSopenharmony_ci 246d4afb5ceSopenharmony_ci } lws_end_foreach_dll(d); 247d4afb5ceSopenharmony_ci 248d4afb5ceSopenharmony_ci return NULL; 249d4afb5ceSopenharmony_ci} 250d4afb5ceSopenharmony_ci 251d4afb5ceSopenharmony_cistatic int 252d4afb5ceSopenharmony_cilws_cache_heap_tag_match(struct lws_cache_ttl_lru *cache, const char *wc, 253d4afb5ceSopenharmony_ci const char *tag, char lookup_rules) 254d4afb5ceSopenharmony_ci{ 255d4afb5ceSopenharmony_ci return lws_strcmp_wildcard(wc, strlen(wc), tag, strlen(tag)); 256d4afb5ceSopenharmony_ci} 257d4afb5ceSopenharmony_ci 258d4afb5ceSopenharmony_cistatic int 259d4afb5ceSopenharmony_cilws_cache_heap_lookup(struct lws_cache_ttl_lru *_c, const char *wildcard_key, 260d4afb5ceSopenharmony_ci lws_dll2_owner_t *results_owner) 261d4afb5ceSopenharmony_ci{ 262d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c; 263d4afb5ceSopenharmony_ci size_t sklen = strlen(wildcard_key); 264d4afb5ceSopenharmony_ci 265d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, d, cache->items_lru.head) { 266d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item = lws_container_of(d, 267d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t, 268d4afb5ceSopenharmony_ci list_lru); 269d4afb5ceSopenharmony_ci const char *iname = ((const char *)&item[1]) + item->size; 270d4afb5ceSopenharmony_ci 271d4afb5ceSopenharmony_ci if (!lws_strcmp_wildcard(wildcard_key, sklen, iname, 272d4afb5ceSopenharmony_ci strlen(iname))) { 273d4afb5ceSopenharmony_ci size_t ilen = strlen(iname); 274d4afb5ceSopenharmony_ci lws_cache_match_t *m; 275d4afb5ceSopenharmony_ci char hit = 0; 276d4afb5ceSopenharmony_ci 277d4afb5ceSopenharmony_ci /* 278d4afb5ceSopenharmony_ci * It musn't already be on the list from an earlier 279d4afb5ceSopenharmony_ci * cache level 280d4afb5ceSopenharmony_ci */ 281d4afb5ceSopenharmony_ci 282d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, e, 283d4afb5ceSopenharmony_ci results_owner->head) { 284d4afb5ceSopenharmony_ci lws_cache_match_t *i = lws_container_of(e, 285d4afb5ceSopenharmony_ci lws_cache_match_t, list); 286d4afb5ceSopenharmony_ci if (i->tag_size == ilen && 287d4afb5ceSopenharmony_ci !strcmp(iname, ((const char *)&i[1]))) { 288d4afb5ceSopenharmony_ci hit = 1; 289d4afb5ceSopenharmony_ci break; 290d4afb5ceSopenharmony_ci } 291d4afb5ceSopenharmony_ci } lws_end_foreach_dll(e); 292d4afb5ceSopenharmony_ci 293d4afb5ceSopenharmony_ci if (!hit) { 294d4afb5ceSopenharmony_ci 295d4afb5ceSopenharmony_ci /* 296d4afb5ceSopenharmony_ci * it's unique, instantiate a record for it 297d4afb5ceSopenharmony_ci */ 298d4afb5ceSopenharmony_ci 299d4afb5ceSopenharmony_ci m = lws_fi(&_c->info.cx->fic, 300d4afb5ceSopenharmony_ci "cache_lookup_oom") ? NULL : 301d4afb5ceSopenharmony_ci lws_malloc(sizeof(*m) + ilen + 1, 302d4afb5ceSopenharmony_ci __func__); 303d4afb5ceSopenharmony_ci if (!m) { 304d4afb5ceSopenharmony_ci lws_cache_clear_matches(results_owner); 305d4afb5ceSopenharmony_ci return 1; 306d4afb5ceSopenharmony_ci } 307d4afb5ceSopenharmony_ci 308d4afb5ceSopenharmony_ci memset(&m->list, 0, sizeof(m->list)); 309d4afb5ceSopenharmony_ci m->tag_size = ilen; 310d4afb5ceSopenharmony_ci memcpy(&m[1], iname, ilen + 1); 311d4afb5ceSopenharmony_ci 312d4afb5ceSopenharmony_ci lws_dll2_add_tail(&m->list, results_owner); 313d4afb5ceSopenharmony_ci } 314d4afb5ceSopenharmony_ci } 315d4afb5ceSopenharmony_ci 316d4afb5ceSopenharmony_ci } lws_end_foreach_dll(d); 317d4afb5ceSopenharmony_ci 318d4afb5ceSopenharmony_ci return 0; 319d4afb5ceSopenharmony_ci} 320d4afb5ceSopenharmony_ci 321d4afb5ceSopenharmony_cistatic int 322d4afb5ceSopenharmony_cilws_cache_heap_write(struct lws_cache_ttl_lru *_c, const char *specific_key, 323d4afb5ceSopenharmony_ci const uint8_t *source, size_t size, lws_usec_t expiry, 324d4afb5ceSopenharmony_ci void **ppvoid) 325d4afb5ceSopenharmony_ci{ 326d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c; 327d4afb5ceSopenharmony_ci struct lws_cache_ttl_lru *backing = _c; 328d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item, *ei; 329d4afb5ceSopenharmony_ci size_t kl = strlen(specific_key); 330d4afb5ceSopenharmony_ci char *p; 331d4afb5ceSopenharmony_ci 332d4afb5ceSopenharmony_ci lwsl_cache("%s: %s: len %d\n", __func__, _c->info.name, (int)size); 333d4afb5ceSopenharmony_ci 334d4afb5ceSopenharmony_ci /* 335d4afb5ceSopenharmony_ci * Is this new tag going to invalidate any existing cached meta-results? 336d4afb5ceSopenharmony_ci * 337d4afb5ceSopenharmony_ci * If so, let's destroy any of those first to recover the heap 338d4afb5ceSopenharmony_ci */ 339d4afb5ceSopenharmony_ci 340d4afb5ceSopenharmony_ci if (backing->info.parent) 341d4afb5ceSopenharmony_ci backing = backing->info.parent; 342d4afb5ceSopenharmony_ci 343d4afb5ceSopenharmony_ci lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 344d4afb5ceSopenharmony_ci cache->items_lru.head) { 345d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *i = lws_container_of(d, 346d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t, 347d4afb5ceSopenharmony_ci list_lru); 348d4afb5ceSopenharmony_ci const char *iname = ((const char *)&i[1]) + i->size; 349d4afb5ceSopenharmony_ci 350d4afb5ceSopenharmony_ci if (*iname == META_ITEM_LEADING) { 351d4afb5ceSopenharmony_ci 352d4afb5ceSopenharmony_ci /* 353d4afb5ceSopenharmony_ci * If the item about to be added would match any cached 354d4afb5ceSopenharmony_ci * results from before it was added, we have to 355d4afb5ceSopenharmony_ci * invalidate them. To check this, we have to use the 356d4afb5ceSopenharmony_ci * matching rules at the backing store level 357d4afb5ceSopenharmony_ci */ 358d4afb5ceSopenharmony_ci 359d4afb5ceSopenharmony_ci if (!strcmp(iname + 1, specific_key)) 360d4afb5ceSopenharmony_ci _lws_cache_heap_item_destroy(cache, i); 361d4afb5ceSopenharmony_ci } 362d4afb5ceSopenharmony_ci 363d4afb5ceSopenharmony_ci } lws_end_foreach_dll_safe(d, d1); 364d4afb5ceSopenharmony_ci 365d4afb5ceSopenharmony_ci 366d4afb5ceSopenharmony_ci /* 367d4afb5ceSopenharmony_ci * Keep us under the limit if possible... note this will always allow 368d4afb5ceSopenharmony_ci * caching a single large item even if it is above the limits 369d4afb5ceSopenharmony_ci */ 370d4afb5ceSopenharmony_ci 371d4afb5ceSopenharmony_ci while ((cache->cache.info.max_footprint && 372d4afb5ceSopenharmony_ci cache->cache.current_footprint + size > 373d4afb5ceSopenharmony_ci cache->cache.info.max_footprint) || 374d4afb5ceSopenharmony_ci (cache->cache.info.max_items && 375d4afb5ceSopenharmony_ci cache->items_lru.count + 1 > cache->cache.info.max_items)) 376d4afb5ceSopenharmony_ci lws_cache_item_evict_lru(cache); 377d4afb5ceSopenharmony_ci 378d4afb5ceSopenharmony_ci /* remove any existing entry of the same key */ 379d4afb5ceSopenharmony_ci 380d4afb5ceSopenharmony_ci lws_cache_heap_invalidate(&cache->cache, specific_key); 381d4afb5ceSopenharmony_ci 382d4afb5ceSopenharmony_ci item = lws_fi(&_c->info.cx->fic, "cache_write_oom") ? NULL : 383d4afb5ceSopenharmony_ci lws_malloc(sizeof(*item) + kl + 1u + size, __func__); 384d4afb5ceSopenharmony_ci if (!item) 385d4afb5ceSopenharmony_ci return 1; 386d4afb5ceSopenharmony_ci 387d4afb5ceSopenharmony_ci cache->cache.current_footprint += item->size; 388d4afb5ceSopenharmony_ci 389d4afb5ceSopenharmony_ci /* only need to zero down our item object */ 390d4afb5ceSopenharmony_ci memset(item, 0, sizeof(*item)); 391d4afb5ceSopenharmony_ci 392d4afb5ceSopenharmony_ci p = (char *)&item[1]; 393d4afb5ceSopenharmony_ci if (ppvoid) 394d4afb5ceSopenharmony_ci *ppvoid = p; 395d4afb5ceSopenharmony_ci 396d4afb5ceSopenharmony_ci /* copy the payload into place */ 397d4afb5ceSopenharmony_ci if (source) 398d4afb5ceSopenharmony_ci memcpy(p, source, size); 399d4afb5ceSopenharmony_ci 400d4afb5ceSopenharmony_ci /* copy the key string into place, with terminating NUL */ 401d4afb5ceSopenharmony_ci memcpy(p + size, specific_key, kl + 1); 402d4afb5ceSopenharmony_ci 403d4afb5ceSopenharmony_ci item->expiry = expiry; 404d4afb5ceSopenharmony_ci item->key_len = kl; 405d4afb5ceSopenharmony_ci item->size = size; 406d4afb5ceSopenharmony_ci 407d4afb5ceSopenharmony_ci if (expiry) { 408d4afb5ceSopenharmony_ci /* adding to expiry is optional, on nonzero expiry */ 409d4afb5ceSopenharmony_ci lws_dll2_add_sorted(&item->list_expiry, &cache->items_expiry, 410d4afb5ceSopenharmony_ci sort_expiry); 411d4afb5ceSopenharmony_ci ei = lws_container_of(cache->items_expiry.head, 412d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t, list_expiry); 413d4afb5ceSopenharmony_ci lwsl_debug("%s: setting exp %llu\n", __func__, 414d4afb5ceSopenharmony_ci (unsigned long long)ei->expiry); 415d4afb5ceSopenharmony_ci lws_cache_schedule(&cache->cache, expiry_cb, ei->expiry); 416d4afb5ceSopenharmony_ci } 417d4afb5ceSopenharmony_ci 418d4afb5ceSopenharmony_ci /* always add outselves to head of lru list */ 419d4afb5ceSopenharmony_ci lws_dll2_add_head(&item->list_lru, &cache->items_lru); 420d4afb5ceSopenharmony_ci 421d4afb5ceSopenharmony_ci return 0; 422d4afb5ceSopenharmony_ci} 423d4afb5ceSopenharmony_ci 424d4afb5ceSopenharmony_cistatic int 425d4afb5ceSopenharmony_cilws_cache_heap_get(struct lws_cache_ttl_lru *_c, const char *specific_key, 426d4afb5ceSopenharmony_ci const void **pdata, size_t *psize) 427d4afb5ceSopenharmony_ci{ 428d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c; 429d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item; 430d4afb5ceSopenharmony_ci 431d4afb5ceSopenharmony_ci item = lws_cache_heap_specific(cache, specific_key); 432d4afb5ceSopenharmony_ci if (!item) 433d4afb5ceSopenharmony_ci return 1; 434d4afb5ceSopenharmony_ci 435d4afb5ceSopenharmony_ci /* we are using it, move it to lru head */ 436d4afb5ceSopenharmony_ci lws_dll2_remove(&item->list_lru); 437d4afb5ceSopenharmony_ci lws_dll2_add_head(&item->list_lru, &cache->items_lru); 438d4afb5ceSopenharmony_ci 439d4afb5ceSopenharmony_ci if (pdata) { 440d4afb5ceSopenharmony_ci *pdata = (const void *)&item[1]; 441d4afb5ceSopenharmony_ci *psize = item->size; 442d4afb5ceSopenharmony_ci } 443d4afb5ceSopenharmony_ci 444d4afb5ceSopenharmony_ci return 0; 445d4afb5ceSopenharmony_ci} 446d4afb5ceSopenharmony_ci 447d4afb5ceSopenharmony_cistatic int 448d4afb5ceSopenharmony_cilws_cache_heap_invalidate(struct lws_cache_ttl_lru *_c, const char *specific_key) 449d4afb5ceSopenharmony_ci{ 450d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c; 451d4afb5ceSopenharmony_ci struct lws_cache_ttl_lru *backing = _c; 452d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item; 453d4afb5ceSopenharmony_ci const void *user; 454d4afb5ceSopenharmony_ci size_t size; 455d4afb5ceSopenharmony_ci 456d4afb5ceSopenharmony_ci if (lws_cache_heap_get(_c, specific_key, &user, &size)) 457d4afb5ceSopenharmony_ci return 0; 458d4afb5ceSopenharmony_ci 459d4afb5ceSopenharmony_ci if (backing->info.parent) 460d4afb5ceSopenharmony_ci backing = backing->info.parent; 461d4afb5ceSopenharmony_ci 462d4afb5ceSopenharmony_ci item = (lws_cache_ttl_item_heap_t *)(((uint8_t *)user) - sizeof(*item)); 463d4afb5ceSopenharmony_ci 464d4afb5ceSopenharmony_ci /* 465d4afb5ceSopenharmony_ci * We must invalidate any cached results that would have included this 466d4afb5ceSopenharmony_ci */ 467d4afb5ceSopenharmony_ci 468d4afb5ceSopenharmony_ci lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 469d4afb5ceSopenharmony_ci cache->items_lru.head) { 470d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *i = lws_container_of(d, 471d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t, 472d4afb5ceSopenharmony_ci list_lru); 473d4afb5ceSopenharmony_ci const char *iname = ((const char *)&i[1]) + i->size; 474d4afb5ceSopenharmony_ci 475d4afb5ceSopenharmony_ci if (*iname == META_ITEM_LEADING) { 476d4afb5ceSopenharmony_ci 477d4afb5ceSopenharmony_ci /* 478d4afb5ceSopenharmony_ci * If the item about to be added would match any cached 479d4afb5ceSopenharmony_ci * results from before it was added, we have to 480d4afb5ceSopenharmony_ci * invalidate them. To check this, we have to use the 481d4afb5ceSopenharmony_ci * matching rules at the backing store level 482d4afb5ceSopenharmony_ci */ 483d4afb5ceSopenharmony_ci 484d4afb5ceSopenharmony_ci if (!backing->info.ops->tag_match(backing, iname + 1, 485d4afb5ceSopenharmony_ci specific_key, 1)) 486d4afb5ceSopenharmony_ci _lws_cache_heap_item_destroy(cache, i); 487d4afb5ceSopenharmony_ci } 488d4afb5ceSopenharmony_ci 489d4afb5ceSopenharmony_ci } lws_end_foreach_dll_safe(d, d1); 490d4afb5ceSopenharmony_ci 491d4afb5ceSopenharmony_ci lws_cache_heap_item_destroy(cache, item, 0); 492d4afb5ceSopenharmony_ci 493d4afb5ceSopenharmony_ci return 0; 494d4afb5ceSopenharmony_ci} 495d4afb5ceSopenharmony_ci 496d4afb5ceSopenharmony_cistatic struct lws_cache_ttl_lru * 497d4afb5ceSopenharmony_cilws_cache_heap_create(const struct lws_cache_creation_info *info) 498d4afb5ceSopenharmony_ci{ 499d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t_heap_t *cache; 500d4afb5ceSopenharmony_ci 501d4afb5ceSopenharmony_ci assert(info->cx); 502d4afb5ceSopenharmony_ci assert(info->name); 503d4afb5ceSopenharmony_ci 504d4afb5ceSopenharmony_ci cache = lws_fi(&info->cx->fic, "cache_createfail") ? NULL : 505d4afb5ceSopenharmony_ci lws_zalloc(sizeof(*cache), __func__); 506d4afb5ceSopenharmony_ci if (!cache) 507d4afb5ceSopenharmony_ci return NULL; 508d4afb5ceSopenharmony_ci 509d4afb5ceSopenharmony_ci cache->cache.info = *info; 510d4afb5ceSopenharmony_ci if (info->parent) 511d4afb5ceSopenharmony_ci info->parent->child = &cache->cache; 512d4afb5ceSopenharmony_ci 513d4afb5ceSopenharmony_ci // lwsl_cache("%s: create %s\n", __func__, info->name); 514d4afb5ceSopenharmony_ci 515d4afb5ceSopenharmony_ci return (struct lws_cache_ttl_lru *)cache; 516d4afb5ceSopenharmony_ci} 517d4afb5ceSopenharmony_ci 518d4afb5ceSopenharmony_cistatic int 519d4afb5ceSopenharmony_cidestroy_dll(struct lws_dll2 *d, void *user) 520d4afb5ceSopenharmony_ci{ 521d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t *_c = (struct lws_cache_ttl_lru *)user; 522d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c; 523d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item = 524d4afb5ceSopenharmony_ci lws_container_of(d, lws_cache_ttl_item_heap_t, list_lru); 525d4afb5ceSopenharmony_ci 526d4afb5ceSopenharmony_ci lws_cache_heap_item_destroy(cache, item, 0); 527d4afb5ceSopenharmony_ci 528d4afb5ceSopenharmony_ci return 0; 529d4afb5ceSopenharmony_ci} 530d4afb5ceSopenharmony_ci 531d4afb5ceSopenharmony_cistatic int 532d4afb5ceSopenharmony_cilws_cache_heap_expunge(struct lws_cache_ttl_lru *_c) 533d4afb5ceSopenharmony_ci{ 534d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c; 535d4afb5ceSopenharmony_ci 536d4afb5ceSopenharmony_ci lws_dll2_foreach_safe(&cache->items_lru, cache, destroy_dll); 537d4afb5ceSopenharmony_ci 538d4afb5ceSopenharmony_ci return 0; 539d4afb5ceSopenharmony_ci} 540d4afb5ceSopenharmony_ci 541d4afb5ceSopenharmony_cistatic void 542d4afb5ceSopenharmony_cilws_cache_heap_destroy(struct lws_cache_ttl_lru **_cache) 543d4afb5ceSopenharmony_ci{ 544d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t *c = *_cache; 545d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)c; 546d4afb5ceSopenharmony_ci 547d4afb5ceSopenharmony_ci if (!cache) 548d4afb5ceSopenharmony_ci return; 549d4afb5ceSopenharmony_ci 550d4afb5ceSopenharmony_ci lws_sul_cancel(&c->sul); 551d4afb5ceSopenharmony_ci 552d4afb5ceSopenharmony_ci lws_dll2_foreach_safe(&cache->items_lru, cache, destroy_dll); 553d4afb5ceSopenharmony_ci 554d4afb5ceSopenharmony_ci lws_free_set_NULL(*_cache); 555d4afb5ceSopenharmony_ci} 556d4afb5ceSopenharmony_ci 557d4afb5ceSopenharmony_ci#if defined(_DEBUG) 558d4afb5ceSopenharmony_cistatic int 559d4afb5ceSopenharmony_cidump_dll(struct lws_dll2 *d, void *user) 560d4afb5ceSopenharmony_ci{ 561d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item = 562d4afb5ceSopenharmony_ci lws_container_of(d, lws_cache_ttl_item_heap_t, list_lru); 563d4afb5ceSopenharmony_ci 564d4afb5ceSopenharmony_ci lwsl_cache(" %s: size %d, exp %llu\n", 565d4afb5ceSopenharmony_ci (const char *)&item[1] + item->size, 566d4afb5ceSopenharmony_ci (int)item->size, (unsigned long long)item->expiry); 567d4afb5ceSopenharmony_ci 568d4afb5ceSopenharmony_ci lwsl_hexdump_cache((const char *)&item[1], item->size); 569d4afb5ceSopenharmony_ci 570d4afb5ceSopenharmony_ci return 0; 571d4afb5ceSopenharmony_ci} 572d4afb5ceSopenharmony_ci 573d4afb5ceSopenharmony_cistatic void 574d4afb5ceSopenharmony_cilws_cache_heap_debug_dump(struct lws_cache_ttl_lru *_c) 575d4afb5ceSopenharmony_ci{ 576d4afb5ceSopenharmony_ci lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c; 577d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_NO_LOGS) 578d4afb5ceSopenharmony_ci lws_cache_ttl_item_heap_t *item = NULL; 579d4afb5ceSopenharmony_ci 580d4afb5ceSopenharmony_ci lws_dll2_t *d = cache->items_expiry.head; 581d4afb5ceSopenharmony_ci 582d4afb5ceSopenharmony_ci if (d) 583d4afb5ceSopenharmony_ci item = lws_container_of(d, lws_cache_ttl_item_heap_t, 584d4afb5ceSopenharmony_ci list_expiry); 585d4afb5ceSopenharmony_ci 586d4afb5ceSopenharmony_ci lwsl_cache("%s: %s: items %d, earliest %llu\n", __func__, 587d4afb5ceSopenharmony_ci cache->cache.info.name, (int)cache->items_lru.count, 588d4afb5ceSopenharmony_ci item ? (unsigned long long)item->expiry : 0ull); 589d4afb5ceSopenharmony_ci#endif 590d4afb5ceSopenharmony_ci 591d4afb5ceSopenharmony_ci lws_dll2_foreach_safe(&cache->items_lru, cache, dump_dll); 592d4afb5ceSopenharmony_ci} 593d4afb5ceSopenharmony_ci#endif 594d4afb5ceSopenharmony_ci 595d4afb5ceSopenharmony_ciconst struct lws_cache_ops lws_cache_ops_heap = { 596d4afb5ceSopenharmony_ci .create = lws_cache_heap_create, 597d4afb5ceSopenharmony_ci .destroy = lws_cache_heap_destroy, 598d4afb5ceSopenharmony_ci .expunge = lws_cache_heap_expunge, 599d4afb5ceSopenharmony_ci 600d4afb5ceSopenharmony_ci .write = lws_cache_heap_write, 601d4afb5ceSopenharmony_ci .tag_match = lws_cache_heap_tag_match, 602d4afb5ceSopenharmony_ci .lookup = lws_cache_heap_lookup, 603d4afb5ceSopenharmony_ci .invalidate = lws_cache_heap_invalidate, 604d4afb5ceSopenharmony_ci .get = lws_cache_heap_get, 605d4afb5ceSopenharmony_ci#if defined(_DEBUG) 606d4afb5ceSopenharmony_ci .debug_dump = lws_cache_heap_debug_dump, 607d4afb5ceSopenharmony_ci#endif 608d4afb5ceSopenharmony_ci}; 609