1*9507f98cSAndroid Build Coastguard Worker // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2*9507f98cSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*9507f98cSAndroid Build Coastguard Worker // found in the LICENSE file. See the AUTHORS file for names of contributors.
4*9507f98cSAndroid Build Coastguard Worker
5*9507f98cSAndroid Build Coastguard Worker #include "leveldb/cache.h"
6*9507f98cSAndroid Build Coastguard Worker
7*9507f98cSAndroid Build Coastguard Worker #include <cassert>
8*9507f98cSAndroid Build Coastguard Worker #include <cstdio>
9*9507f98cSAndroid Build Coastguard Worker #include <cstdlib>
10*9507f98cSAndroid Build Coastguard Worker
11*9507f98cSAndroid Build Coastguard Worker #include "port/port.h"
12*9507f98cSAndroid Build Coastguard Worker #include "port/thread_annotations.h"
13*9507f98cSAndroid Build Coastguard Worker #include "util/hash.h"
14*9507f98cSAndroid Build Coastguard Worker #include "util/mutexlock.h"
15*9507f98cSAndroid Build Coastguard Worker
16*9507f98cSAndroid Build Coastguard Worker namespace leveldb {
17*9507f98cSAndroid Build Coastguard Worker
~Cache()18*9507f98cSAndroid Build Coastguard Worker Cache::~Cache() {}
19*9507f98cSAndroid Build Coastguard Worker
20*9507f98cSAndroid Build Coastguard Worker namespace {
21*9507f98cSAndroid Build Coastguard Worker
22*9507f98cSAndroid Build Coastguard Worker // LRU cache implementation
23*9507f98cSAndroid Build Coastguard Worker //
24*9507f98cSAndroid Build Coastguard Worker // Cache entries have an "in_cache" boolean indicating whether the cache has a
25*9507f98cSAndroid Build Coastguard Worker // reference on the entry. The only ways that this can become false without the
26*9507f98cSAndroid Build Coastguard Worker // entry being passed to its "deleter" are via Erase(), via Insert() when
27*9507f98cSAndroid Build Coastguard Worker // an element with a duplicate key is inserted, or on destruction of the cache.
28*9507f98cSAndroid Build Coastguard Worker //
29*9507f98cSAndroid Build Coastguard Worker // The cache keeps two linked lists of items in the cache. All items in the
30*9507f98cSAndroid Build Coastguard Worker // cache are in one list or the other, and never both. Items still referenced
31*9507f98cSAndroid Build Coastguard Worker // by clients but erased from the cache are in neither list. The lists are:
32*9507f98cSAndroid Build Coastguard Worker // - in-use: contains the items currently referenced by clients, in no
33*9507f98cSAndroid Build Coastguard Worker // particular order. (This list is used for invariant checking. If we
34*9507f98cSAndroid Build Coastguard Worker // removed the check, elements that would otherwise be on this list could be
35*9507f98cSAndroid Build Coastguard Worker // left as disconnected singleton lists.)
36*9507f98cSAndroid Build Coastguard Worker // - LRU: contains the items not currently referenced by clients, in LRU order
37*9507f98cSAndroid Build Coastguard Worker // Elements are moved between these lists by the Ref() and Unref() methods,
38*9507f98cSAndroid Build Coastguard Worker // when they detect an element in the cache acquiring or losing its only
39*9507f98cSAndroid Build Coastguard Worker // external reference.
40*9507f98cSAndroid Build Coastguard Worker
41*9507f98cSAndroid Build Coastguard Worker // An entry is a variable length heap-allocated structure. Entries
42*9507f98cSAndroid Build Coastguard Worker // are kept in a circular doubly linked list ordered by access time.
43*9507f98cSAndroid Build Coastguard Worker struct LRUHandle {
44*9507f98cSAndroid Build Coastguard Worker void* value;
45*9507f98cSAndroid Build Coastguard Worker void (*deleter)(const Slice&, void* value);
46*9507f98cSAndroid Build Coastguard Worker LRUHandle* next_hash;
47*9507f98cSAndroid Build Coastguard Worker LRUHandle* next;
48*9507f98cSAndroid Build Coastguard Worker LRUHandle* prev;
49*9507f98cSAndroid Build Coastguard Worker size_t charge; // TODO(opt): Only allow uint32_t?
50*9507f98cSAndroid Build Coastguard Worker size_t key_length;
51*9507f98cSAndroid Build Coastguard Worker bool in_cache; // Whether entry is in the cache.
52*9507f98cSAndroid Build Coastguard Worker uint32_t refs; // References, including cache reference, if present.
53*9507f98cSAndroid Build Coastguard Worker uint32_t hash; // Hash of key(); used for fast sharding and comparisons
54*9507f98cSAndroid Build Coastguard Worker char key_data[1]; // Beginning of key
55*9507f98cSAndroid Build Coastguard Worker
keyleveldb::__anon852f22290111::LRUHandle56*9507f98cSAndroid Build Coastguard Worker Slice key() const {
57*9507f98cSAndroid Build Coastguard Worker // next_ is only equal to this if the LRU handle is the list head of an
58*9507f98cSAndroid Build Coastguard Worker // empty list. List heads never have meaningful keys.
59*9507f98cSAndroid Build Coastguard Worker assert(next != this);
60*9507f98cSAndroid Build Coastguard Worker
61*9507f98cSAndroid Build Coastguard Worker return Slice(key_data, key_length);
62*9507f98cSAndroid Build Coastguard Worker }
63*9507f98cSAndroid Build Coastguard Worker };
64*9507f98cSAndroid Build Coastguard Worker
65*9507f98cSAndroid Build Coastguard Worker // We provide our own simple hash table since it removes a whole bunch
66*9507f98cSAndroid Build Coastguard Worker // of porting hacks and is also faster than some of the built-in hash
67*9507f98cSAndroid Build Coastguard Worker // table implementations in some of the compiler/runtime combinations
68*9507f98cSAndroid Build Coastguard Worker // we have tested. E.g., readrandom speeds up by ~5% over the g++
69*9507f98cSAndroid Build Coastguard Worker // 4.4.3's builtin hashtable.
70*9507f98cSAndroid Build Coastguard Worker class HandleTable {
71*9507f98cSAndroid Build Coastguard Worker public:
HandleTable()72*9507f98cSAndroid Build Coastguard Worker HandleTable() : length_(0), elems_(0), list_(nullptr) { Resize(); }
~HandleTable()73*9507f98cSAndroid Build Coastguard Worker ~HandleTable() { delete[] list_; }
74*9507f98cSAndroid Build Coastguard Worker
Lookup(const Slice & key,uint32_t hash)75*9507f98cSAndroid Build Coastguard Worker LRUHandle* Lookup(const Slice& key, uint32_t hash) {
76*9507f98cSAndroid Build Coastguard Worker return *FindPointer(key, hash);
77*9507f98cSAndroid Build Coastguard Worker }
78*9507f98cSAndroid Build Coastguard Worker
Insert(LRUHandle * h)79*9507f98cSAndroid Build Coastguard Worker LRUHandle* Insert(LRUHandle* h) {
80*9507f98cSAndroid Build Coastguard Worker LRUHandle** ptr = FindPointer(h->key(), h->hash);
81*9507f98cSAndroid Build Coastguard Worker LRUHandle* old = *ptr;
82*9507f98cSAndroid Build Coastguard Worker h->next_hash = (old == nullptr ? nullptr : old->next_hash);
83*9507f98cSAndroid Build Coastguard Worker *ptr = h;
84*9507f98cSAndroid Build Coastguard Worker if (old == nullptr) {
85*9507f98cSAndroid Build Coastguard Worker ++elems_;
86*9507f98cSAndroid Build Coastguard Worker if (elems_ > length_) {
87*9507f98cSAndroid Build Coastguard Worker // Since each cache entry is fairly large, we aim for a small
88*9507f98cSAndroid Build Coastguard Worker // average linked list length (<= 1).
89*9507f98cSAndroid Build Coastguard Worker Resize();
90*9507f98cSAndroid Build Coastguard Worker }
91*9507f98cSAndroid Build Coastguard Worker }
92*9507f98cSAndroid Build Coastguard Worker return old;
93*9507f98cSAndroid Build Coastguard Worker }
94*9507f98cSAndroid Build Coastguard Worker
Remove(const Slice & key,uint32_t hash)95*9507f98cSAndroid Build Coastguard Worker LRUHandle* Remove(const Slice& key, uint32_t hash) {
96*9507f98cSAndroid Build Coastguard Worker LRUHandle** ptr = FindPointer(key, hash);
97*9507f98cSAndroid Build Coastguard Worker LRUHandle* result = *ptr;
98*9507f98cSAndroid Build Coastguard Worker if (result != nullptr) {
99*9507f98cSAndroid Build Coastguard Worker *ptr = result->next_hash;
100*9507f98cSAndroid Build Coastguard Worker --elems_;
101*9507f98cSAndroid Build Coastguard Worker }
102*9507f98cSAndroid Build Coastguard Worker return result;
103*9507f98cSAndroid Build Coastguard Worker }
104*9507f98cSAndroid Build Coastguard Worker
105*9507f98cSAndroid Build Coastguard Worker private:
106*9507f98cSAndroid Build Coastguard Worker // The table consists of an array of buckets where each bucket is
107*9507f98cSAndroid Build Coastguard Worker // a linked list of cache entries that hash into the bucket.
108*9507f98cSAndroid Build Coastguard Worker uint32_t length_;
109*9507f98cSAndroid Build Coastguard Worker uint32_t elems_;
110*9507f98cSAndroid Build Coastguard Worker LRUHandle** list_;
111*9507f98cSAndroid Build Coastguard Worker
112*9507f98cSAndroid Build Coastguard Worker // Return a pointer to slot that points to a cache entry that
113*9507f98cSAndroid Build Coastguard Worker // matches key/hash. If there is no such cache entry, return a
114*9507f98cSAndroid Build Coastguard Worker // pointer to the trailing slot in the corresponding linked list.
FindPointer(const Slice & key,uint32_t hash)115*9507f98cSAndroid Build Coastguard Worker LRUHandle** FindPointer(const Slice& key, uint32_t hash) {
116*9507f98cSAndroid Build Coastguard Worker LRUHandle** ptr = &list_[hash & (length_ - 1)];
117*9507f98cSAndroid Build Coastguard Worker while (*ptr != nullptr && ((*ptr)->hash != hash || key != (*ptr)->key())) {
118*9507f98cSAndroid Build Coastguard Worker ptr = &(*ptr)->next_hash;
119*9507f98cSAndroid Build Coastguard Worker }
120*9507f98cSAndroid Build Coastguard Worker return ptr;
121*9507f98cSAndroid Build Coastguard Worker }
122*9507f98cSAndroid Build Coastguard Worker
Resize()123*9507f98cSAndroid Build Coastguard Worker void Resize() {
124*9507f98cSAndroid Build Coastguard Worker uint32_t new_length = 4;
125*9507f98cSAndroid Build Coastguard Worker while (new_length < elems_) {
126*9507f98cSAndroid Build Coastguard Worker new_length *= 2;
127*9507f98cSAndroid Build Coastguard Worker }
128*9507f98cSAndroid Build Coastguard Worker LRUHandle** new_list = new LRUHandle*[new_length];
129*9507f98cSAndroid Build Coastguard Worker memset(new_list, 0, sizeof(new_list[0]) * new_length);
130*9507f98cSAndroid Build Coastguard Worker uint32_t count = 0;
131*9507f98cSAndroid Build Coastguard Worker for (uint32_t i = 0; i < length_; i++) {
132*9507f98cSAndroid Build Coastguard Worker LRUHandle* h = list_[i];
133*9507f98cSAndroid Build Coastguard Worker while (h != nullptr) {
134*9507f98cSAndroid Build Coastguard Worker LRUHandle* next = h->next_hash;
135*9507f98cSAndroid Build Coastguard Worker uint32_t hash = h->hash;
136*9507f98cSAndroid Build Coastguard Worker LRUHandle** ptr = &new_list[hash & (new_length - 1)];
137*9507f98cSAndroid Build Coastguard Worker h->next_hash = *ptr;
138*9507f98cSAndroid Build Coastguard Worker *ptr = h;
139*9507f98cSAndroid Build Coastguard Worker h = next;
140*9507f98cSAndroid Build Coastguard Worker count++;
141*9507f98cSAndroid Build Coastguard Worker }
142*9507f98cSAndroid Build Coastguard Worker }
143*9507f98cSAndroid Build Coastguard Worker assert(elems_ == count);
144*9507f98cSAndroid Build Coastguard Worker delete[] list_;
145*9507f98cSAndroid Build Coastguard Worker list_ = new_list;
146*9507f98cSAndroid Build Coastguard Worker length_ = new_length;
147*9507f98cSAndroid Build Coastguard Worker }
148*9507f98cSAndroid Build Coastguard Worker };
149*9507f98cSAndroid Build Coastguard Worker
150*9507f98cSAndroid Build Coastguard Worker // A single shard of sharded cache.
151*9507f98cSAndroid Build Coastguard Worker class LRUCache {
152*9507f98cSAndroid Build Coastguard Worker public:
153*9507f98cSAndroid Build Coastguard Worker LRUCache();
154*9507f98cSAndroid Build Coastguard Worker ~LRUCache();
155*9507f98cSAndroid Build Coastguard Worker
156*9507f98cSAndroid Build Coastguard Worker // Separate from constructor so caller can easily make an array of LRUCache
SetCapacity(size_t capacity)157*9507f98cSAndroid Build Coastguard Worker void SetCapacity(size_t capacity) { capacity_ = capacity; }
158*9507f98cSAndroid Build Coastguard Worker
159*9507f98cSAndroid Build Coastguard Worker // Like Cache methods, but with an extra "hash" parameter.
160*9507f98cSAndroid Build Coastguard Worker Cache::Handle* Insert(const Slice& key, uint32_t hash, void* value,
161*9507f98cSAndroid Build Coastguard Worker size_t charge,
162*9507f98cSAndroid Build Coastguard Worker void (*deleter)(const Slice& key, void* value));
163*9507f98cSAndroid Build Coastguard Worker Cache::Handle* Lookup(const Slice& key, uint32_t hash);
164*9507f98cSAndroid Build Coastguard Worker void Release(Cache::Handle* handle);
165*9507f98cSAndroid Build Coastguard Worker void Erase(const Slice& key, uint32_t hash);
166*9507f98cSAndroid Build Coastguard Worker void Prune();
TotalCharge() const167*9507f98cSAndroid Build Coastguard Worker size_t TotalCharge() const {
168*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
169*9507f98cSAndroid Build Coastguard Worker return usage_;
170*9507f98cSAndroid Build Coastguard Worker }
171*9507f98cSAndroid Build Coastguard Worker
172*9507f98cSAndroid Build Coastguard Worker private:
173*9507f98cSAndroid Build Coastguard Worker void LRU_Remove(LRUHandle* e);
174*9507f98cSAndroid Build Coastguard Worker void LRU_Append(LRUHandle* list, LRUHandle* e);
175*9507f98cSAndroid Build Coastguard Worker void Ref(LRUHandle* e);
176*9507f98cSAndroid Build Coastguard Worker void Unref(LRUHandle* e);
177*9507f98cSAndroid Build Coastguard Worker bool FinishErase(LRUHandle* e) EXCLUSIVE_LOCKS_REQUIRED(mutex_);
178*9507f98cSAndroid Build Coastguard Worker
179*9507f98cSAndroid Build Coastguard Worker // Initialized before use.
180*9507f98cSAndroid Build Coastguard Worker size_t capacity_;
181*9507f98cSAndroid Build Coastguard Worker
182*9507f98cSAndroid Build Coastguard Worker // mutex_ protects the following state.
183*9507f98cSAndroid Build Coastguard Worker mutable port::Mutex mutex_;
184*9507f98cSAndroid Build Coastguard Worker size_t usage_ GUARDED_BY(mutex_);
185*9507f98cSAndroid Build Coastguard Worker
186*9507f98cSAndroid Build Coastguard Worker // Dummy head of LRU list.
187*9507f98cSAndroid Build Coastguard Worker // lru.prev is newest entry, lru.next is oldest entry.
188*9507f98cSAndroid Build Coastguard Worker // Entries have refs==1 and in_cache==true.
189*9507f98cSAndroid Build Coastguard Worker LRUHandle lru_ GUARDED_BY(mutex_);
190*9507f98cSAndroid Build Coastguard Worker
191*9507f98cSAndroid Build Coastguard Worker // Dummy head of in-use list.
192*9507f98cSAndroid Build Coastguard Worker // Entries are in use by clients, and have refs >= 2 and in_cache==true.
193*9507f98cSAndroid Build Coastguard Worker LRUHandle in_use_ GUARDED_BY(mutex_);
194*9507f98cSAndroid Build Coastguard Worker
195*9507f98cSAndroid Build Coastguard Worker HandleTable table_ GUARDED_BY(mutex_);
196*9507f98cSAndroid Build Coastguard Worker };
197*9507f98cSAndroid Build Coastguard Worker
LRUCache()198*9507f98cSAndroid Build Coastguard Worker LRUCache::LRUCache() : capacity_(0), usage_(0) {
199*9507f98cSAndroid Build Coastguard Worker // Make empty circular linked lists.
200*9507f98cSAndroid Build Coastguard Worker lru_.next = &lru_;
201*9507f98cSAndroid Build Coastguard Worker lru_.prev = &lru_;
202*9507f98cSAndroid Build Coastguard Worker in_use_.next = &in_use_;
203*9507f98cSAndroid Build Coastguard Worker in_use_.prev = &in_use_;
204*9507f98cSAndroid Build Coastguard Worker }
205*9507f98cSAndroid Build Coastguard Worker
~LRUCache()206*9507f98cSAndroid Build Coastguard Worker LRUCache::~LRUCache() {
207*9507f98cSAndroid Build Coastguard Worker assert(in_use_.next == &in_use_); // Error if caller has an unreleased handle
208*9507f98cSAndroid Build Coastguard Worker for (LRUHandle* e = lru_.next; e != &lru_;) {
209*9507f98cSAndroid Build Coastguard Worker LRUHandle* next = e->next;
210*9507f98cSAndroid Build Coastguard Worker assert(e->in_cache);
211*9507f98cSAndroid Build Coastguard Worker e->in_cache = false;
212*9507f98cSAndroid Build Coastguard Worker assert(e->refs == 1); // Invariant of lru_ list.
213*9507f98cSAndroid Build Coastguard Worker Unref(e);
214*9507f98cSAndroid Build Coastguard Worker e = next;
215*9507f98cSAndroid Build Coastguard Worker }
216*9507f98cSAndroid Build Coastguard Worker }
217*9507f98cSAndroid Build Coastguard Worker
Ref(LRUHandle * e)218*9507f98cSAndroid Build Coastguard Worker void LRUCache::Ref(LRUHandle* e) {
219*9507f98cSAndroid Build Coastguard Worker if (e->refs == 1 && e->in_cache) { // If on lru_ list, move to in_use_ list.
220*9507f98cSAndroid Build Coastguard Worker LRU_Remove(e);
221*9507f98cSAndroid Build Coastguard Worker LRU_Append(&in_use_, e);
222*9507f98cSAndroid Build Coastguard Worker }
223*9507f98cSAndroid Build Coastguard Worker e->refs++;
224*9507f98cSAndroid Build Coastguard Worker }
225*9507f98cSAndroid Build Coastguard Worker
Unref(LRUHandle * e)226*9507f98cSAndroid Build Coastguard Worker void LRUCache::Unref(LRUHandle* e) {
227*9507f98cSAndroid Build Coastguard Worker assert(e->refs > 0);
228*9507f98cSAndroid Build Coastguard Worker e->refs--;
229*9507f98cSAndroid Build Coastguard Worker if (e->refs == 0) { // Deallocate.
230*9507f98cSAndroid Build Coastguard Worker assert(!e->in_cache);
231*9507f98cSAndroid Build Coastguard Worker (*e->deleter)(e->key(), e->value);
232*9507f98cSAndroid Build Coastguard Worker free(e);
233*9507f98cSAndroid Build Coastguard Worker } else if (e->in_cache && e->refs == 1) {
234*9507f98cSAndroid Build Coastguard Worker // No longer in use; move to lru_ list.
235*9507f98cSAndroid Build Coastguard Worker LRU_Remove(e);
236*9507f98cSAndroid Build Coastguard Worker LRU_Append(&lru_, e);
237*9507f98cSAndroid Build Coastguard Worker }
238*9507f98cSAndroid Build Coastguard Worker }
239*9507f98cSAndroid Build Coastguard Worker
LRU_Remove(LRUHandle * e)240*9507f98cSAndroid Build Coastguard Worker void LRUCache::LRU_Remove(LRUHandle* e) {
241*9507f98cSAndroid Build Coastguard Worker e->next->prev = e->prev;
242*9507f98cSAndroid Build Coastguard Worker e->prev->next = e->next;
243*9507f98cSAndroid Build Coastguard Worker }
244*9507f98cSAndroid Build Coastguard Worker
LRU_Append(LRUHandle * list,LRUHandle * e)245*9507f98cSAndroid Build Coastguard Worker void LRUCache::LRU_Append(LRUHandle* list, LRUHandle* e) {
246*9507f98cSAndroid Build Coastguard Worker // Make "e" newest entry by inserting just before *list
247*9507f98cSAndroid Build Coastguard Worker e->next = list;
248*9507f98cSAndroid Build Coastguard Worker e->prev = list->prev;
249*9507f98cSAndroid Build Coastguard Worker e->prev->next = e;
250*9507f98cSAndroid Build Coastguard Worker e->next->prev = e;
251*9507f98cSAndroid Build Coastguard Worker }
252*9507f98cSAndroid Build Coastguard Worker
Lookup(const Slice & key,uint32_t hash)253*9507f98cSAndroid Build Coastguard Worker Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) {
254*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
255*9507f98cSAndroid Build Coastguard Worker LRUHandle* e = table_.Lookup(key, hash);
256*9507f98cSAndroid Build Coastguard Worker if (e != nullptr) {
257*9507f98cSAndroid Build Coastguard Worker Ref(e);
258*9507f98cSAndroid Build Coastguard Worker }
259*9507f98cSAndroid Build Coastguard Worker return reinterpret_cast<Cache::Handle*>(e);
260*9507f98cSAndroid Build Coastguard Worker }
261*9507f98cSAndroid Build Coastguard Worker
Release(Cache::Handle * handle)262*9507f98cSAndroid Build Coastguard Worker void LRUCache::Release(Cache::Handle* handle) {
263*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
264*9507f98cSAndroid Build Coastguard Worker Unref(reinterpret_cast<LRUHandle*>(handle));
265*9507f98cSAndroid Build Coastguard Worker }
266*9507f98cSAndroid Build Coastguard Worker
Insert(const Slice & key,uint32_t hash,void * value,size_t charge,void (* deleter)(const Slice & key,void * value))267*9507f98cSAndroid Build Coastguard Worker Cache::Handle* LRUCache::Insert(const Slice& key, uint32_t hash, void* value,
268*9507f98cSAndroid Build Coastguard Worker size_t charge,
269*9507f98cSAndroid Build Coastguard Worker void (*deleter)(const Slice& key,
270*9507f98cSAndroid Build Coastguard Worker void* value)) {
271*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
272*9507f98cSAndroid Build Coastguard Worker
273*9507f98cSAndroid Build Coastguard Worker LRUHandle* e =
274*9507f98cSAndroid Build Coastguard Worker reinterpret_cast<LRUHandle*>(malloc(sizeof(LRUHandle) - 1 + key.size()));
275*9507f98cSAndroid Build Coastguard Worker e->value = value;
276*9507f98cSAndroid Build Coastguard Worker e->deleter = deleter;
277*9507f98cSAndroid Build Coastguard Worker e->charge = charge;
278*9507f98cSAndroid Build Coastguard Worker e->key_length = key.size();
279*9507f98cSAndroid Build Coastguard Worker e->hash = hash;
280*9507f98cSAndroid Build Coastguard Worker e->in_cache = false;
281*9507f98cSAndroid Build Coastguard Worker e->refs = 1; // for the returned handle.
282*9507f98cSAndroid Build Coastguard Worker std::memcpy(e->key_data, key.data(), key.size());
283*9507f98cSAndroid Build Coastguard Worker
284*9507f98cSAndroid Build Coastguard Worker if (capacity_ > 0) {
285*9507f98cSAndroid Build Coastguard Worker e->refs++; // for the cache's reference.
286*9507f98cSAndroid Build Coastguard Worker e->in_cache = true;
287*9507f98cSAndroid Build Coastguard Worker LRU_Append(&in_use_, e);
288*9507f98cSAndroid Build Coastguard Worker usage_ += charge;
289*9507f98cSAndroid Build Coastguard Worker FinishErase(table_.Insert(e));
290*9507f98cSAndroid Build Coastguard Worker } else { // don't cache. (capacity_==0 is supported and turns off caching.)
291*9507f98cSAndroid Build Coastguard Worker // next is read by key() in an assert, so it must be initialized
292*9507f98cSAndroid Build Coastguard Worker e->next = nullptr;
293*9507f98cSAndroid Build Coastguard Worker }
294*9507f98cSAndroid Build Coastguard Worker while (usage_ > capacity_ && lru_.next != &lru_) {
295*9507f98cSAndroid Build Coastguard Worker LRUHandle* old = lru_.next;
296*9507f98cSAndroid Build Coastguard Worker assert(old->refs == 1);
297*9507f98cSAndroid Build Coastguard Worker bool erased = FinishErase(table_.Remove(old->key(), old->hash));
298*9507f98cSAndroid Build Coastguard Worker if (!erased) { // to avoid unused variable when compiled NDEBUG
299*9507f98cSAndroid Build Coastguard Worker assert(erased);
300*9507f98cSAndroid Build Coastguard Worker }
301*9507f98cSAndroid Build Coastguard Worker }
302*9507f98cSAndroid Build Coastguard Worker
303*9507f98cSAndroid Build Coastguard Worker return reinterpret_cast<Cache::Handle*>(e);
304*9507f98cSAndroid Build Coastguard Worker }
305*9507f98cSAndroid Build Coastguard Worker
306*9507f98cSAndroid Build Coastguard Worker // If e != nullptr, finish removing *e from the cache; it has already been
307*9507f98cSAndroid Build Coastguard Worker // removed from the hash table. Return whether e != nullptr.
FinishErase(LRUHandle * e)308*9507f98cSAndroid Build Coastguard Worker bool LRUCache::FinishErase(LRUHandle* e) {
309*9507f98cSAndroid Build Coastguard Worker if (e != nullptr) {
310*9507f98cSAndroid Build Coastguard Worker assert(e->in_cache);
311*9507f98cSAndroid Build Coastguard Worker LRU_Remove(e);
312*9507f98cSAndroid Build Coastguard Worker e->in_cache = false;
313*9507f98cSAndroid Build Coastguard Worker usage_ -= e->charge;
314*9507f98cSAndroid Build Coastguard Worker Unref(e);
315*9507f98cSAndroid Build Coastguard Worker }
316*9507f98cSAndroid Build Coastguard Worker return e != nullptr;
317*9507f98cSAndroid Build Coastguard Worker }
318*9507f98cSAndroid Build Coastguard Worker
Erase(const Slice & key,uint32_t hash)319*9507f98cSAndroid Build Coastguard Worker void LRUCache::Erase(const Slice& key, uint32_t hash) {
320*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
321*9507f98cSAndroid Build Coastguard Worker FinishErase(table_.Remove(key, hash));
322*9507f98cSAndroid Build Coastguard Worker }
323*9507f98cSAndroid Build Coastguard Worker
Prune()324*9507f98cSAndroid Build Coastguard Worker void LRUCache::Prune() {
325*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
326*9507f98cSAndroid Build Coastguard Worker while (lru_.next != &lru_) {
327*9507f98cSAndroid Build Coastguard Worker LRUHandle* e = lru_.next;
328*9507f98cSAndroid Build Coastguard Worker assert(e->refs == 1);
329*9507f98cSAndroid Build Coastguard Worker bool erased = FinishErase(table_.Remove(e->key(), e->hash));
330*9507f98cSAndroid Build Coastguard Worker if (!erased) { // to avoid unused variable when compiled NDEBUG
331*9507f98cSAndroid Build Coastguard Worker assert(erased);
332*9507f98cSAndroid Build Coastguard Worker }
333*9507f98cSAndroid Build Coastguard Worker }
334*9507f98cSAndroid Build Coastguard Worker }
335*9507f98cSAndroid Build Coastguard Worker
336*9507f98cSAndroid Build Coastguard Worker static const int kNumShardBits = 4;
337*9507f98cSAndroid Build Coastguard Worker static const int kNumShards = 1 << kNumShardBits;
338*9507f98cSAndroid Build Coastguard Worker
339*9507f98cSAndroid Build Coastguard Worker class ShardedLRUCache : public Cache {
340*9507f98cSAndroid Build Coastguard Worker private:
341*9507f98cSAndroid Build Coastguard Worker LRUCache shard_[kNumShards];
342*9507f98cSAndroid Build Coastguard Worker port::Mutex id_mutex_;
343*9507f98cSAndroid Build Coastguard Worker uint64_t last_id_;
344*9507f98cSAndroid Build Coastguard Worker
HashSlice(const Slice & s)345*9507f98cSAndroid Build Coastguard Worker static inline uint32_t HashSlice(const Slice& s) {
346*9507f98cSAndroid Build Coastguard Worker return Hash(s.data(), s.size(), 0);
347*9507f98cSAndroid Build Coastguard Worker }
348*9507f98cSAndroid Build Coastguard Worker
Shard(uint32_t hash)349*9507f98cSAndroid Build Coastguard Worker static uint32_t Shard(uint32_t hash) { return hash >> (32 - kNumShardBits); }
350*9507f98cSAndroid Build Coastguard Worker
351*9507f98cSAndroid Build Coastguard Worker public:
ShardedLRUCache(size_t capacity)352*9507f98cSAndroid Build Coastguard Worker explicit ShardedLRUCache(size_t capacity) : last_id_(0) {
353*9507f98cSAndroid Build Coastguard Worker const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards;
354*9507f98cSAndroid Build Coastguard Worker for (int s = 0; s < kNumShards; s++) {
355*9507f98cSAndroid Build Coastguard Worker shard_[s].SetCapacity(per_shard);
356*9507f98cSAndroid Build Coastguard Worker }
357*9507f98cSAndroid Build Coastguard Worker }
~ShardedLRUCache()358*9507f98cSAndroid Build Coastguard Worker ~ShardedLRUCache() override {}
Insert(const Slice & key,void * value,size_t charge,void (* deleter)(const Slice & key,void * value))359*9507f98cSAndroid Build Coastguard Worker Handle* Insert(const Slice& key, void* value, size_t charge,
360*9507f98cSAndroid Build Coastguard Worker void (*deleter)(const Slice& key, void* value)) override {
361*9507f98cSAndroid Build Coastguard Worker const uint32_t hash = HashSlice(key);
362*9507f98cSAndroid Build Coastguard Worker return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter);
363*9507f98cSAndroid Build Coastguard Worker }
Lookup(const Slice & key)364*9507f98cSAndroid Build Coastguard Worker Handle* Lookup(const Slice& key) override {
365*9507f98cSAndroid Build Coastguard Worker const uint32_t hash = HashSlice(key);
366*9507f98cSAndroid Build Coastguard Worker return shard_[Shard(hash)].Lookup(key, hash);
367*9507f98cSAndroid Build Coastguard Worker }
Release(Handle * handle)368*9507f98cSAndroid Build Coastguard Worker void Release(Handle* handle) override {
369*9507f98cSAndroid Build Coastguard Worker LRUHandle* h = reinterpret_cast<LRUHandle*>(handle);
370*9507f98cSAndroid Build Coastguard Worker shard_[Shard(h->hash)].Release(handle);
371*9507f98cSAndroid Build Coastguard Worker }
Erase(const Slice & key)372*9507f98cSAndroid Build Coastguard Worker void Erase(const Slice& key) override {
373*9507f98cSAndroid Build Coastguard Worker const uint32_t hash = HashSlice(key);
374*9507f98cSAndroid Build Coastguard Worker shard_[Shard(hash)].Erase(key, hash);
375*9507f98cSAndroid Build Coastguard Worker }
Value(Handle * handle)376*9507f98cSAndroid Build Coastguard Worker void* Value(Handle* handle) override {
377*9507f98cSAndroid Build Coastguard Worker return reinterpret_cast<LRUHandle*>(handle)->value;
378*9507f98cSAndroid Build Coastguard Worker }
NewId()379*9507f98cSAndroid Build Coastguard Worker uint64_t NewId() override {
380*9507f98cSAndroid Build Coastguard Worker MutexLock l(&id_mutex_);
381*9507f98cSAndroid Build Coastguard Worker return ++(last_id_);
382*9507f98cSAndroid Build Coastguard Worker }
Prune()383*9507f98cSAndroid Build Coastguard Worker void Prune() override {
384*9507f98cSAndroid Build Coastguard Worker for (int s = 0; s < kNumShards; s++) {
385*9507f98cSAndroid Build Coastguard Worker shard_[s].Prune();
386*9507f98cSAndroid Build Coastguard Worker }
387*9507f98cSAndroid Build Coastguard Worker }
TotalCharge() const388*9507f98cSAndroid Build Coastguard Worker size_t TotalCharge() const override {
389*9507f98cSAndroid Build Coastguard Worker size_t total = 0;
390*9507f98cSAndroid Build Coastguard Worker for (int s = 0; s < kNumShards; s++) {
391*9507f98cSAndroid Build Coastguard Worker total += shard_[s].TotalCharge();
392*9507f98cSAndroid Build Coastguard Worker }
393*9507f98cSAndroid Build Coastguard Worker return total;
394*9507f98cSAndroid Build Coastguard Worker }
395*9507f98cSAndroid Build Coastguard Worker };
396*9507f98cSAndroid Build Coastguard Worker
397*9507f98cSAndroid Build Coastguard Worker } // end anonymous namespace
398*9507f98cSAndroid Build Coastguard Worker
NewLRUCache(size_t capacity)399*9507f98cSAndroid Build Coastguard Worker Cache* NewLRUCache(size_t capacity) { return new ShardedLRUCache(capacity); }
400*9507f98cSAndroid Build Coastguard Worker
401*9507f98cSAndroid Build Coastguard Worker } // namespace leveldb
402