LRU
LRU算法一般是用在构建缓存上的,主要目的是在于怎么将部分缓存数据给淘汰掉。
开源组件
可以使用redis的链表与字典来实现一个demo,下面列出使用的redis结构体.
双向链表
typedef struct listNode {
struct listNode *prev;
struct listNode *next;
void *value;
} listNode;
typedef struct list {
listNode *head;
listNode *tail;
void *(*dup)(void *ptr);
void (*free)(void *ptr);
int (*match)(void *ptr, void *key);
unsigned long len;
} list;
字典(Key-Val)
/* This is our hash table structure. Every dictionary has two of this as we
* implement incremental rehashing, for the old to the new table. */
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
unsigned long iterators; /* number of iterators currently running */
} dict;
LRU需要的结构体
typedef struct SIMPLE_LRU_S
{
pthread_rwlock_t stLock; /* 锁,多线程使用 */
dict stKV; /* 缓存KV,用于查找 */
list stLi; /* 链表,用来淘汰,节点数据内存与stKV相同 */
unsigned int ulMaxElemNum; /* 最大元素个数 */
}SIMPLE_LRU_S;
对此,需要解释一下:
stLock
是用在多线程上锁必须加的锁stKV
是用来缓存查找的,否则遍历速度较慢stLi
是为了淘汰链表尾部数据的ulMaxElemNum
是用来判定当前缓存最多使用的多少个数据,超过此数值,则淘汰
PlanUML
流程图
@startuml SimpleLRU
title SimpeLRU
start
:调用缓存对外接口;
' 数据是否存在以及查找可以通过stKV去处理;
' 缓存中的数据个数通过stLi的len获取;
if (数据查找 ?) then(存在)
:将数据从stLi当前位置移动到stLi的头部;
else (不存在)
if (缓存中的数据个数是否 >= ulMaxElemNum ?) then(大于)
:删除链表stLi尾部最后一个元素;
:删除stKV中此数据的Key-Val映射;
else (小于)
:ignore;
endif
:调用业务API获取读取数据;
:建立数据的Key-Val映射,放到stKV;
:将数据的引用放到stLi的首部;
endif
:返回数据;
end
@enduml
参考资料
https://www.jianshu.com/p/d533d8a66795
https://www.iteye.com/blog/flychao88-1977653