From f4267177e617464c6d8c5462a16dc0f39bc76033 Mon Sep 17 00:00:00 2001 From: Benign X <1341398182@qq.com> Date: Mon, 29 Jan 2024 20:44:56 +0800 Subject: [PATCH] feat(cache): refactor cache framework and add new APIs (#5501) --- src/misc/cache/_lv_cache_lru_rb.c | 85 ++++++++++++++++++++----------- src/misc/cache/lv_cache.c | 61 +++++++++++++++++++++- src/misc/cache/lv_cache.h | 4 +- src/misc/cache/lv_cache_private.h | 21 +++++--- 4 files changed, 131 insertions(+), 40 deletions(-) diff --git a/src/misc/cache/_lv_cache_lru_rb.c b/src/misc/cache/_lv_cache_lru_rb.c index 4f375aa8c..cd6298f6a 100644 --- a/src/misc/cache/_lv_cache_lru_rb.c +++ b/src/misc/cache/_lv_cache_lru_rb.c @@ -44,6 +44,9 @@ static lv_cache_entry_t * add_cb(lv_cache_t * cache, const void * key, void * us static void remove_cb(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data); static void drop_cb(lv_cache_t * cache, const void * key, void * user_data); static void drop_all_cb(lv_cache_t * cache, void * user_data); +static lv_cache_entry_t * get_victim_cb(lv_cache_t * cache, void * user_data); +static lv_cache_reserve_cond_res_t reserve_cond_cb(lv_cache_t * cache, const void * key, size_t reserved_size, + void * user_data); static void * alloc_new_node(lv_lru_rb_t_ * lru, void * key, void * user_data); inline static void ** get_lru_node(lv_lru_rb_t_ * lru, lv_rb_node_t * node); @@ -63,7 +66,9 @@ const lv_cache_class_t lv_cache_class_lru_rb_count = { .add_cb = add_cb, .remove_cb = remove_cb, .drop_cb = drop_cb, - .drop_all_cb = drop_all_cb + .drop_all_cb = drop_all_cb, + .get_victim_cb = get_victim_cb, + .reserve_cond_cb = reserve_cond_cb }; const lv_cache_class_t lv_cache_class_lru_rb_size = { @@ -75,7 +80,9 @@ const lv_cache_class_t lv_cache_class_lru_rb_size = { .add_cb = add_cb, .remove_cb = remove_cb, .drop_cb = drop_cb, - .drop_all_cb = drop_all_cb + .drop_all_cb = drop_all_cb, + .get_victim_cb = get_victim_cb, + .reserve_cond_cb = reserve_cond_cb }; /********************** * STATIC VARIABLES @@ -259,34 +266,6 @@ static lv_cache_entry_t * add_cb(lv_cache_t * cache, const void * key, void * us return NULL; } - uint32_t data_size = lru->get_data_size_cb(key); - if(data_size > lru->cache.max_size) { - LV_LOG_ERROR("data size (%" LV_PRIu32 ") is larger than max size (%" LV_PRIu32 ")", data_size, - (uint32_t)lru->cache.max_size); - return NULL; - } - - void * tail = _lv_ll_get_tail(&lru->ll); - void * curr = tail; - while(cache->size + data_size > lru->cache.max_size) { - if(curr == NULL) { - LV_LOG_ERROR("failed to drop cache"); - return NULL; - } - - lv_rb_node_t * tail_node = *(lv_rb_node_t **)curr; - void * search_key = tail_node->data; - lv_cache_entry_t * entry = lv_cache_entry_get_entry(search_key, cache->node_size); - if(lv_cache_entry_get_ref(entry) == 0) { - cache->clz->drop_cb(cache, search_key, user_data); - curr = _lv_ll_get_tail(&lru->ll); - continue; - } - - curr = _lv_ll_get_prev(&lru->ll, curr); - } - - /*cache miss*/ lv_rb_node_t * new_node = alloc_new_node(lru, (void *)key, user_data); if(new_node == NULL) { return NULL; @@ -294,7 +273,7 @@ static lv_cache_entry_t * add_cb(lv_cache_t * cache, const void * key, void * us lv_cache_entry_t * entry = lv_cache_entry_get_entry(new_node->data, cache->node_size); - cache->size += data_size; + cache->size += lru->get_data_size_cb(key); return entry; } @@ -391,6 +370,50 @@ static void drop_all_cb(lv_cache_t * cache, void * user_data) cache->size = 0; } +static lv_cache_entry_t * get_victim_cb(lv_cache_t * cache, void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + + lv_rb_node_t ** tail; + _LV_LL_READ_BACK(&lru->ll, tail) { + lv_rb_node_t * tail_node = *tail; + lv_cache_entry_t * entry = lv_cache_entry_get_entry(tail_node->data, cache->node_size); + if(lv_cache_entry_get_ref(entry) == 0) { + return entry; + } + } + + return NULL; +} + +static lv_cache_reserve_cond_res_t reserve_cond_cb(lv_cache_t * cache, const void * key, size_t reserved_size, + void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + + if(lru == NULL) { + return LV_CACHE_RESERVE_COND_ERROR; + } + + uint32_t data_size = key ? lru->get_data_size_cb(key) : 0; + if(data_size > lru->cache.max_size) { + LV_LOG_ERROR("data size (%" LV_PRIu32 ") is larger than max size (%" LV_PRIu32 ")", data_size, lru->cache.max_size); + return LV_CACHE_RESERVE_COND_TOO_LARGE; + } + + return cache->size + reserved_size + data_size > lru->cache.max_size + ? LV_CACHE_RESERVE_COND_NEED_VICTIM + : LV_CACHE_RESERVE_COND_OK; +} + static uint32_t cnt_get_data_size_cb(const void * data) { LV_UNUSED(data); diff --git a/src/misc/cache/lv_cache.c b/src/misc/cache/lv_cache.c index 46abe430c..27b52b14f 100644 --- a/src/misc/cache/lv_cache.c +++ b/src/misc/cache/lv_cache.c @@ -23,6 +23,8 @@ * STATIC PROTOTYPES **********************/ static void cache_drop_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data); +static bool cache_evict_one_internal_no_lock(lv_cache_t * cache, void * user_data); +static lv_cache_entry_t * cache_add_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data); /********************** * GLOBAL VARIABLES **********************/ @@ -106,11 +108,12 @@ lv_cache_entry_t * lv_cache_add(lv_cache_t * cache, const void * key, void * use LV_ASSERT_NULL(key); lv_mutex_lock(&cache->lock); - lv_cache_entry_t * entry = cache->clz->add_cb(cache, key, user_data); + lv_cache_entry_t * entry = cache_add_internal_no_lock(cache, key, user_data); if(entry != NULL) { lv_cache_entry_acquire_data(entry); } lv_mutex_unlock(&cache->lock); + return entry; } lv_cache_entry_t * lv_cache_acquire_or_create(lv_cache_t * cache, const void * key, void * user_data) @@ -125,7 +128,7 @@ lv_cache_entry_t * lv_cache_acquire_or_create(lv_cache_t * cache, const void * k lv_mutex_unlock(&cache->lock); return entry; } - entry = cache->clz->add_cb(cache, key, user_data); + entry = cache_add_internal_no_lock(cache, key, user_data); if(entry == NULL) { lv_mutex_unlock(&cache->lock); return NULL; @@ -142,6 +145,16 @@ lv_cache_entry_t * lv_cache_acquire_or_create(lv_cache_t * cache, const void * k lv_mutex_unlock(&cache->lock); return entry; } +void lv_cache_reserve(lv_cache_t * cache, uint32_t reserved_size, void * user_data) +{ + LV_ASSERT_NULL(cache); + + for(lv_cache_reserve_cond_res_t reserve_cond_res = cache->clz->reserve_cond_cb(cache, NULL, reserved_size, user_data); + reserve_cond_res == LV_CACHE_RESERVE_COND_NEED_VICTIM; + reserve_cond_res = cache->clz->reserve_cond_cb(cache, NULL, reserved_size, user_data)) + cache_evict_one_internal_no_lock(cache, user_data); + +} void lv_cache_drop(lv_cache_t * cache, const void * key, void * user_data) { LV_ASSERT_NULL(cache); @@ -151,6 +164,16 @@ void lv_cache_drop(lv_cache_t * cache, const void * key, void * user_data) cache_drop_internal_no_lock(cache, key, user_data); lv_mutex_unlock(&cache->lock); } +bool lv_cache_evict_one(lv_cache_t * cache, void * user_data) +{ + LV_ASSERT_NULL(cache); + + lv_mutex_lock(&cache->lock); + bool res = cache_evict_one_internal_no_lock(cache, user_data); + lv_mutex_unlock(&cache->lock); + + return res; +} void lv_cache_drop_all(lv_cache_t * cache, void * user_data) { LV_ASSERT_NULL(cache); @@ -195,9 +218,11 @@ void lv_cache_set_free_cb(lv_cache_t * cache, lv_cache_free_cb_t free_cb, void * LV_UNUSED(user_data); cache->ops.free_cb = free_cb; } + /********************** * STATIC FUNCTIONS **********************/ + static void cache_drop_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data) { lv_cache_entry_t * entry = cache->clz->get_cb(cache, key, user_data); @@ -215,3 +240,35 @@ static void cache_drop_internal_no_lock(lv_cache_t * cache, const void * key, vo cache->clz->remove_cb(cache, entry, user_data); } } + +static bool cache_evict_one_internal_no_lock(lv_cache_t * cache, void * user_data) +{ + lv_cache_entry_t * victim = cache->clz->get_victim_cb(cache, user_data); + + if(victim == NULL) { + LV_LOG_ERROR("No victim found"); + return false; + } + + cache->clz->remove_cb(cache, victim, user_data); + cache->ops.free_cb(lv_cache_entry_get_data(victim), user_data); + lv_cache_entry_delete(victim); + return true; +} + +static lv_cache_entry_t * cache_add_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data) +{ + lv_cache_reserve_cond_res_t reserve_cond_res = cache->clz->reserve_cond_cb(cache, key, 0, user_data); + if(reserve_cond_res == LV_CACHE_RESERVE_COND_TOO_LARGE) { + LV_LOG_ERROR("data %p is too large that exceeds max size (%" LV_PRIu32 ")", key, cache->max_size); + } + + for(; reserve_cond_res == LV_CACHE_RESERVE_COND_NEED_VICTIM; + reserve_cond_res = cache->clz->reserve_cond_cb(cache, key, 0, user_data)) + if(cache_evict_one_internal_no_lock(cache, user_data) == false) + return NULL; + + lv_cache_entry_t * entry = cache->clz->add_cb(cache, key, user_data); + + return entry; +} diff --git a/src/misc/cache/lv_cache.h b/src/misc/cache/lv_cache.h index c79a00e76..0ee2955c4 100644 --- a/src/misc/cache/lv_cache.h +++ b/src/misc/cache/lv_cache.h @@ -41,10 +41,12 @@ lv_cache_entry_t * lv_cache_acquire(lv_cache_t * cache, const void * key, void * lv_cache_entry_t * lv_cache_acquire_or_create(lv_cache_t * cache, const void * key, void * user_data); lv_cache_entry_t * lv_cache_add(lv_cache_t * cache, const void * key, void * user_data); void lv_cache_release(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data); +void lv_cache_reserve(lv_cache_t * cache, uint32_t reserved_size, void * user_data); void lv_cache_drop(lv_cache_t * cache, const void * key, void * user_data); void lv_cache_drop_all(lv_cache_t * cache, void * user_data); +bool lv_cache_evict_one(lv_cache_t * cache, void * user_data); -void lv_cache_set_max_size(lv_cache_t * cache, size_t max_size, void * user_data); +void lv_cache_set_max_size(lv_cache_t * cache, size_t max_size, void * user_data); size_t lv_cache_get_max_size(lv_cache_t * cache, void * user_data); size_t lv_cache_get_size(lv_cache_t * cache, void * user_data); size_t lv_cache_get_free_size(lv_cache_t * cache, void * user_data); diff --git a/src/misc/cache/lv_cache_private.h b/src/misc/cache/lv_cache_private.h index 7a83e04d0..54ddda86b 100644 --- a/src/misc/cache/lv_cache_private.h +++ b/src/misc/cache/lv_cache_private.h @@ -26,9 +26,13 @@ extern "C" { * TYPEDEFS **********************/ -/*----------------- - * Cache entry slot - *----------------*/ +typedef enum { + LV_CACHE_RESERVE_COND_OK, + LV_CACHE_RESERVE_COND_TOO_LARGE, + LV_CACHE_RESERVE_COND_NEED_VICTIM, + LV_CACHE_RESERVE_COND_ERROR +} lv_cache_reserve_cond_res_t; + struct _lv_cache_ops_t; struct _lv_cache_t; struct _lv_cache_class_t; @@ -52,6 +56,9 @@ typedef lv_cache_entry_t * (*lv_cache_add_cb_t)(lv_cache_t * cache, const void * typedef void (*lv_cache_remove_cb_t)(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data); typedef void (*lv_cache_drop_cb_t)(lv_cache_t * cache, const void * key, void * user_data); typedef void (*lv_cache_clear_cb_t)(lv_cache_t * cache, void * user_data); +typedef lv_cache_entry_t * (*lv_cache_get_victim_cb)(lv_cache_t * cache, void * user_data); +typedef lv_cache_reserve_cond_res_t (*lv_cache_reserve_cond_cb)(lv_cache_t * cache, const void * key, size_t size, + void * user_data); struct _lv_cache_ops_t { lv_cache_compare_cb_t compare_cb; @@ -62,10 +69,10 @@ struct _lv_cache_ops_t { struct _lv_cache_t { const lv_cache_class_t * clz; - size_t node_size; + uint32_t node_size; - size_t max_size; - size_t size; + uint32_t max_size; + uint32_t size; lv_cache_ops_t ops; @@ -82,6 +89,8 @@ struct _lv_cache_class_t { lv_cache_remove_cb_t remove_cb; lv_cache_drop_cb_t drop_cb; lv_cache_clear_cb_t drop_all_cb; + lv_cache_get_victim_cb get_victim_cb; + lv_cache_reserve_cond_cb reserve_cond_cb; }; /*-----------------