leveldb-ruby 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/README +17 -0
  2. data/ext/leveldb/extconf.rb +10 -0
  3. data/ext/leveldb/leveldb.cc +181 -0
  4. data/leveldb/Makefile +172 -0
  5. data/leveldb/db/builder.cc +90 -0
  6. data/leveldb/db/builder.h +36 -0
  7. data/leveldb/db/corruption_test.cc +354 -0
  8. data/leveldb/db/db_bench.cc +677 -0
  9. data/leveldb/db/db_impl.cc +1236 -0
  10. data/leveldb/db/db_impl.h +180 -0
  11. data/leveldb/db/db_iter.cc +298 -0
  12. data/leveldb/db/db_iter.h +26 -0
  13. data/leveldb/db/db_test.cc +1192 -0
  14. data/leveldb/db/dbformat.cc +87 -0
  15. data/leveldb/db/dbformat.h +165 -0
  16. data/leveldb/db/dbformat_test.cc +112 -0
  17. data/leveldb/db/filename.cc +135 -0
  18. data/leveldb/db/filename.h +80 -0
  19. data/leveldb/db/filename_test.cc +122 -0
  20. data/leveldb/db/log_format.h +35 -0
  21. data/leveldb/db/log_reader.cc +254 -0
  22. data/leveldb/db/log_reader.h +108 -0
  23. data/leveldb/db/log_test.cc +500 -0
  24. data/leveldb/db/log_writer.cc +103 -0
  25. data/leveldb/db/log_writer.h +48 -0
  26. data/leveldb/db/memtable.cc +108 -0
  27. data/leveldb/db/memtable.h +85 -0
  28. data/leveldb/db/repair.cc +384 -0
  29. data/leveldb/db/skiplist.h +378 -0
  30. data/leveldb/db/skiplist_test.cc +378 -0
  31. data/leveldb/db/snapshot.h +66 -0
  32. data/leveldb/db/table_cache.cc +95 -0
  33. data/leveldb/db/table_cache.h +50 -0
  34. data/leveldb/db/version_edit.cc +268 -0
  35. data/leveldb/db/version_edit.h +106 -0
  36. data/leveldb/db/version_edit_test.cc +46 -0
  37. data/leveldb/db/version_set.cc +1060 -0
  38. data/leveldb/db/version_set.h +306 -0
  39. data/leveldb/db/write_batch.cc +138 -0
  40. data/leveldb/db/write_batch_internal.h +45 -0
  41. data/leveldb/db/write_batch_test.cc +89 -0
  42. data/leveldb/include/leveldb/cache.h +99 -0
  43. data/leveldb/include/leveldb/comparator.h +63 -0
  44. data/leveldb/include/leveldb/db.h +148 -0
  45. data/leveldb/include/leveldb/env.h +302 -0
  46. data/leveldb/include/leveldb/iterator.h +100 -0
  47. data/leveldb/include/leveldb/options.h +198 -0
  48. data/leveldb/include/leveldb/slice.h +109 -0
  49. data/leveldb/include/leveldb/status.h +100 -0
  50. data/leveldb/include/leveldb/table.h +70 -0
  51. data/leveldb/include/leveldb/table_builder.h +91 -0
  52. data/leveldb/include/leveldb/write_batch.h +64 -0
  53. data/leveldb/port/port.h +23 -0
  54. data/leveldb/port/port_android.cc +64 -0
  55. data/leveldb/port/port_android.h +150 -0
  56. data/leveldb/port/port_chromium.cc +80 -0
  57. data/leveldb/port/port_chromium.h +97 -0
  58. data/leveldb/port/port_example.h +115 -0
  59. data/leveldb/port/port_osx.cc +50 -0
  60. data/leveldb/port/port_osx.h +125 -0
  61. data/leveldb/port/port_posix.cc +50 -0
  62. data/leveldb/port/port_posix.h +94 -0
  63. data/leveldb/port/sha1_portable.cc +298 -0
  64. data/leveldb/port/sha1_portable.h +25 -0
  65. data/leveldb/port/sha1_test.cc +39 -0
  66. data/leveldb/port/win/stdint.h +24 -0
  67. data/leveldb/table/block.cc +263 -0
  68. data/leveldb/table/block.h +43 -0
  69. data/leveldb/table/block_builder.cc +109 -0
  70. data/leveldb/table/block_builder.h +57 -0
  71. data/leveldb/table/format.cc +131 -0
  72. data/leveldb/table/format.h +103 -0
  73. data/leveldb/table/iterator.cc +67 -0
  74. data/leveldb/table/iterator_wrapper.h +63 -0
  75. data/leveldb/table/merger.cc +197 -0
  76. data/leveldb/table/merger.h +26 -0
  77. data/leveldb/table/table.cc +175 -0
  78. data/leveldb/table/table_builder.cc +227 -0
  79. data/leveldb/table/table_test.cc +845 -0
  80. data/leveldb/table/two_level_iterator.cc +182 -0
  81. data/leveldb/table/two_level_iterator.h +34 -0
  82. data/leveldb/util/arena.cc +68 -0
  83. data/leveldb/util/arena.h +68 -0
  84. data/leveldb/util/arena_test.cc +68 -0
  85. data/leveldb/util/cache.cc +255 -0
  86. data/leveldb/util/cache_test.cc +169 -0
  87. data/leveldb/util/coding.cc +194 -0
  88. data/leveldb/util/coding.h +104 -0
  89. data/leveldb/util/coding_test.cc +173 -0
  90. data/leveldb/util/comparator.cc +72 -0
  91. data/leveldb/util/crc32c.cc +332 -0
  92. data/leveldb/util/crc32c.h +45 -0
  93. data/leveldb/util/crc32c_test.cc +72 -0
  94. data/leveldb/util/env.cc +77 -0
  95. data/leveldb/util/env_chromium.cc +612 -0
  96. data/leveldb/util/env_posix.cc +606 -0
  97. data/leveldb/util/env_test.cc +102 -0
  98. data/leveldb/util/hash.cc +45 -0
  99. data/leveldb/util/hash.h +19 -0
  100. data/leveldb/util/histogram.cc +128 -0
  101. data/leveldb/util/histogram.h +41 -0
  102. data/leveldb/util/logging.cc +81 -0
  103. data/leveldb/util/logging.h +47 -0
  104. data/leveldb/util/mutexlock.h +39 -0
  105. data/leveldb/util/options.cc +28 -0
  106. data/leveldb/util/random.h +59 -0
  107. data/leveldb/util/status.cc +75 -0
  108. data/leveldb/util/testharness.cc +65 -0
  109. data/leveldb/util/testharness.h +129 -0
  110. data/leveldb/util/testutil.cc +51 -0
  111. data/leveldb/util/testutil.h +53 -0
  112. data/lib/leveldb.rb +36 -0
  113. metadata +183 -0
