mirror of
https://github.com/emqx/neuron.git
synced 2026-10-21 16:55:53 +08:00
177 lines
3.7 KiB
C
177 lines
3.7 KiB
C
#include <assert.h>
|
|
|
|
#include <neuron.h>
|
|
|
|
#include "utils/mem_cache.h"
|
|
|
|
typedef struct element {
|
|
cache_item_t item;
|
|
struct element *prev;
|
|
struct element *next;
|
|
} element;
|
|
|
|
struct neu_mem_cache {
|
|
size_t max_bytes; // 0 no limit
|
|
size_t max_items; // 0 no limit
|
|
size_t used_bytes;
|
|
size_t used_items;
|
|
element *head;
|
|
};
|
|
|
|
neu_mem_cache_t *neu_mem_cache_create(const size_t max_bytes,
|
|
const size_t max_items)
|
|
{
|
|
neu_mem_cache_t *cache = calloc(1, sizeof(neu_mem_cache_t));
|
|
if (NULL == cache) {
|
|
return NULL;
|
|
}
|
|
|
|
cache->max_bytes = max_bytes;
|
|
cache->max_items = max_items;
|
|
cache->used_bytes = 0;
|
|
cache->used_items = 0;
|
|
cache->head = NULL;
|
|
return cache;
|
|
}
|
|
|
|
cache_item_t neu_mem_cache_earliest(neu_mem_cache_t *cache);
|
|
|
|
static bool queue_is_full(neu_mem_cache_t *cache, cache_item_t *item)
|
|
{
|
|
if ((0 != cache->max_bytes) &&
|
|
(item->size + cache->used_bytes) > cache->max_bytes) {
|
|
return true;
|
|
}
|
|
|
|
if ((0 != cache->max_items) && (cache->used_items >= cache->max_items)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int neu_mem_cache_add(neu_mem_cache_t *cache, cache_item_t *item)
|
|
{
|
|
assert(NULL != cache);
|
|
assert(NULL != item);
|
|
|
|
while (queue_is_full(cache, item)) {
|
|
cache_item_t remove_item = neu_mem_cache_earliest(cache);
|
|
if (NULL == remove_item.data) {
|
|
// size(item.data) > cache->max_bytes
|
|
return -1;
|
|
}
|
|
|
|
if (NULL != remove_item.release && NULL != remove_item.data) {
|
|
remove_item.release(remove_item.data);
|
|
}
|
|
}
|
|
|
|
element *el = calloc(1, sizeof(element));
|
|
if (NULL == el) {
|
|
return -1;
|
|
}
|
|
|
|
el->item = *item;
|
|
DL_PREPEND(cache->head, el);
|
|
|
|
cache->used_bytes += item->size;
|
|
cache->used_items += 1;
|
|
return 0;
|
|
}
|
|
|
|
cache_item_t neu_mem_cache_earliest(neu_mem_cache_t *cache)
|
|
{
|
|
assert(NULL != cache);
|
|
|
|
cache_item_t item = { 0 };
|
|
element * elm = DL_LAST(cache->head);
|
|
if (NULL == elm) {
|
|
return item;
|
|
}
|
|
|
|
item = elm->item;
|
|
DL_DELETE(cache->head, elm);
|
|
free(elm);
|
|
|
|
cache->used_bytes -= item.size;
|
|
cache->used_items -= 1;
|
|
return item;
|
|
}
|
|
|
|
cache_item_t neu_mem_cache_latest(neu_mem_cache_t *cache)
|
|
{
|
|
assert(NULL != cache);
|
|
|
|
cache_item_t item = { 0 };
|
|
element * elm = cache->head;
|
|
if (NULL == elm) {
|
|
return item;
|
|
}
|
|
|
|
item = elm->item;
|
|
DL_DELETE(cache->head, elm);
|
|
free(elm);
|
|
|
|
cache->used_bytes -= item.size;
|
|
cache->used_items -= 1;
|
|
return item;
|
|
}
|
|
|
|
void neu_mem_cache_used(neu_mem_cache_t *cache, size_t *bytes, size_t *msgs)
|
|
{
|
|
assert(NULL != cache);
|
|
|
|
*bytes = cache->used_bytes;
|
|
*msgs = cache->used_items;
|
|
}
|
|
|
|
int neu_mem_cache_dump(neu_mem_cache_t *cache, cache_dump callback, void *ctx)
|
|
{
|
|
assert(NULL != cache);
|
|
|
|
if (NULL != callback) {
|
|
element *el = NULL;
|
|
element *tmp = NULL;
|
|
DL_FOREACH_SAFE(cache->head, el, tmp)
|
|
{
|
|
callback(&el->item, ctx);
|
|
|
|
if (NULL != el->item.release) {
|
|
el->item.release(&el->item);
|
|
}
|
|
|
|
LL_DELETE(cache->head, el);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int neu_mem_cache_clear(neu_mem_cache_t *cache)
|
|
{
|
|
assert(NULL != cache);
|
|
|
|
element *el = NULL;
|
|
element *tmp = NULL;
|
|
DL_FOREACH_SAFE(cache->head, el, tmp)
|
|
{
|
|
if (NULL != el->item.release && NULL != el->item.data) {
|
|
el->item.release(el->item.data);
|
|
}
|
|
|
|
LL_DELETE(cache->head, el);
|
|
free(el);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void neu_mem_cache_destroy(neu_mem_cache_t *cache)
|
|
{
|
|
assert(NULL != cache);
|
|
|
|
neu_mem_cache_clear(cache);
|
|
free(cache);
|
|
}
|