Cache为接口类。为实际的缓存操作类ShardedLRUCache提供接口。
ShardedLRUCache封装了16个LRUCache缓存片,每次对缓存的读取、插入、查找、删除操作都对应到所封装的相应缓存片LRUCache的相应方法完成。ShardedLRUCache提供了对应缓存片的方法。
LRUCache为一个循环双链表,与标准实现一致。其”头结点“lru_的prev始终指向最新节点,next始终指向最久未用节点,其对象容器为HashTable,用于为LRUCache提供快速的查找操作。
LRUHandle为节点类。其 next_hash指针用于HashTable中的bucket单向链表 。next和prev指针用于LRUCache循环双向链表的后继和前驱。
源码:
Cache接口类:
class Cache {
public:
Cache() { }
// Destroys all existing entries by calling the "deleter"
// function that was passed to the constructor.
virtual ~Cache();
struct Handle { };
//插入一个键_值到缓存,随之可能改变整个缓存的容量。返回句柄。
//当调用者不再需要<span style="font-family: Arial, Helvetica, sans-serif;">键_值</span><span style="font-family: Arial, Helvetica, sans-serif;">该时应调用Release(handle)引用计数减为0时,作为参数传入的deleter会删除该条目。</span>
virtual Handle* Insert(const Slice& key, void* value, size_t charge,
void (*deleter)(const Slice& key, void* value)) = 0;
//查找
virtual Handle* Lookup(const Slice& key) = 0;//当没有该key时,返回null
//递减引用计数
virtual void Release(Handle* handle) = 0;
<pre name="code" class="cpp">//返回其value<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
virtual void* Value(Handle* handle) = 0;
<pre name="code" class="cpp">//注意:只有当该条目的所有句柄都释放后才会真正删除该条目
virtual void Erase(const Slice& key) = 0;
//创建一个计数id,多个用户共享该缓存的关键域
virtual uint64_t NewId() = 0; private: void LRU_Remove(Handle* e); void LRU_Append(Handle* e); void Unref(Handle* e); struct Rep; Rep* rep_; // No copying allowed Cache(const Cache&); void operator=(const Cache&);};
LRUHandle节点类:
struct LRUHandle {
void* value;
void (*deleter)(const Slice&, void* value);//资源回收函数
LRUHandle* next_hash;// 用于hash table中的bucket单向链表 纵向
LRUHandle* next;//双向链表 前驱 横向
LRUHandle* prev;//双向链表 后继
size_t charge; // TODO(opt): Only allow uint32_t?
size_t key_length;//key的长度
uint32_t refs;//节点的引用计数
uint32_t hash; // Hash of key(); used for fast sharding and comparisons 即位于哪个bucket
char key_data[1]; // Beginning of key key的指针
Slice key() const {//获取key
// For cheaper lookups, we allow a temporary Handle object
// to store a pointer to a key in "value".
//对于临时节点,让其value存放其key的指针
if (next == this) {//无后继节点(临时节点)
return *(reinterpret_cast<Slice*>(value));
} else {
return Slice(key_data, key_length);
}
}
};
class HandleTable {
public:
HandleTable() : length_(0), elems_(0), list_(NULL) { Resize(); }
~HandleTable() { delete[] list_; }
//在hash的bucket中查找key的节点
LRUHandle* Lookup(const Slice& key, uint32_t hash) {
return *FindPointer(key, hash);
}
//插入节点 如果原来有则返回其节点指针,否则返回null
LRUHandle* Insert(LRUHandle* h) {
LRUHandle** ptr = FindPointer(h->key(), h->hash);
LRUHandle* old = *ptr;
h->next_hash = (old == NULL ? NULL : old->next_hash);//如果原来没有,则插入到最后,否则替换(old的前驱节点的处理??)
*ptr = h;
if (old == NULL) {
++elems_;
if (elems_ > length_) {//若总元素个数过大,则需要调整bucket的个数 length_
//每个bucket的长度<=1,即元素总数<=bucket数量
Resize();
}
}
return old;
}
//如果存在则返回其节点指针,否则返回null
LRUHandle* Remove(const Slice& key, uint32_t hash) {
LRUHandle** ptr = FindPointer(key, hash);
LRUHandle* result = *ptr;
if (result != NULL) {
*ptr = result->next_hash;
--elems_;
}
return result;
}
private:
uint32_t length_;//bucket的个数
uint32_t elems_;//总的节点数 所有bucket中的节点之和
LRUHandle** list_;//哈希指针数组
LRUHandle** FindPointer(const Slice& key, uint32_t hash) {
LRUHandle** ptr = &list_[hash & (length_ - 1)];
while (*ptr != NULL && //在对应的bucket中从上往下循环查找
((*ptr)->hash != hash || key != (*ptr)->key())) {
ptr = &(*ptr)->next_hash;
}
return ptr;
}
void Resize() {
uint32_t new_length = 4;//注意:每次调整都 翻倍增长
while (new_length < elems_) {
new_length *= 2;
}
LRUHandle** new_list = new LRUHandle*[new_length];//从新分配哈希表指针数组
memset(new_list, 0, sizeof(new_list[0]) * new_length);//每个LRUHandle*置为null
uint32_t count = 0;
for (uint32_t i = 0; i < length_; i++) {// 重新hash,一次全部执行完毕
LRUHandle* h = list_[i];
while (h != NULL) {
LRUHandle* next = h->next_hash;
Slice key = h->key();
uint32_t hash = h->hash;
LRUHandle** ptr = &new_list[hash & (new_length - 1)];//找到新哈希表的bucket
h->next_hash = *ptr; //放到新的bucket的开头
*ptr = h;
h = next;
count++;
}
}
assert(elems_ == count);
delete[] list_;//释放原来的哈希表 注意:节点的引用计数
list_ = new_list;
length_ = new_length;
}
};
//单片缓存类 <span style="font-family: Arial, Helvetica, sans-serif;">循环双向链表 对象容器为 hashtable</span>
class LRUCache {
public:
LRUCache();
~LRUCache();
<pre name="code" class="cpp">//设置容量
void SetCapacity(size_t capacity) { capacity_ = capacity; }
</pre><pre name="code" class="cpp"> //插入节点
Cache::Handle* Insert(const Slice& key, uint32_t hash,
void* value, size_t charge,
void (*deleter)(const Slice& key, void* value));
//查找节点
Cache::Handle* Lookup(const Slice& key, uint32_t hash);
<pre name="code" class="cpp">//释放引用计数
void Release(Cache::Handle* handle);
<pre name="code" class="cpp">//删除节点
void Erase(const Slice& key, uint32_t hash); private: void LRU_Remove(LRUHandle* e);//删除节点 void LRU_Append(LRUHandle* e);//插入节点到”头“之前 void Unref(LRUHandle* e);//递减引用计数 size_t capacity_;//容量 port::Mutex mutex_;//互斥访问 size_t usage_;//已用容量 uint64_t last_id_; //每次新加节点放到最前面 LRUHandle lru_;//假 头结点(循环双向链表) HandleTable table_;//对象容器};
ShardedLRUCache:
//实际对外缓存片封装类(LRUCache数组)
class ShardedLRUCache : public Cache {//Cache 接口类
private:
LRUCache shard_[kNumShards];
port::Mutex id_mutex_;
uint64_t last_id_;
//计算hash值
static inline uint32_t HashSlice(const Slice& s) {
return Hash(s.data(), s.size(), 0);
}
//映射到哪个缓存CRUCache片
static uint32_t Shard(uint32_t hash) {//hash值的高4位
return hash >> (32 - kNumShardBits);
}
public:
//构造函数
explicit ShardedLRUCache(size_t capacity)
: last_id_(0) {
const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards;//每片缓存容量
for (int s = 0; s < kNumShards; s++) {
shard_[s].SetCapacity(per_shard);
}
}
virtual ~ShardedLRUCache() { }
//插入到指定片
virtual Handle* Insert(const Slice& key, void* value, size_t charge,
void (*deleter)(const Slice& key, void* value)) {
const uint32_t hash = HashSlice(key);
return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter);
}
virtual Handle* Lookup(const Slice& key) {
const uint32_t hash = HashSlice(key);
return shard_[Shard(hash)].Lookup(key, hash);
}
//释放引用计数
virtual void Release(Handle* handle) {
LRUHandle* h = reinterpret_cast<LRUHandle*>(handle);
shard_[Shard(h->hash)].Release(handle);
}
//删除元素
virtual void Erase(const Slice& key) {
const uint32_t hash = HashSlice(key);
shard_[Shard(hash)].Erase(key, hash);
}
virtual void* Value(Handle* handle) {
return reinterpret_cast<LRUHandle*>(handle)->value;
}
//递增引用计数
virtual uint64_t NewId() {
MutexLock l(&id_mutex_);
return ++(last_id_);
}
};