@@ -0,0 +1,182 @@
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 "table/two_level_iterator.h"
6
+
7
+ #include "leveldb/table.h"
8
+ #include "table/block.h"
9
+ #include "table/format.h"
10
+ #include "table/iterator_wrapper.h"
11
+
12
+ namespace leveldb {
13
+
14
+ namespace {
15
+
16
+ typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&);
17
+
18
+ class TwoLevelIterator: public Iterator {
19
+ public:
20
+ TwoLevelIterator(
21
+ Iterator* index_iter,
22
+ BlockFunction block_function,
23
+ void* arg,
24
+ const ReadOptions& options);
25
+
26
+ virtual ~TwoLevelIterator();
27
+
28
+ virtual void Seek(const Slice& target);
29
+ virtual void SeekToFirst();
30
+ virtual void SeekToLast();
31
+ virtual void Next();
32
+ virtual void Prev();
33
+
34
+ virtual bool Valid() const {
35
+ return data_iter_.Valid();
36
+ }
37
+ virtual Slice key() const {
38
+ assert(Valid());
39
+ return data_iter_.key();
40
+ }
41
+ virtual Slice value() const {
42
+ assert(Valid());
43
+ return data_iter_.value();
44
+ }
45
+ virtual Status status() const {
46
+ // It'd be nice if status() returned a const Status& instead of a Status
47
+ if (!index_iter_.status().ok()) {
48
+ return index_iter_.status();
49
+ } else if (data_iter_.iter() != NULL && !data_iter_.status().ok()) {
50
+ return data_iter_.status();
51
+ } else {
52
+ return status_;
53
+ }
54
+ }
55
+
56
+ private:
57
+ void SaveError(const Status& s) {
58
+ if (status_.ok() && !s.ok()) status_ = s;
59
+ }
60
+ void SkipEmptyDataBlocksForward();
61
+ void SkipEmptyDataBlocksBackward();
62
+ void SetDataIterator(Iterator* data_iter);
63
+ void InitDataBlock();
64
+
65
+ BlockFunction block_function_;
66
+ void* arg_;
67
+ const ReadOptions options_;
68
+ Status status_;
69
+ IteratorWrapper index_iter_;
70
+ IteratorWrapper data_iter_; // May be NULL
71
+ // If data_iter_ is non-NULL, then "data_block_handle_" holds the
72
+ // "index_value" passed to block_function_ to create the data_iter_.
73
+ std::string data_block_handle_;
74
+ };
75
+
76
+ TwoLevelIterator::TwoLevelIterator(
77
+ Iterator* index_iter,
78
+ BlockFunction block_function,
79
+ void* arg,
80
+ const ReadOptions& options)
81
+ : block_function_(block_function),
82
+ arg_(arg),
83
+ options_(options),
84
+ index_iter_(index_iter),
85
+ data_iter_(NULL) {
86
+ }
87
+
88
+ TwoLevelIterator::~TwoLevelIterator() {
89
+ }
90
+
91
+ void TwoLevelIterator::Seek(const Slice& target) {
92
+ index_iter_.Seek(target);
93
+ InitDataBlock();
94
+ if (data_iter_.iter() != NULL) data_iter_.Seek(target);
95
+ SkipEmptyDataBlocksForward();
96
+ }
97
+
98
+ void TwoLevelIterator::SeekToFirst() {
99
+ index_iter_.SeekToFirst();
100
+ InitDataBlock();
101
+ if (data_iter_.iter() != NULL) data_iter_.SeekToFirst();
102
+ SkipEmptyDataBlocksForward();
103
+ }
104
+
105
+ void TwoLevelIterator::SeekToLast() {
106
+ index_iter_.SeekToLast();
107
+ InitDataBlock();
108
+ if (data_iter_.iter() != NULL) data_iter_.SeekToLast();
109
+ SkipEmptyDataBlocksBackward();
110
+ }
111
+
112
+ void TwoLevelIterator::Next() {
113
+ assert(Valid());
114
+ data_iter_.Next();
115
+ SkipEmptyDataBlocksForward();
116
+ }
117
+
118
+ void TwoLevelIterator::Prev() {
119
+ assert(Valid());
120
+ data_iter_.Prev();
121
+ SkipEmptyDataBlocksBackward();
122
+ }
123
+
124
+
125
+ void TwoLevelIterator::SkipEmptyDataBlocksForward() {
126
+ while (data_iter_.iter() == NULL || !data_iter_.Valid()) {
127
+ // Move to next block
128
+ if (!index_iter_.Valid()) {
129
+ SetDataIterator(NULL);
130
+ return;
131
+ }
132
+ index_iter_.Next();
133
+ InitDataBlock();
134
+ if (data_iter_.iter() != NULL) data_iter_.SeekToFirst();
135
+ }
136
+ }
137
+
138
+ void TwoLevelIterator::SkipEmptyDataBlocksBackward() {
139
+ while (data_iter_.iter() == NULL || !data_iter_.Valid()) {
140
+ // Move to next block
141
+ if (!index_iter_.Valid()) {
142
+ SetDataIterator(NULL);
143
+ return;
144
+ }
145
+ index_iter_.Prev();
146
+ InitDataBlock();
147
+ if (data_iter_.iter() != NULL) data_iter_.SeekToLast();
148
+ }
149
+ }
150
+
151
+ void TwoLevelIterator::SetDataIterator(Iterator* data_iter) {
152
+ if (data_iter_.iter() != NULL) SaveError(data_iter_.status());
153
+ data_iter_.Set(data_iter);
154
+ }
155
+
156
+ void TwoLevelIterator::InitDataBlock() {
157
+ if (!index_iter_.Valid()) {
158
+ SetDataIterator(NULL);
159
+ } else {
160
+ Slice handle = index_iter_.value();
161
+ if (data_iter_.iter() != NULL && handle.compare(data_block_handle_) == 0) {
162
+ // data_iter_ is already constructed with this iterator, so
163
+ // no need to change anything
164
+ } else {
165
+ Iterator* iter = (*block_function_)(arg_, options_, handle);
166
+ data_block_handle_.assign(handle.data(), handle.size());
167
+ SetDataIterator(iter);
168
+ }
169
+ }
170
+ }
171
+
172
+ }
173
+
174
+ Iterator* NewTwoLevelIterator(
175
+ Iterator* index_iter,
176
+ BlockFunction block_function,
177
+ void* arg,
178
+ const ReadOptions& options) {
179
+ return new TwoLevelIterator(index_iter, block_function, arg, options);
180
+ }
181
+
182
+ }
@@ -0,0 +1,34 @@
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
+ #ifndef STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_
6
+ #define STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_
7
+
8
+ #include "leveldb/iterator.h"
9
+
10
+ namespace leveldb {
11
+
12
+ struct ReadOptions;
13
+
14
+ // Return a new two level iterator. A two-level iterator contains an
15
+ // index iterator whose values point to a sequence of blocks where
16
+ // each block is itself a sequence of key,value pairs. The returned
17
+ // two-level iterator yields the concatenation of all key/value pairs
18
+ // in the sequence of blocks. Takes ownership of "index_iter" and
19
+ // will delete it when no longer needed.
20
+ //
21
+ // Uses a supplied function to convert an index_iter value into
22
+ // an iterator over the contents of the corresponding block.
23
+ extern Iterator* NewTwoLevelIterator(
24
+ Iterator* index_iter,
25
+ Iterator* (*block_function)(
26
+ void* arg,
27
+ const ReadOptions& options,
28
+ const Slice& index_value),
29
+ void* arg,
30
+ const ReadOptions& options);
31
+
32
+ }
33
+
34
+ #endif // STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_
@@ -0,0 +1,68 @@
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 "util/arena.h"
6
+ #include <assert.h>
7
+
8
+ namespace leveldb {
9
+
10
+ static const int kBlockSize = 4096;
11
+
12
+ Arena::Arena() {
13
+ blocks_memory_ = 0;
14
+ alloc_ptr_ = NULL; // First allocation will allocate a block
15
+ alloc_bytes_remaining_ = 0;
16
+ }
17
+
18
+ Arena::~Arena() {
19
+ for (size_t i = 0; i < blocks_.size(); i++) {
20
+ delete[] blocks_[i];
21
+ }
22
+ }
23
+
24
+ char* Arena::AllocateFallback(size_t bytes) {
25
+ if (bytes > kBlockSize / 4) {
26
+ // Object is more than a quarter of our block size. Allocate it separately
27
+ // to avoid wasting too much space in leftover bytes.
28
+ char* result = AllocateNewBlock(bytes);
29
+ return result;
30
+ }
31
+
32
+ // We waste the remaining space in the current block.
33
+ alloc_ptr_ = AllocateNewBlock(kBlockSize);
34
+ alloc_bytes_remaining_ = kBlockSize;
35
+
36
+ char* result = alloc_ptr_;
37
+ alloc_ptr_ += bytes;
38
+ alloc_bytes_remaining_ -= bytes;
39
+ return result;
40
+ }
41
+
42
+ char* Arena::AllocateAligned(size_t bytes) {
43
+ const int align = sizeof(void*); // We'll align to pointer size
44
+ assert((align & (align-1)) == 0); // Pointer size should be a power of 2
45
+ size_t current_mod = reinterpret_cast<uintptr_t>(alloc_ptr_) & (align-1);
46
+ size_t slop = (current_mod == 0 ? 0 : align - current_mod);
47
+ size_t needed = bytes + slop;
48
+ char* result;
49
+ if (needed <= alloc_bytes_remaining_) {
50
+ result = alloc_ptr_ + slop;
51
+ alloc_ptr_ += needed;
52
+ alloc_bytes_remaining_ -= needed;
53
+ } else {
54
+ // AllocateFallback always returned aligned memory
55
+ result = AllocateFallback(bytes);
56
+ }
57
+ assert((reinterpret_cast<uintptr_t>(result) & (align-1)) == 0);
58
+ return result;
59
+ }
60
+
61
+ char* Arena::AllocateNewBlock(size_t block_bytes) {
62
+ char* result = new char[block_bytes];
63
+ blocks_memory_ += block_bytes;
64
+ blocks_.push_back(result);
65
+ return result;
66
+ }
67
+
68
+ }
@@ -0,0 +1,68 @@
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
+ #ifndef STORAGE_LEVELDB_UTIL_ARENA_H_
6
+ #define STORAGE_LEVELDB_UTIL_ARENA_H_
7
+
8
+ #include <cstddef>
9
+ #include <vector>
10
+ #include <assert.h>
11
+ #include <stdint.h>
12
+
13
+ namespace leveldb {
14
+
15
+ class Arena {
16
+ public:
17
+ Arena();
18
+ ~Arena();
19
+
20
+ // Return a pointer to a newly allocated memory block of "bytes" bytes.
21
+ char* Allocate(size_t bytes);
22
+
23
+ // Allocate memory with the normal alignment guarantees provided by malloc
24
+ char* AllocateAligned(size_t bytes);
25
+
26
+ // Returns an estimate of the total memory usage of data allocated
27
+ // by the arena (including space allocated but not yet used for user
28
+ // allocations).
29
+ size_t MemoryUsage() const {
30
+ return blocks_memory_ + blocks_.capacity() * sizeof(char*);
31
+ }
32
+
33
+ private:
34
+ char* AllocateFallback(size_t bytes);
35
+ char* AllocateNewBlock(size_t block_bytes);
36
+
37
+ // Allocation state
38
+ char* alloc_ptr_;
39
+ size_t alloc_bytes_remaining_;
40
+
41
+ // Array of new[] allocated memory blocks
42
+ std::vector<char*> blocks_;
43
+
44
+ // Bytes of memory in blocks allocated so far
45
+ size_t blocks_memory_;
46
+
47
+ // No copying allowed
48
+ Arena(const Arena&);
49
+ void operator=(const Arena&);
50
+ };
51
+
52
+ inline char* Arena::Allocate(size_t bytes) {
53
+ // The semantics of what to return are a bit messy if we allow
54
+ // 0-byte allocations, so we disallow them here (we don't need
55
+ // them for our internal use).
56
+ assert(bytes > 0);
57
+ if (bytes <= alloc_bytes_remaining_) {
58
+ char* result = alloc_ptr_;
59
+ alloc_ptr_ += bytes;
60
+ alloc_bytes_remaining_ -= bytes;
61
+ return result;
62
+ }
63
+ return AllocateFallback(bytes);
64
+ }
65
+
66
+ }
67
+
68
+ #endif // STORAGE_LEVELDB_UTIL_ARENA_H_
@@ -0,0 +1,68 @@
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 "util/arena.h"
6
+
7
+ #include "util/random.h"
8
+ #include "util/testharness.h"
9
+
10
+ namespace leveldb {
11
+
12
+ class ArenaTest { };
13
+
14
+ TEST(ArenaTest, Empty) {
15
+ Arena arena;
16
+ }
17
+
18
+ TEST(ArenaTest, Simple) {
19
+ std::vector<std::pair<size_t, char*> > allocated;
20
+ Arena arena;
21
+ const int N = 100000;
22
+ size_t bytes = 0;
23
+ Random rnd(301);
24
+ for (int i = 0; i < N; i++) {
25
+ size_t s;
26
+ if (i % (N / 10) == 0) {
27
+ s = i;
28
+ } else {
29
+ s = rnd.OneIn(4000) ? rnd.Uniform(6000) :
30
+ (rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20));
31
+ }
32
+ if (s == 0) {
33
+ // Our arena disallows size 0 allocations.
34
+ s = 1;
35
+ }
36
+ char* r;
37
+ if (rnd.OneIn(10)) {
38
+ r = arena.AllocateAligned(s);
39
+ } else {
40
+ r = arena.Allocate(s);
41
+ }
42
+
43
+ for (int b = 0; b < s; b++) {
44
+ // Fill the "i"th allocation with a known bit pattern
45
+ r[b] = i % 256;
46
+ }
47
+ bytes += s;
48
+ allocated.push_back(std::make_pair(s, r));
49
+ ASSERT_GE(arena.MemoryUsage(), bytes);
50
+ if (i > N/10) {
51
+ ASSERT_LE(arena.MemoryUsage(), bytes * 1.10);
52
+ }
53
+ }
54
+ for (int i = 0; i < allocated.size(); i++) {
55
+ size_t num_bytes = allocated[i].first;
56
+ const char* p = allocated[i].second;
57
+ for (int b = 0; b < num_bytes; b++) {
58
+ // Check the "i"th allocation for the known bit pattern
59
+ ASSERT_EQ(int(p[b]) & 0xff, i % 256);
60
+ }
61
+ }
62
+ }
63
+
64
+ }
65
+
66
+ int main(int argc, char** argv) {
67
+ return leveldb::test::RunAllTests();
68
+ }
@@ -0,0 +1,255 @@
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
+ #if defined(LEVELDB_PLATFORM_POSIX) || defined(LEVELDB_PLATFORM_ANDROID)
6
+ #include <unordered_set>
7
+ #elif defined(LEVELDB_PLATFORM_OSX)
8
+ #include <ext/hash_set>
9
+ #elif defined(LEVELDB_PLATFORM_CHROMIUM)
10
+ #include "base/hash_tables.h"
11
+ #else
12
+ #include <hash_set> // TODO(sanjay): Switch to unordered_set when possible.
13
+ #endif
14
+
15
+ #include <assert.h>
16
+
17
+ #include "leveldb/cache.h"
18
+ #include "port/port.h"
19
+ #include "util/hash.h"
20
+ #include "util/mutexlock.h"
21
+
22
+ namespace leveldb {
23
+
24
+ Cache::~Cache() {
25
+ }
26
+
27
+ namespace {
28
+
29
+ // LRU cache implementation
30
+
31
+ // An entry is a variable length heap-allocated structure. Entries
32
+ // are kept in a circular doubly linked list ordered by access time.
33
+ struct LRUHandle {
34
+ void* value;
35
+ void (*deleter)(const Slice&, void* value);
36
+ LRUHandle* next;
37
+ LRUHandle* prev;
38
+ size_t charge; // TODO(opt): Only allow uint32_t?
39
+ size_t key_length;
40
+ size_t refs; // TODO(opt): Pack with "key_length"?
41
+ char key_data[1]; // Beginning of key
42
+
43
+ Slice key() const {
44
+ // For cheaper lookups, we allow a temporary Handle object
45
+ // to store a pointer to a key in "value".
46
+ if (next == this) {
47
+ return *(reinterpret_cast<Slice*>(value));
48
+ } else {
49
+ return Slice(key_data, key_length);
50
+ }
51
+ }
52
+ };
53
+
54
+ // Pick a platform specific hash_set instantiation
55
+ #if defined(LEVELDB_PLATFORM_CHROMIUM) && defined(OS_WIN)
56
+ // Microsoft's hash_set deviates from the standard. See
57
+ // http://msdn.microsoft.com/en-us/library/1t4xas78(v=vs.80).aspx
58
+ // for details. Basically the 2 param () operator is a less than and
59
+ // the 1 param () operator is a hash function.
60
+ struct HandleHashCompare : public stdext::hash_compare<LRUHandle*> {
61
+ size_t operator() (LRUHandle* h) const {
62
+ Slice k = h->key();
63
+ return Hash(k.data(), k.size(), 0);
64
+ }
65
+ bool operator() (LRUHandle* a, LRUHandle* b) const {
66
+ return a->key().compare(b->key()) < 0;
67
+ }
68
+ };
69
+ typedef base::hash_set<LRUHandle*, HandleHashCompare> HandleTable;
70
+ #else
71
+ struct HandleHash {
72
+ inline size_t operator()(LRUHandle* h) const {
73
+ Slice k = h->key();
74
+ return Hash(k.data(), k.size(), 0);
75
+ }
76
+ };
77
+
78
+ struct HandleEq {
79
+ inline bool operator()(LRUHandle* a, LRUHandle* b) const {
80
+ return a->key() == b->key();
81
+ }
82
+ };
83
+ # if defined(LEVELDB_PLATFORM_CHROMIUM)
84
+ typedef base::hash_set<LRUHandle*, HandleHash, HandleEq> HandleTable;
85
+ # elif defined(LEVELDB_PLATFORM_POSIX) || defined(LEVELDB_PLATFORM_ANDROID)
86
+ typedef std::unordered_set<LRUHandle*, HandleHash, HandleEq> HandleTable;
87
+ # else
88
+ typedef __gnu_cxx::hash_set<LRUHandle*, HandleHash, HandleEq> HandleTable;
89
+ # endif
90
+ #endif
91
+
92
+ class LRUCache : public Cache {
93
+ public:
94
+ explicit LRUCache(size_t capacity);
95
+ virtual ~LRUCache();
96
+
97
+ virtual Handle* Insert(const Slice& key, void* value, size_t charge,
98
+ void (*deleter)(const Slice& key, void* value));
99
+ virtual Handle* Lookup(const Slice& key);
100
+ virtual void Release(Handle* handle);
101
+ virtual void* Value(Handle* handle);
102
+ virtual void Erase(const Slice& key);
103
+ virtual uint64_t NewId();
104
+
105
+ private:
106
+ void LRU_Remove(LRUHandle* e);
107
+ void LRU_Append(LRUHandle* e);
108
+ void Unref(LRUHandle* e);
109
+
110
+ // Constructor parameters
111
+ const size_t capacity_;
112
+
113
+ // mutex_ protects the following state.
114
+ port::Mutex mutex_;
115
+ size_t usage_;
116
+ uint64_t last_id_;
117
+
118
+ // Dummy head of LRU list.
119
+ // lru.prev is newest entry, lru.next is oldest entry.
120
+ LRUHandle lru_;
121
+
122
+ HandleTable table_;
123
+ };
124
+
125
+ LRUCache::LRUCache(size_t capacity)
126
+ : capacity_(capacity),
127
+ usage_(0),
128
+ last_id_(0) {
129
+ // Make empty circular linked list
130
+ lru_.next = &lru_;
131
+ lru_.prev = &lru_;
132
+ }
133
+
134
+ LRUCache::~LRUCache() {
135
+ table_.clear();
136
+ for (LRUHandle* e = lru_.next; e != &lru_; ) {
137
+ LRUHandle* next = e->next;
138
+ assert(e->refs == 1); // Error if caller has an unreleased handle
139
+ Unref(e);
140
+ e = next;
141
+ }
142
+ }
143
+
144
+ void LRUCache::Unref(LRUHandle* e) {
145
+ assert(e->refs > 0);
146
+ e->refs--;
147
+ if (e->refs <= 0) {
148
+ usage_ -= e->charge;
149
+ (*e->deleter)(e->key(), e->value);
150
+ free(e);
151
+ }
152
+ }
153
+
154
+ void LRUCache::LRU_Remove(LRUHandle* e) {
155
+ e->next->prev = e->prev;
156
+ e->prev->next = e->next;
157
+ }
158
+
159
+ void LRUCache::LRU_Append(LRUHandle* e) {
160
+ // Make "e" newest entry by inserting just before lru_
161
+ e->next = &lru_;
162
+ e->prev = lru_.prev;
163
+ e->prev->next = e;
164
+ e->next->prev = e;
165
+ }
166
+
167
+ Cache::Handle* LRUCache::Lookup(const Slice& key) {
168
+ MutexLock l(&mutex_);
169
+
170
+ LRUHandle dummy;
171
+ dummy.next = &dummy;
172
+ dummy.value = const_cast<Slice*>(&key);
173
+ HandleTable::iterator iter = table_.find(&dummy);
174
+ if (iter == table_.end()) {
175
+ return NULL;
176
+ } else {
177
+ LRUHandle* e = const_cast<LRUHandle*>(*iter);
178
+ e->refs++;
179
+ LRU_Remove(e);
180
+ LRU_Append(e);
181
+ return reinterpret_cast<Handle*>(e);
182
+ }
183
+ }
184
+
185
+ void* LRUCache::Value(Handle* handle) {
186
+ return reinterpret_cast<LRUHandle*>(handle)->value;
187
+ }
188
+
189
+ void LRUCache::Release(Handle* handle) {
190
+ MutexLock l(&mutex_);
191
+ Unref(reinterpret_cast<LRUHandle*>(handle));
192
+ }
193
+
194
+ Cache::Handle* LRUCache::Insert(const Slice& key, void* value, size_t charge,
195
+ void (*deleter)(const Slice& key, void* value)) {
196
+ MutexLock l(&mutex_);
197
+
198
+ LRUHandle* e = reinterpret_cast<LRUHandle*>(
199
+ malloc(sizeof(LRUHandle)-1 + key.size()));
200
+ e->value = value;
201
+ e->deleter = deleter;
202
+ e->charge = charge;
203
+ e->key_length = key.size();
204
+ e->refs = 2; // One from LRUCache, one for the returned handle
205
+ memcpy(e->key_data, key.data(), key.size());
206
+ LRU_Append(e);
207
+ usage_ += charge;
208
+
209
+ std::pair<HandleTable::iterator,bool> p = table_.insert(e);
210
+ if (!p.second) {
211
+ // Kill existing entry
212
+ LRUHandle* old = const_cast<LRUHandle*>(*(p.first));
213
+ LRU_Remove(old);
214
+ table_.erase(p.first);
215
+ table_.insert(e);
216
+ Unref(old);
217
+ }
218
+
219
+ while (usage_ > capacity_ && lru_.next != &lru_) {
220
+ LRUHandle* old = lru_.next;
221
+ LRU_Remove(old);
222
+ table_.erase(old);
223
+ Unref(old);
224
+ }
225
+
226
+ return reinterpret_cast<Handle*>(e);
227
+ }
228
+
229
+ void LRUCache::Erase(const Slice& key) {
230
+ MutexLock l(&mutex_);
231
+
232
+ LRUHandle dummy;
233
+ dummy.next = &dummy;
234
+ dummy.value = const_cast<Slice*>(&key);
235
+ HandleTable::iterator iter = table_.find(&dummy);
236
+ if (iter != table_.end()) {
237
+ LRUHandle* e = const_cast<LRUHandle*>(*iter);
238
+ LRU_Remove(e);
239
+ table_.erase(iter);
240
+ Unref(e);
241
+ }
242
+ }
243
+
244
+ uint64_t LRUCache::NewId() {
245
+ MutexLock l(&mutex_);
246
+ return ++(last_id_);
247
+ }
248
+
249
+ } // end anonymous namespace
250
+
251
+ Cache* NewLRUCache(size_t capacity) {
252
+ return new LRUCache(capacity);
253
+ }
254
+
255
+ }