feat(cache): refactor cache framework and add new APIs (#5501)
This commit is contained in:
85
src/misc/cache/_lv_cache_lru_rb.c
vendored
85
src/misc/cache/_lv_cache_lru_rb.c
vendored
@@ -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);
|
||||
|
||||
61
src/misc/cache/lv_cache.c
vendored
61
src/misc/cache/lv_cache.c
vendored
@@ -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;
|
||||
}
|
||||
|
||||
4
src/misc/cache/lv_cache.h
vendored
4
src/misc/cache/lv_cache.h
vendored
@@ -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);
|
||||
|
||||
21
src/misc/cache/lv_cache_private.h
vendored
21
src/misc/cache/lv_cache_private.h
vendored
@@ -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;
|
||||
};
|
||||
|
||||
/*-----------------
|
||||
|
||||
Reference in New Issue
Block a user