structLRUHandle { void* value; void (*deleter)(const Slice&, void* value); LRUHandle* next_hash; LRUHandle* next; LRUHandle* prev; size_t charge; // TODO(opt): Only allow uint32_t? size_t key_length; bool in_cache; // Whether entry is in the cache. uint32_t refs; // References, including cache reference, if present. uint32_t hash; // Hash of key(); used for fast sharding(分片) and comparisons char key_data[1]; // Beginning of key
Slice key()const{ // next_ is only equal to this if the LRU handle is the list head of an // empty list. List heads never have meaningful keys. assert(next != this);
classHandleTable { public: // ... private: // The table consists of an array of buckets where each bucket is // a linked list of cache entries that hash into the bucket. uint32_t length_; // bucket数量 uint32_t elems_; // 节点数量 LRUHandle** list_; // 保存指针的数组,数组大小是length_ }
length_是桶的大小,就是list_数组的大小,初始化为4,后面按2倍扩容
elems_节点数量,当节点数量>length_的时候,开始扩容,resize函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// 如果没有冲突,Insert后返回空 // 如果冲突,覆盖冲突节点(hash表key不能重复) LRUHandle* Insert(LRUHandle* h){ LRUHandle** ptr = FindPointer(h->key(), h->hash); LRUHandle* old = *ptr; h->next_hash = (old == nullptr ? nullptr : old->next_hash); *ptr = h; if (old == nullptr) { ++elems_; if (elems_ > length_) { // Since each cache entry is fairly large, we aim for a small // average linked list length (<= 1). // 扩容的时机比较特殊,没有按装载因子算,元素个数大于桶的大小就扩容了, 链表不会太长 Resize(); } } return old; }
// Initialized before use. // 容量 size_t capacity_;
// mutex_ protects the following state. mutable port::Mutex mutex_; // 使用量 size_t usage_ GUARDED_BY(mutex_);
// Dummy head of LRU list. // lru.prev is newest entry, lru.next is oldest entry. // Entries have refs==1 and in_cache==true. // lru头结点,头结点是dummy不保存外部数据 // refs==1在lru_链表,>1在in_use链表,1代表cache本身的引用,client每使用一次会+1 LRUHandle lru_ GUARDED_BY(mutex_);
// Dummy head of in-use list. // Entries are in use by clients, and have refs >= 2 and in_cache==true. // in_use头结点,被client使用的在in_use_链表,其他的在lru_链表 LRUHandle in_use_ GUARDED_BY(mutex_);
HandleTable table_ GUARDED_BY(mutex_); };
引用计数>1放在in_use_链表,=1放在lru_,=0就开始释放资源了。
1 2 3 4 5 6 7 8 9 10 11 12
voidLRUCache::LRU_Append(LRUHandle* list, LRUHandle* e){ // Make "e" newest entry by inserting just before *list e->next = list; e->prev = list->prev; e->prev->next = e; e->next->prev = e; }