feat(cache): refactor cache framework and add new APIs (#5501)

This commit is contained in:
Benign X
2024-01-29 20:44:56 +08:00
committed by GitHub
parent 4f9c16f177
commit f4267177e6
4 changed files with 131 additions and 40 deletions

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
};
/*-----------------