1 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9 #include "leveldb/cache.h"
10 #include "port/port.h"
11 #include "util/hash.h"
12 #include "util/mutexlock.h"
21 // LRU cache implementation
23 // Cache entries have an "in_cache" boolean indicating whether the cache has a
24 // reference on the entry. The only ways that this can become false without the
25 // entry being passed to its "deleter" are via Erase(), via Insert() when
26 // an element with a duplicate key is inserted, or on destruction of the cache.
28 // The cache keeps two linked lists of items in the cache. All items in the
29 // cache are in one list or the other, and never both. Items still referenced
30 // by clients but erased from the cache are in neither list. The lists are:
31 // - in-use: contains the items currently referenced by clients, in no
32 // particular order. (This list is used for invariant checking. If we
33 // removed the check, elements that would otherwise be on this list could be
34 // left as disconnected singleton lists.)
35 // - LRU: contains the items not currently referenced by clients, in LRU order
36 // Elements are moved between these lists by the Ref() and Unref() methods,
37 // when they detect an element in the cache acquiring or losing its only
38 // external reference.
40 // An entry is a variable length heap-allocated structure. Entries
41 // are kept in a circular doubly linked list ordered by access time.
44 void (*deleter
)(const Slice
&, void* value
);
48 size_t charge
; // TODO(opt): Only allow uint32_t?
50 bool in_cache
; // Whether entry is in the cache.
51 uint32_t refs
; // References, including cache reference, if present.
52 uint32_t hash
; // Hash of key(); used for fast sharding and comparisons
53 char key_data
[1]; // Beginning of key
56 // For cheaper lookups, we allow a temporary Handle object
57 // to store a pointer to a key in "value".
59 return *(reinterpret_cast<Slice
*>(value
));
61 return Slice(key_data
, key_length
);
66 // We provide our own simple hash table since it removes a whole bunch
67 // of porting hacks and is also faster than some of the built-in hash
68 // table implementations in some of the compiler/runtime combinations
69 // we have tested. E.g., readrandom speeds up by ~5% over the g++
70 // 4.4.3's builtin hashtable.
73 HandleTable() : length_(0), elems_(0), list_(NULL
) { Resize(); }
74 ~HandleTable() { delete[] list_
; }
76 LRUHandle
* Lookup(const Slice
& key
, uint32_t hash
) {
77 return *FindPointer(key
, hash
);
80 LRUHandle
* Insert(LRUHandle
* h
) {
81 LRUHandle
** ptr
= FindPointer(h
->key(), h
->hash
);
82 LRUHandle
* old
= *ptr
;
83 h
->next_hash
= (old
== NULL
? NULL
: old
->next_hash
);
87 if (elems_
> length_
) {
88 // Since each cache entry is fairly large, we aim for a small
89 // average linked list length (<= 1).
96 LRUHandle
* Remove(const Slice
& key
, uint32_t hash
) {
97 LRUHandle
** ptr
= FindPointer(key
, hash
);
98 LRUHandle
* result
= *ptr
;
100 *ptr
= result
->next_hash
;
107 // The table consists of an array of buckets where each bucket is
108 // a linked list of cache entries that hash into the bucket.
113 // Return a pointer to slot that points to a cache entry that
114 // matches key/hash. If there is no such cache entry, return a
115 // pointer to the trailing slot in the corresponding linked list.
116 LRUHandle
** FindPointer(const Slice
& key
, uint32_t hash
) {
117 LRUHandle
** ptr
= &list_
[hash
& (length_
- 1)];
118 while (*ptr
!= NULL
&&
119 ((*ptr
)->hash
!= hash
|| key
!= (*ptr
)->key())) {
120 ptr
= &(*ptr
)->next_hash
;
126 uint32_t new_length
= 4;
127 while (new_length
< elems_
) {
130 LRUHandle
** new_list
= new LRUHandle
*[new_length
];
131 memset(new_list
, 0, sizeof(new_list
[0]) * new_length
);
133 for (uint32_t i
= 0; i
< length_
; i
++) {
134 LRUHandle
* h
= list_
[i
];
136 LRUHandle
* next
= h
->next_hash
;
137 uint32_t hash
= h
->hash
;
138 LRUHandle
** ptr
= &new_list
[hash
& (new_length
- 1)];
145 assert(elems_
== count
);
148 length_
= new_length
;
152 // A single shard of sharded cache.
158 // Separate from constructor so caller can easily make an array of LRUCache
159 void SetCapacity(size_t capacity
) { capacity_
= capacity
; }
161 // Like Cache methods, but with an extra "hash" parameter.
162 Cache::Handle
* Insert(const Slice
& key
, uint32_t hash
,
163 void* value
, size_t charge
,
164 void (*deleter
)(const Slice
& key
, void* value
));
165 Cache::Handle
* Lookup(const Slice
& key
, uint32_t hash
);
166 void Release(Cache::Handle
* handle
);
167 void Erase(const Slice
& key
, uint32_t hash
);
169 size_t TotalCharge() const {
170 MutexLock
l(&mutex_
);
175 void LRU_Remove(LRUHandle
* e
);
176 void LRU_Append(LRUHandle
*list
, LRUHandle
* e
);
177 void Ref(LRUHandle
* e
);
178 void Unref(LRUHandle
* e
);
179 bool FinishErase(LRUHandle
* e
);
181 // Initialized before use.
184 // mutex_ protects the following state.
185 mutable port::Mutex mutex_
;
188 // Dummy head of LRU list.
189 // lru.prev is newest entry, lru.next is oldest entry.
190 // Entries have refs==1 and in_cache==true.
193 // Dummy head of in-use list.
194 // Entries are in use by clients, and have refs >= 2 and in_cache==true.
202 // Make empty circular linked lists.
205 in_use_
.next
= &in_use_
;
206 in_use_
.prev
= &in_use_
;
209 LRUCache::~LRUCache() {
210 assert(in_use_
.next
== &in_use_
); // Error if caller has an unreleased handle
211 for (LRUHandle
* e
= lru_
.next
; e
!= &lru_
; ) {
212 LRUHandle
* next
= e
->next
;
215 assert(e
->refs
== 1); // Invariant of lru_ list.
221 void LRUCache::Ref(LRUHandle
* e
) {
222 if (e
->refs
== 1 && e
->in_cache
) { // If on lru_ list, move to in_use_ list.
224 LRU_Append(&in_use_
, e
);
229 void LRUCache::Unref(LRUHandle
* e
) {
232 if (e
->refs
== 0) { // Deallocate.
233 assert(!e
->in_cache
);
234 (*e
->deleter
)(e
->key(), e
->value
);
236 } else if (e
->in_cache
&& e
->refs
== 1) { // No longer in use; move to lru_ list.
238 LRU_Append(&lru_
, e
);
242 void LRUCache::LRU_Remove(LRUHandle
* e
) {
243 e
->next
->prev
= e
->prev
;
244 e
->prev
->next
= e
->next
;
247 void LRUCache::LRU_Append(LRUHandle
* list
, LRUHandle
* e
) {
248 // Make "e" newest entry by inserting just before *list
250 e
->prev
= list
->prev
;
255 Cache::Handle
* LRUCache::Lookup(const Slice
& key
, uint32_t hash
) {
256 MutexLock
l(&mutex_
);
257 LRUHandle
* e
= table_
.Lookup(key
, hash
);
261 return reinterpret_cast<Cache::Handle
*>(e
);
264 void LRUCache::Release(Cache::Handle
* handle
) {
265 MutexLock
l(&mutex_
);
266 Unref(reinterpret_cast<LRUHandle
*>(handle
));
269 Cache::Handle
* LRUCache::Insert(
270 const Slice
& key
, uint32_t hash
, void* value
, size_t charge
,
271 void (*deleter
)(const Slice
& key
, void* value
)) {
272 MutexLock
l(&mutex_
);
274 LRUHandle
* e
= reinterpret_cast<LRUHandle
*>(
275 malloc(sizeof(LRUHandle
)-1 + key
.size()));
277 e
->deleter
= deleter
;
279 e
->key_length
= key
.size();
282 e
->refs
= 1; // for the returned handle.
283 memcpy(e
->key_data
, key
.data(), key
.size());
286 e
->refs
++; // for the cache's reference.
288 LRU_Append(&in_use_
, e
);
290 FinishErase(table_
.Insert(e
));
291 } // else don't cache. (Tests use capacity_==0 to turn off caching.)
293 while (usage_
> capacity_
&& lru_
.next
!= &lru_
) {
294 LRUHandle
* old
= lru_
.next
;
295 assert(old
->refs
== 1);
296 bool erased
= FinishErase(table_
.Remove(old
->key(), old
->hash
));
297 if (!erased
) { // to avoid unused variable when compiled NDEBUG
302 return reinterpret_cast<Cache::Handle
*>(e
);
305 // If e != NULL, finish removing *e from the cache; it has already been removed
306 // from the hash table. Return whether e != NULL. Requires mutex_ held.
307 bool LRUCache::FinishErase(LRUHandle
* e
) {
318 void LRUCache::Erase(const Slice
& key
, uint32_t hash
) {
319 MutexLock
l(&mutex_
);
320 FinishErase(table_
.Remove(key
, hash
));
323 void LRUCache::Prune() {
324 MutexLock
l(&mutex_
);
325 while (lru_
.next
!= &lru_
) {
326 LRUHandle
* e
= lru_
.next
;
327 assert(e
->refs
== 1);
328 bool erased
= FinishErase(table_
.Remove(e
->key(), e
->hash
));
329 if (!erased
) { // to avoid unused variable when compiled NDEBUG
335 static const int kNumShardBits
= 4;
336 static const int kNumShards
= 1 << kNumShardBits
;
338 class ShardedLRUCache
: public Cache
{
340 LRUCache shard_
[kNumShards
];
341 port::Mutex id_mutex_
;
344 static inline uint32_t HashSlice(const Slice
& s
) {
345 return Hash(s
.data(), s
.size(), 0);
348 static uint32_t Shard(uint32_t hash
) {
349 return hash
>> (32 - kNumShardBits
);
353 explicit ShardedLRUCache(size_t capacity
)
355 const size_t per_shard
= (capacity
+ (kNumShards
- 1)) / kNumShards
;
356 for (int s
= 0; s
< kNumShards
; s
++) {
357 shard_
[s
].SetCapacity(per_shard
);
360 virtual ~ShardedLRUCache() { }
361 virtual Handle
* Insert(const Slice
& key
, void* value
, size_t charge
,
362 void (*deleter
)(const Slice
& key
, void* value
)) {
363 const uint32_t hash
= HashSlice(key
);
364 return shard_
[Shard(hash
)].Insert(key
, hash
, value
, charge
, deleter
);
366 virtual Handle
* Lookup(const Slice
& key
) {
367 const uint32_t hash
= HashSlice(key
);
368 return shard_
[Shard(hash
)].Lookup(key
, hash
);
370 virtual void Release(Handle
* handle
) {
371 LRUHandle
* h
= reinterpret_cast<LRUHandle
*>(handle
);
372 shard_
[Shard(h
->hash
)].Release(handle
);
374 virtual void Erase(const Slice
& key
) {
375 const uint32_t hash
= HashSlice(key
);
376 shard_
[Shard(hash
)].Erase(key
, hash
);
378 virtual void* Value(Handle
* handle
) {
379 return reinterpret_cast<LRUHandle
*>(handle
)->value
;
381 virtual uint64_t NewId() {
382 MutexLock
l(&id_mutex_
);
385 virtual void Prune() {
386 for (int s
= 0; s
< kNumShards
; s
++) {
390 virtual size_t TotalCharge() const {
392 for (int s
= 0; s
< kNumShards
; s
++) {
393 total
+= shard_
[s
].TotalCharge();
399 } // end anonymous namespace
401 Cache
* NewLRUCache(size_t capacity
) {
402 return new ShardedLRUCache(capacity
);
405 } // namespace leveldb