转载请注明出处:http://blog.csdn.net/luotuo44/article/details/42869325
LRU队列:
之前的《slab内存分配》博文已经写到:一个slab class里面的所有slab分配器只分配相同大小的item,不同的slab class分配不同大小的item。item结构体里面有一个slabs_clsid成员,用来指明自己是属于哪个slab class的。这里把slabs_clsid值相同的item称为是同一类item。
slab分配器负责分配一个item,但这个item并非直接被哈希表进行管理。从《哈希表的删除操作》可以得知,对哈希表中的某一个item进行删除只是简单地将这个item从哈希表的冲突链中删除掉,并没有把item内存归还给slab。实际上,slab分配器分配出去的item是由一个LRU队列进行管理的。当一个item从LRU队列中删除就会归还给slab分配器 。
LRU队列其实是一个双向链表。memcached里面有多条LRU队列,条数等于item的种类数。所以呢,同一类item(slabs_clsid成员变量值相等)将放到同一条LRU队列中。之所以是双向链表,是因为要方便从前后两个方向插入和遍历链表。下面浏览一下item结构体的部分成员。
typedef struct _stritem {
struct _stritem *next; //next指针,用于LRU链表
struct _stritem *prev; //prev指针,用于LRU链表
struct _stritem *h_next;//h_next指针,用于哈希表的冲突链
rel_time_t time; //最后一次访问时间。绝对时间
...
uint8_t slabs_clsid;/* which slab class we're in */
} item;
接下来阅读管理LRU队列的数据结构。其实是超级简单的,就三个全局数组而已,而且是static数组(开心吧)。
//memcached.h文件
#define POWER_LARGEST 200
//items.c文件
#define LARGEST_ID POWER_LARGEST
static item *heads[LARGEST_ID];//指向每一个LRU队列头
static item *tails[LARGEST_ID];//指向每一个LRU队列尾
static unsigned int sizes[LARGEST_ID];//每一个LRU队列有多少个item
可以看到这三个数组的大小是和slabclass提供的最大slab class个数是一样的。这样也印证了一个LRU队列就对应一类item。heads[i]指向第i类LRU链表的第一个item,tails[i]则指向了第i类LRU链表的最后一个item,sizes[i]则指明第i类LRU链表有多少个item。由LRU队列和heads和tails构成的结构如下图所示:
LRU队列的基本操作:
插入操作:
假设我们有一个item要插入到LRU链表中,那么可以通过调用item_link_q函数把item插入到LRU队列中。下面是具体的实现代码。
//将item插入到LRU队列的头部
static