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 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_cb(lv_cache_t * cache, const void * key, void * user_data);
|
||||||
static void drop_all_cb(lv_cache_t * cache, 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);
|
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);
|
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,
|
.add_cb = add_cb,
|
||||||
.remove_cb = remove_cb,
|
.remove_cb = remove_cb,
|
||||||
.drop_cb = drop_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 = {
|
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,
|
.add_cb = add_cb,
|
||||||
.remove_cb = remove_cb,
|
.remove_cb = remove_cb,
|
||||||
.drop_cb = drop_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
|
* STATIC VARIABLES
|
||||||
@@ -259,34 +266,6 @@ static lv_cache_entry_t * add_cb(lv_cache_t * cache, const void * key, void * us
|
|||||||
return NULL;
|
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);
|
lv_rb_node_t * new_node = alloc_new_node(lru, (void *)key, user_data);
|
||||||
if(new_node == NULL) {
|
if(new_node == NULL) {
|
||||||
return 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);
|
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;
|
return entry;
|
||||||
}
|
}
|
||||||
@@ -391,6 +370,50 @@ static void drop_all_cb(lv_cache_t * cache, void * user_data)
|
|||||||
cache->size = 0;
|
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)
|
static uint32_t cnt_get_data_size_cb(const void * data)
|
||||||
{
|
{
|
||||||
LV_UNUSED(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 PROTOTYPES
|
||||||
**********************/
|
**********************/
|
||||||
static void cache_drop_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data);
|
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
|
* 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_ASSERT_NULL(key);
|
||||||
|
|
||||||
lv_mutex_lock(&cache->lock);
|
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) {
|
if(entry != NULL) {
|
||||||
lv_cache_entry_acquire_data(entry);
|
lv_cache_entry_acquire_data(entry);
|
||||||
}
|
}
|
||||||
lv_mutex_unlock(&cache->lock);
|
lv_mutex_unlock(&cache->lock);
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
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_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);
|
lv_mutex_unlock(&cache->lock);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
entry = cache->clz->add_cb(cache, key, user_data);
|
entry = cache_add_internal_no_lock(cache, key, user_data);
|
||||||
if(entry == NULL) {
|
if(entry == NULL) {
|
||||||
lv_mutex_unlock(&cache->lock);
|
lv_mutex_unlock(&cache->lock);
|
||||||
return NULL;
|
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);
|
lv_mutex_unlock(&cache->lock);
|
||||||
return entry;
|
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)
|
void lv_cache_drop(lv_cache_t * cache, const void * key, void * user_data)
|
||||||
{
|
{
|
||||||
LV_ASSERT_NULL(cache);
|
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);
|
cache_drop_internal_no_lock(cache, key, user_data);
|
||||||
lv_mutex_unlock(&cache->lock);
|
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)
|
void lv_cache_drop_all(lv_cache_t * cache, void * user_data)
|
||||||
{
|
{
|
||||||
LV_ASSERT_NULL(cache);
|
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);
|
LV_UNUSED(user_data);
|
||||||
cache->ops.free_cb = free_cb;
|
cache->ops.free_cb = free_cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* STATIC FUNCTIONS
|
* STATIC FUNCTIONS
|
||||||
**********************/
|
**********************/
|
||||||
|
|
||||||
static void cache_drop_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data)
|
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);
|
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);
|
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_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);
|
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_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(lv_cache_t * cache, const void * key, void * user_data);
|
||||||
void lv_cache_drop_all(lv_cache_t * cache, 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_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_size(lv_cache_t * cache, void * user_data);
|
||||||
size_t lv_cache_get_free_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
|
* TYPEDEFS
|
||||||
**********************/
|
**********************/
|
||||||
|
|
||||||
/*-----------------
|
typedef enum {
|
||||||
* Cache entry slot
|
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_ops_t;
|
||||||
struct _lv_cache_t;
|
struct _lv_cache_t;
|
||||||
struct _lv_cache_class_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_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_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 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 {
|
struct _lv_cache_ops_t {
|
||||||
lv_cache_compare_cb_t compare_cb;
|
lv_cache_compare_cb_t compare_cb;
|
||||||
@@ -62,10 +69,10 @@ struct _lv_cache_ops_t {
|
|||||||
struct _lv_cache_t {
|
struct _lv_cache_t {
|
||||||
const lv_cache_class_t * clz;
|
const lv_cache_class_t * clz;
|
||||||
|
|
||||||
size_t node_size;
|
uint32_t node_size;
|
||||||
|
|
||||||
size_t max_size;
|
uint32_t max_size;
|
||||||
size_t size;
|
uint32_t size;
|
||||||
|
|
||||||
lv_cache_ops_t ops;
|
lv_cache_ops_t ops;
|
||||||
|
|
||||||
@@ -82,6 +89,8 @@ struct _lv_cache_class_t {
|
|||||||
lv_cache_remove_cb_t remove_cb;
|
lv_cache_remove_cb_t remove_cb;
|
||||||
lv_cache_drop_cb_t drop_cb;
|
lv_cache_drop_cb_t drop_cb;
|
||||||
lv_cache_clear_cb_t drop_all_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