filiptepper-leveldb-ruby 0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/LICENSE +24 -0
  2. data/README +72 -0
  3. data/ext/leveldb/extconf.rb +14 -0
  4. data/ext/leveldb/leveldb.cc +530 -0
  5. data/ext/leveldb/platform.rb +83 -0
  6. data/leveldb/Makefile +191 -0
  7. data/leveldb/build_detect_platform +160 -0
  8. data/leveldb/db/builder.cc +88 -0
  9. data/leveldb/db/builder.h +34 -0
  10. data/leveldb/db/c.cc +581 -0
  11. data/leveldb/db/corruption_test.cc +359 -0
  12. data/leveldb/db/db_bench.cc +970 -0
  13. data/leveldb/db/db_impl.cc +1448 -0
  14. data/leveldb/db/db_impl.h +194 -0
  15. data/leveldb/db/db_iter.cc +299 -0
  16. data/leveldb/db/db_iter.h +26 -0
  17. data/leveldb/db/db_test.cc +1901 -0
  18. data/leveldb/db/dbformat.cc +140 -0
  19. data/leveldb/db/dbformat.h +227 -0
  20. data/leveldb/db/dbformat_test.cc +112 -0
  21. data/leveldb/db/filename.cc +139 -0
  22. data/leveldb/db/filename.h +80 -0
  23. data/leveldb/db/filename_test.cc +122 -0
  24. data/leveldb/db/log_format.h +35 -0
  25. data/leveldb/db/log_reader.cc +259 -0
  26. data/leveldb/db/log_reader.h +108 -0
  27. data/leveldb/db/log_test.cc +500 -0
  28. data/leveldb/db/log_writer.cc +103 -0
  29. data/leveldb/db/log_writer.h +48 -0
  30. data/leveldb/db/memtable.cc +145 -0
  31. data/leveldb/db/memtable.h +91 -0
  32. data/leveldb/db/repair.cc +389 -0
  33. data/leveldb/db/skiplist.h +379 -0
  34. data/leveldb/db/skiplist_test.cc +378 -0
  35. data/leveldb/db/snapshot.h +66 -0
  36. data/leveldb/db/table_cache.cc +121 -0
  37. data/leveldb/db/table_cache.h +61 -0
  38. data/leveldb/db/version_edit.cc +266 -0
  39. data/leveldb/db/version_edit.h +107 -0
  40. data/leveldb/db/version_edit_test.cc +46 -0
  41. data/leveldb/db/version_set.cc +1402 -0
  42. data/leveldb/db/version_set.h +370 -0
  43. data/leveldb/db/version_set_test.cc +179 -0
  44. data/leveldb/db/write_batch.cc +147 -0
  45. data/leveldb/db/write_batch_internal.h +49 -0
  46. data/leveldb/db/write_batch_test.cc +120 -0
  47. data/leveldb/helpers/memenv/memenv.cc +374 -0
  48. data/leveldb/helpers/memenv/memenv.h +20 -0
  49. data/leveldb/helpers/memenv/memenv_test.cc +232 -0
  50. data/leveldb/include/leveldb/c.h +275 -0
  51. data/leveldb/include/leveldb/cache.h +99 -0
  52. data/leveldb/include/leveldb/comparator.h +63 -0
  53. data/leveldb/include/leveldb/db.h +161 -0
  54. data/leveldb/include/leveldb/env.h +323 -0
  55. data/leveldb/include/leveldb/filter_policy.h +70 -0
  56. data/leveldb/include/leveldb/iterator.h +100 -0
  57. data/leveldb/include/leveldb/options.h +195 -0
  58. data/leveldb/include/leveldb/slice.h +109 -0
  59. data/leveldb/include/leveldb/status.h +106 -0
  60. data/leveldb/include/leveldb/table.h +85 -0
  61. data/leveldb/include/leveldb/table_builder.h +92 -0
  62. data/leveldb/include/leveldb/write_batch.h +64 -0
  63. data/leveldb/port/atomic_pointer.h +144 -0
  64. data/leveldb/port/port.h +21 -0
  65. data/leveldb/port/port_android.cc +64 -0
  66. data/leveldb/port/port_android.h +159 -0
  67. data/leveldb/port/port_example.h +125 -0
  68. data/leveldb/port/port_posix.cc +50 -0
  69. data/leveldb/port/port_posix.h +129 -0
  70. data/leveldb/port/win/stdint.h +24 -0
  71. data/leveldb/table/block.cc +267 -0
  72. data/leveldb/table/block.h +44 -0
  73. data/leveldb/table/block_builder.cc +109 -0
  74. data/leveldb/table/block_builder.h +57 -0
  75. data/leveldb/table/filter_block.cc +111 -0
  76. data/leveldb/table/filter_block.h +68 -0
  77. data/leveldb/table/filter_block_test.cc +128 -0
  78. data/leveldb/table/format.cc +145 -0
  79. data/leveldb/table/format.h +108 -0
  80. data/leveldb/table/iterator.cc +67 -0
  81. data/leveldb/table/iterator_wrapper.h +63 -0
  82. data/leveldb/table/merger.cc +197 -0
  83. data/leveldb/table/merger.h +26 -0
  84. data/leveldb/table/table.cc +276 -0
  85. data/leveldb/table/table_builder.cc +270 -0
  86. data/leveldb/table/table_test.cc +838 -0
  87. data/leveldb/table/two_level_iterator.cc +182 -0
  88. data/leveldb/table/two_level_iterator.h +34 -0
  89. data/leveldb/util/arena.cc +68 -0
  90. data/leveldb/util/arena.h +68 -0
  91. data/leveldb/util/arena_test.cc +68 -0
  92. data/leveldb/util/bloom.cc +95 -0
  93. data/leveldb/util/bloom_test.cc +159 -0
  94. data/leveldb/util/cache.cc +328 -0
  95. data/leveldb/util/cache_test.cc +186 -0
  96. data/leveldb/util/coding.cc +194 -0
  97. data/leveldb/util/coding.h +104 -0
  98. data/leveldb/util/coding_test.cc +173 -0
  99. data/leveldb/util/comparator.cc +76 -0
  100. data/leveldb/util/crc32c.cc +332 -0
  101. data/leveldb/util/crc32c.h +45 -0
  102. data/leveldb/util/crc32c_test.cc +72 -0
  103. data/leveldb/util/env.cc +96 -0
  104. data/leveldb/util/env_posix.cc +609 -0
  105. data/leveldb/util/env_test.cc +104 -0
  106. data/leveldb/util/filter_policy.cc +11 -0
  107. data/leveldb/util/hash.cc +45 -0
  108. data/leveldb/util/hash.h +19 -0
  109. data/leveldb/util/histogram.cc +139 -0
  110. data/leveldb/util/histogram.h +42 -0
  111. data/leveldb/util/logging.cc +81 -0
  112. data/leveldb/util/logging.h +47 -0
  113. data/leveldb/util/mutexlock.h +39 -0
  114. data/leveldb/util/options.cc +29 -0
  115. data/leveldb/util/posix_logger.h +98 -0
  116. data/leveldb/util/random.h +59 -0
  117. data/leveldb/util/status.cc +75 -0
  118. data/leveldb/util/testharness.cc +77 -0
  119. data/leveldb/util/testharness.h +138 -0
  120. data/leveldb/util/testutil.cc +51 -0
  121. data/leveldb/util/testutil.h +53 -0
  122. data/lib/leveldb.rb +76 -0
  123. metadata +175 -0
