xref: /aosp_15_r20/external/leveldb/util/cache.cc (revision 9507f98c5f32dee4b5f9e4a38cd499f3ff5c4490)
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