@@ -0,0 +1,159 @@
1
+ // Copyright (c) 2012 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.
4
+
5
+ #include "leveldb/filter_policy.h"
6
+
7
+ #include "util/logging.h"
8
+ #include "util/testharness.h"
9
+ #include "util/testutil.h"
10
+
11
+ namespace leveldb {
12
+
13
+ static const int kVerbose = 1;
14
+
15
+ static Slice Key(int i, char* buffer) {
16
+ memcpy(buffer, &i, sizeof(i));
17
+ return Slice(buffer, sizeof(i));
18
+ }
19
+
20
+ class BloomTest {
21
+ private:
22
+ const FilterPolicy* policy_;
23
+ std::string filter_;
24
+ std::vector<std::string> keys_;
25
+
26
+ public:
27
+ BloomTest() : policy_(NewBloomFilterPolicy(10)) { }
28
+
29
+ ~BloomTest() {
30
+ delete policy_;
31
+ }
32
+
33
+ void Reset() {
34
+ keys_.clear();
35
+ filter_.clear();
36
+ }
37
+
38
+ void Add(const Slice& s) {
39
+ keys_.push_back(s.ToString());
40
+ }
41
+
42
+ void Build() {
43
+ std::vector<Slice> key_slices;
44
+ for (size_t i = 0; i < keys_.size(); i++) {
45
+ key_slices.push_back(Slice(keys_[i]));
46
+ }
47
+ filter_.clear();
48
+ policy_->CreateFilter(&key_slices[0], key_slices.size(), &filter_);
49
+ keys_.clear();
50
+ if (kVerbose >= 2) DumpFilter();
51
+ }
52
+
53
+ size_t FilterSize() const {
54
+ return filter_.size();
55
+ }
56
+
57
+ void DumpFilter() {
58
+ fprintf(stderr, "F(");
59
+ for (size_t i = 0; i+1 < filter_.size(); i++) {
60
+ const unsigned int c = static_cast<unsigned int>(filter_[i]);
61
+ for (int j = 0; j < 8; j++) {
62
+ fprintf(stderr, "%c", (c & (1 <<j)) ? '1' : '.');
63
+ }
64
+ }
65
+ fprintf(stderr, ")\n");
66
+ }
67
+
68
+ bool Matches(const Slice& s) {
69
+ if (!keys_.empty()) {
70
+ Build();
71
+ }
72
+ return policy_->KeyMayMatch(s, filter_);
73
+ }
74
+
75
+ double FalsePositiveRate() {
76
+ char buffer[sizeof(int)];
77
+ int result = 0;
78
+ for (int i = 0; i < 10000; i++) {
79
+ if (Matches(Key(i + 1000000000, buffer))) {
80
+ result++;
81
+ }
82
+ }
83
+ return result / 10000.0;
84
+ }
85
+ };
86
+
87
+ TEST(BloomTest, EmptyFilter) {
88
+ ASSERT_TRUE(! Matches("hello"));
89
+ ASSERT_TRUE(! Matches("world"));
90
+ }
91
+
92
+ TEST(BloomTest, Small) {
93
+ Add("hello");
94
+ Add("world");
95
+ ASSERT_TRUE(Matches("hello"));
96
+ ASSERT_TRUE(Matches("world"));
97
+ ASSERT_TRUE(! Matches("x"));
98
+ ASSERT_TRUE(! Matches("foo"));
99
+ }
100
+
101
+ static int NextLength(int length) {
102
+ if (length < 10) {
103
+ length += 1;
104
+ } else if (length < 100) {
105
+ length += 10;
106
+ } else if (length < 1000) {
107
+ length += 100;
108
+ } else {
109
+ length += 1000;
110
+ }
111
+ return length;
112
+ }
113
+
114
+ TEST(BloomTest, VaryingLengths) {
115
+ char buffer[sizeof(int)];
116
+
117
+ // Count number of filters that significantly exceed the false positive rate
118
+ int mediocre_filters = 0;
119
+ int good_filters = 0;
120
+
121
+ for (int length = 1; length <= 10000; length = NextLength(length)) {
122
+ Reset();
123
+ for (int i = 0; i < length; i++) {
124
+ Add(Key(i, buffer));
125
+ }
126
+ Build();
127
+
128
+ ASSERT_LE(FilterSize(), (length * 10 / 8) + 40) << length;
129
+
130
+ // All added keys must match
131
+ for (int i = 0; i < length; i++) {
132
+ ASSERT_TRUE(Matches(Key(i, buffer)))
133
+ << "Length " << length << "; key " << i;
134
+ }
135
+
136
+ // Check false positive rate
137
+ double rate = FalsePositiveRate();
138
+ if (kVerbose >= 1) {
139
+ fprintf(stderr, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n",
140
+ rate*100.0, length, static_cast<int>(FilterSize()));
141
+ }
142
+ ASSERT_LE(rate, 0.02); // Must not be over 2%
143
+ if (rate > 0.0125) mediocre_filters++; // Allowed, but not too often
144
+ else good_filters++;
145
+ }
146
+ if (kVerbose >= 1) {
147
+ fprintf(stderr, "Filters: %d good, %d mediocre\n",
148
+ good_filters, mediocre_filters);
149
+ }
150
+ ASSERT_LE(mediocre_filters, good_filters/5);
151
+ }
152
+
153
+ // Different bits-per-byte
154
+
155
+ } // namespace leveldb
156
+
157
+ int main(int argc, char** argv) {
158
+ return leveldb::test::RunAllTests();
159
+ }
@@ -0,0 +1,328 @@
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.
4
+
5
+ #include <assert.h>
6
+ #include <stdio.h>
7
+ #include <stdlib.h>
8
+
9
+ #include "leveldb/cache.h"
10
+ #include "port/port.h"
11
+ #include "util/hash.h"
12
+ #include "util/mutexlock.h"
13
+
14
+ namespace leveldb {
15
+
16
+ Cache::~Cache() {
17
+ }
18
+
19
+ namespace {
20
+
21
+ // LRU cache implementation
22
+
23
+ // An entry is a variable length heap-allocated structure. Entries
24
+ // are kept in a circular doubly linked list ordered by access time.
25
+ struct LRUHandle {
26
+ void* value;
27
+ void (*deleter)(const Slice&, void* value);
28
+ LRUHandle* next_hash;
29
+ LRUHandle* next;
30
+ LRUHandle* prev;
31
+ size_t charge; // TODO(opt): Only allow uint32_t?
32
+ size_t key_length;
33
+ uint32_t refs;
34
+ uint32_t hash; // Hash of key(); used for fast sharding and comparisons
35
+ char key_data[1]; // Beginning of key
36
+
37
+ Slice key() const {
38
+ // For cheaper lookups, we allow a temporary Handle object
39
+ // to store a pointer to a key in "value".
40
+ if (next == this) {
41
+ return *(reinterpret_cast<Slice*>(value));
42
+ } else {
43
+ return Slice(key_data, key_length);
44
+ }
45
+ }
46
+ };
47
+
48
+ // We provide our own simple hash table since it removes a whole bunch
49
+ // of porting hacks and is also faster than some of the built-in hash
50
+ // table implementations in some of the compiler/runtime combinations
51
+ // we have tested. E.g., readrandom speeds up by ~5% over the g++
52
+ // 4.4.3's builtin hashtable.
53
+ class HandleTable {
54
+ public:
55
+ HandleTable() : length_(0), elems_(0), list_(NULL) { Resize(); }
56
+ ~HandleTable() { delete[] list_; }
57
+
58
+ LRUHandle* Lookup(const Slice& key, uint32_t hash) {
59
+ return *FindPointer(key, hash);
60
+ }
61
+
62
+ LRUHandle* Insert(LRUHandle* h) {
63
+ LRUHandle** ptr = FindPointer(h->key(), h->hash);
64
+ LRUHandle* old = *ptr;
65
+ h->next_hash = (old == NULL ? NULL : old->next_hash);
66
+ *ptr = h;
67
+ if (old == NULL) {
68
+ ++elems_;
69
+ if (elems_ > length_) {
70
+ // Since each cache entry is fairly large, we aim for a small
71
+ // average linked list length (<= 1).
72
+ Resize();
73
+ }
74
+ }
75
+ return old;
76
+ }
77
+
78
+ LRUHandle* Remove(const Slice& key, uint32_t hash) {
79
+ LRUHandle** ptr = FindPointer(key, hash);
80
+ LRUHandle* result = *ptr;
81
+ if (result != NULL) {
82
+ *ptr = result->next_hash;
83
+ --elems_;
84
+ }
85
+ return result;
86
+ }
87
+
88
+ private:
89
+ // The table consists of an array of buckets where each bucket is
90
+ // a linked list of cache entries that hash into the bucket.
91
+ uint32_t length_;
92
+ uint32_t elems_;
93
+ LRUHandle** list_;
94
+
95
+ // Return a pointer to slot that points to a cache entry that
96
+ // matches key/hash. If there is no such cache entry, return a
97
+ // pointer to the trailing slot in the corresponding linked list.
98
+ LRUHandle** FindPointer(const Slice& key, uint32_t hash) {
99
+ LRUHandle** ptr = &list_[hash & (length_ - 1)];
100
+ while (*ptr != NULL &&
101
+ ((*ptr)->hash != hash || key != (*ptr)->key())) {
102
+ ptr = &(*ptr)->next_hash;
103
+ }
104
+ return ptr;
105
+ }
106
+
107
+ void Resize() {
108
+ uint32_t new_length = 4;
109
+ while (new_length < elems_) {
110
+ new_length *= 2;
111
+ }
112
+ LRUHandle** new_list = new LRUHandle*[new_length];
113
+ memset(new_list, 0, sizeof(new_list[0]) * new_length);
114
+ uint32_t count = 0;
115
+ for (uint32_t i = 0; i < length_; i++) {
116
+ LRUHandle* h = list_[i];
117
+ while (h != NULL) {
118
+ LRUHandle* next = h->next_hash;
119
+ Slice key = h->key();
120
+ uint32_t hash = h->hash;
121
+ LRUHandle** ptr = &new_list[hash & (new_length - 1)];
122
+ h->next_hash = *ptr;
123
+ *ptr = h;
124
+ h = next;
125
+ count++;
126
+ }
127
+ }
128
+ assert(elems_ == count);
129
+ delete[] list_;
130
+ list_ = new_list;
131
+ length_ = new_length;
132
+ }
133
+ };
134
+
135
+ // A single shard of sharded cache.
136
+ class LRUCache {
137
+ public:
138
+ LRUCache();
139
+ ~LRUCache();
140
+
141
+ // Separate from constructor so caller can easily make an array of LRUCache
142
+ void SetCapacity(size_t capacity) { capacity_ = capacity; }
143
+
144
+ // Like Cache methods, but with an extra "hash" parameter.
145
+ Cache::Handle* Insert(const Slice& key, uint32_t hash,
146
+ void* value, size_t charge,
147
+ void (*deleter)(const Slice& key, void* value));
148
+ Cache::Handle* Lookup(const Slice& key, uint32_t hash);
149
+ void Release(Cache::Handle* handle);
150
+ void Erase(const Slice& key, uint32_t hash);
151
+
152
+ private:
153
+ void LRU_Remove(LRUHandle* e);
154
+ void LRU_Append(LRUHandle* e);
155
+ void Unref(LRUHandle* e);
156
+
157
+ // Initialized before use.
158
+ size_t capacity_;
159
+
160
+ // mutex_ protects the following state.
161
+ port::Mutex mutex_;
162
+ size_t usage_;
163
+ uint64_t last_id_;
164
+
165
+ // Dummy head of LRU list.
166
+ // lru.prev is newest entry, lru.next is oldest entry.
167
+ LRUHandle lru_;
168
+
169
+ HandleTable table_;
170
+ };
171
+
172
+ LRUCache::LRUCache()
173
+ : usage_(0),
174
+ last_id_(0) {
175
+ // Make empty circular linked list
176
+ lru_.next = &lru_;
177
+ lru_.prev = &lru_;
178
+ }
179
+
180
+ LRUCache::~LRUCache() {
181
+ for (LRUHandle* e = lru_.next; e != &lru_; ) {
182
+ LRUHandle* next = e->next;
183
+ assert(e->refs == 1); // Error if caller has an unreleased handle
184
+ Unref(e);
185
+ e = next;
186
+ }
187
+ }
188
+
189
+ void LRUCache::Unref(LRUHandle* e) {
190
+ assert(e->refs > 0);
191
+ e->refs--;
192
+ if (e->refs <= 0) {
193
+ usage_ -= e->charge;
194
+ (*e->deleter)(e->key(), e->value);
195
+ free(e);
196
+ }
197
+ }
198
+
199
+ void LRUCache::LRU_Remove(LRUHandle* e) {
200
+ e->next->prev = e->prev;
201
+ e->prev->next = e->next;
202
+ }
203
+
204
+ void LRUCache::LRU_Append(LRUHandle* e) {
205
+ // Make "e" newest entry by inserting just before lru_
206
+ e->next = &lru_;
207
+ e->prev = lru_.prev;
208
+ e->prev->next = e;
209
+ e->next->prev = e;
210
+ }
211
+
212
+ Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) {
213
+ MutexLock l(&mutex_);
214
+ LRUHandle* e = table_.Lookup(key, hash);
215
+ if (e != NULL) {
216
+ e->refs++;
217
+ LRU_Remove(e);
218
+ LRU_Append(e);
219
+ }
220
+ return reinterpret_cast<Cache::Handle*>(e);
221
+ }
222
+
223
+ void LRUCache::Release(Cache::Handle* handle) {
224
+ MutexLock l(&mutex_);
225
+ Unref(reinterpret_cast<LRUHandle*>(handle));
226
+ }
227
+
228
+ Cache::Handle* LRUCache::Insert(
229
+ const Slice& key, uint32_t hash, void* value, size_t charge,
230
+ void (*deleter)(const Slice& key, void* value)) {
231
+ MutexLock l(&mutex_);
232
+
233
+ LRUHandle* e = reinterpret_cast<LRUHandle*>(
234
+ malloc(sizeof(LRUHandle)-1 + key.size()));
235
+ e->value = value;
236
+ e->deleter = deleter;
237
+ e->charge = charge;
238
+ e->key_length = key.size();
239
+ e->hash = hash;
240
+ e->refs = 2; // One from LRUCache, one for the returned handle
241
+ memcpy(e->key_data, key.data(), key.size());
242
+ LRU_Append(e);
243
+ usage_ += charge;
244
+
245
+ LRUHandle* old = table_.Insert(e);
246
+ if (old != NULL) {
247
+ LRU_Remove(old);
248
+ Unref(old);
249
+ }
250
+
251
+ while (usage_ > capacity_ && lru_.next != &lru_) {
252
+ LRUHandle* old = lru_.next;
253
+ LRU_Remove(old);
254
+ table_.Remove(old->key(), old->hash);
255
+ Unref(old);
256
+ }
257
+
258
+ return reinterpret_cast<Cache::Handle*>(e);
259
+ }
260
+
261
+ void LRUCache::Erase(const Slice& key, uint32_t hash) {
262
+ MutexLock l(&mutex_);
263
+ LRUHandle* e = table_.Remove(key, hash);
264
+ if (e != NULL) {
265
+ LRU_Remove(e);
266
+ Unref(e);
267
+ }
268
+ }
269
+
270
+ static const int kNumShardBits = 4;
271
+ static const int kNumShards = 1 << kNumShardBits;
272
+
273
+ class ShardedLRUCache : public Cache {
274
+ private:
275
+ LRUCache shard_[kNumShards];
276
+ port::Mutex id_mutex_;
277
+ uint64_t last_id_;
278
+
279
+ static inline uint32_t HashSlice(const Slice& s) {
280
+ return Hash(s.data(), s.size(), 0);
281
+ }
282
+
283
+ static uint32_t Shard(uint32_t hash) {
284
+ return hash >> (32 - kNumShardBits);
285
+ }
286
+
287
+ public:
288
+ explicit ShardedLRUCache(size_t capacity)
289
+ : last_id_(0) {
290
+ const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards;
291
+ for (int s = 0; s < kNumShards; s++) {
292
+ shard_[s].SetCapacity(per_shard);
293
+ }
294
+ }
295
+ virtual ~ShardedLRUCache() { }
296
+ virtual Handle* Insert(const Slice& key, void* value, size_t charge,
297
+ void (*deleter)(const Slice& key, void* value)) {
298
+ const uint32_t hash = HashSlice(key);
299
+ return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter);
300
+ }
301
+ virtual Handle* Lookup(const Slice& key) {
302
+ const uint32_t hash = HashSlice(key);
303
+ return shard_[Shard(hash)].Lookup(key, hash);
304
+ }
305
+ virtual void Release(Handle* handle) {
306
+ LRUHandle* h = reinterpret_cast<LRUHandle*>(handle);
307
+ shard_[Shard(h->hash)].Release(handle);
308
+ }
309
+ virtual void Erase(const Slice& key) {
310
+ const uint32_t hash = HashSlice(key);
311
+ shard_[Shard(hash)].Erase(key, hash);
312
+ }
313
+ virtual void* Value(Handle* handle) {
314
+ return reinterpret_cast<LRUHandle*>(handle)->value;
315
+ }
316
+ virtual uint64_t NewId() {
317
+ MutexLock l(&id_mutex_);
318
+ return ++(last_id_);
319
+ }
320
+ };
321
+
322
+ } // end anonymous namespace
323
+
324
+ Cache* NewLRUCache(size_t capacity) {
325
+ return new ShardedLRUCache(capacity);
326
+ }
327
+
328
+ } // namespace leveldb