filiptepper-leveldb-ruby 0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,379 @@
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
+ // Thread safety
6
+ // -------------
7
+ //
8
+ // Writes require external synchronization, most likely a mutex.
9
+ // Reads require a guarantee that the SkipList will not be destroyed
10
+ // while the read is in progress. Apart from that, reads progress
11
+ // without any internal locking or synchronization.
12
+ //
13
+ // Invariants:
14
+ //
15
+ // (1) Allocated nodes are never deleted until the SkipList is
16
+ // destroyed. This is trivially guaranteed by the code since we
17
+ // never delete any skip list nodes.
18
+ //
19
+ // (2) The contents of a Node except for the next/prev pointers are
20
+ // immutable after the Node has been linked into the SkipList.
21
+ // Only Insert() modifies the list, and it is careful to initialize
22
+ // a node and use release-stores to publish the nodes in one or
23
+ // more lists.
24
+ //
25
+ // ... prev vs. next pointer ordering ...
26
+
27
+ #include <assert.h>
28
+ #include <stdlib.h>
29
+ #include "port/port.h"
30
+ #include "util/arena.h"
31
+ #include "util/random.h"
32
+
33
+ namespace leveldb {
34
+
35
+ class Arena;
36
+
37
+ template<typename Key, class Comparator>
38
+ class SkipList {
39
+ private:
40
+ struct Node;
41
+
42
+ public:
43
+ // Create a new SkipList object that will use "cmp" for comparing keys,
44
+ // and will allocate memory using "*arena". Objects allocated in the arena
45
+ // must remain allocated for the lifetime of the skiplist object.
46
+ explicit SkipList(Comparator cmp, Arena* arena);
47
+
48
+ // Insert key into the list.
49
+ // REQUIRES: nothing that compares equal to key is currently in the list.
50
+ void Insert(const Key& key);
51
+
52
+ // Returns true iff an entry that compares equal to key is in the list.
53
+ bool Contains(const Key& key) const;
54
+
55
+ // Iteration over the contents of a skip list
56
+ class Iterator {
57
+ public:
58
+ // Initialize an iterator over the specified list.
59
+ // The returned iterator is not valid.
60
+ explicit Iterator(const SkipList* list);
61
+
62
+ // Returns true iff the iterator is positioned at a valid node.
63
+ bool Valid() const;
64
+
65
+ // Returns the key at the current position.
66
+ // REQUIRES: Valid()
67
+ const Key& key() const;
68
+
69
+ // Advances to the next position.
70
+ // REQUIRES: Valid()
71
+ void Next();
72
+
73
+ // Advances to the previous position.
74
+ // REQUIRES: Valid()
75
+ void Prev();
76
+
77
+ // Advance to the first entry with a key >= target
78
+ void Seek(const Key& target);
79
+
80
+ // Position at the first entry in list.
81
+ // Final state of iterator is Valid() iff list is not empty.
82
+ void SeekToFirst();
83
+
84
+ // Position at the last entry in list.
85
+ // Final state of iterator is Valid() iff list is not empty.
86
+ void SeekToLast();
87
+
88
+ private:
89
+ const SkipList* list_;
90
+ Node* node_;
91
+ // Intentionally copyable
92
+ };
93
+
94
+ private:
95
+ enum { kMaxHeight = 12 };
96
+
97
+ // Immutable after construction
98
+ Comparator const compare_;
99
+ Arena* const arena_; // Arena used for allocations of nodes
100
+
101
+ Node* const head_;
102
+
103
+ // Modified only by Insert(). Read racily by readers, but stale
104
+ // values are ok.
105
+ port::AtomicPointer max_height_; // Height of the entire list
106
+
107
+ inline int GetMaxHeight() const {
108
+ return static_cast<int>(
109
+ reinterpret_cast<intptr_t>(max_height_.NoBarrier_Load()));
110
+ }
111
+
112
+ // Read/written only by Insert().
113
+ Random rnd_;
114
+
115
+ Node* NewNode(const Key& key, int height);
116
+ int RandomHeight();
117
+ bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); }
118
+
119
+ // Return true if key is greater than the data stored in "n"
120
+ bool KeyIsAfterNode(const Key& key, Node* n) const;
121
+
122
+ // Return the earliest node that comes at or after key.
123
+ // Return NULL if there is no such node.
124
+ //
125
+ // If prev is non-NULL, fills prev[level] with pointer to previous
126
+ // node at "level" for every level in [0..max_height_-1].
127
+ Node* FindGreaterOrEqual(const Key& key, Node** prev) const;
128
+
129
+ // Return the latest node with a key < key.
130
+ // Return head_ if there is no such node.
131
+ Node* FindLessThan(const Key& key) const;
132
+
133
+ // Return the last node in the list.
134
+ // Return head_ if list is empty.
135
+ Node* FindLast() const;
136
+
137
+ // No copying allowed
138
+ SkipList(const SkipList&);
139
+ void operator=(const SkipList&);
140
+ };
141
+
142
+ // Implementation details follow
143
+ template<typename Key, class Comparator>
144
+ struct SkipList<Key,Comparator>::Node {
145
+ explicit Node(const Key& k) : key(k) { }
146
+
147
+ Key const key;
148
+
149
+ // Accessors/mutators for links. Wrapped in methods so we can
150
+ // add the appropriate barriers as necessary.
151
+ Node* Next(int n) {
152
+ assert(n >= 0);
153
+ // Use an 'acquire load' so that we observe a fully initialized
154
+ // version of the returned Node.
155
+ return reinterpret_cast<Node*>(next_[n].Acquire_Load());
156
+ }
157
+ void SetNext(int n, Node* x) {
158
+ assert(n >= 0);
159
+ // Use a 'release store' so that anybody who reads through this
160
+ // pointer observes a fully initialized version of the inserted node.
161
+ next_[n].Release_Store(x);
162
+ }
163
+
164
+ // No-barrier variants that can be safely used in a few locations.
165
+ Node* NoBarrier_Next(int n) {
166
+ assert(n >= 0);
167
+ return reinterpret_cast<Node*>(next_[n].NoBarrier_Load());
168
+ }
169
+ void NoBarrier_SetNext(int n, Node* x) {
170
+ assert(n >= 0);
171
+ next_[n].NoBarrier_Store(x);
172
+ }
173
+
174
+ private:
175
+ // Array of length equal to the node height. next_[0] is lowest level link.
176
+ port::AtomicPointer next_[1];
177
+ };
178
+
179
+ template<typename Key, class Comparator>
180
+ typename SkipList<Key,Comparator>::Node*
181
+ SkipList<Key,Comparator>::NewNode(const Key& key, int height) {
182
+ char* mem = arena_->AllocateAligned(
183
+ sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1));
184
+ return new (mem) Node(key);
185
+ }
186
+
187
+ template<typename Key, class Comparator>
188
+ inline SkipList<Key,Comparator>::Iterator::Iterator(const SkipList* list) {
189
+ list_ = list;
190
+ node_ = NULL;
191
+ }
192
+
193
+ template<typename Key, class Comparator>
194
+ inline bool SkipList<Key,Comparator>::Iterator::Valid() const {
195
+ return node_ != NULL;
196
+ }
197
+
198
+ template<typename Key, class Comparator>
199
+ inline const Key& SkipList<Key,Comparator>::Iterator::key() const {
200
+ assert(Valid());
201
+ return node_->key;
202
+ }
203
+
204
+ template<typename Key, class Comparator>
205
+ inline void SkipList<Key,Comparator>::Iterator::Next() {
206
+ assert(Valid());
207
+ node_ = node_->Next(0);
208
+ }
209
+
210
+ template<typename Key, class Comparator>
211
+ inline void SkipList<Key,Comparator>::Iterator::Prev() {
212
+ // Instead of using explicit "prev" links, we just search for the
213
+ // last node that falls before key.
214
+ assert(Valid());
215
+ node_ = list_->FindLessThan(node_->key);
216
+ if (node_ == list_->head_) {
217
+ node_ = NULL;
218
+ }
219
+ }
220
+
221
+ template<typename Key, class Comparator>
222
+ inline void SkipList<Key,Comparator>::Iterator::Seek(const Key& target) {
223
+ node_ = list_->FindGreaterOrEqual(target, NULL);
224
+ }
225
+
226
+ template<typename Key, class Comparator>
227
+ inline void SkipList<Key,Comparator>::Iterator::SeekToFirst() {
228
+ node_ = list_->head_->Next(0);
229
+ }
230
+
231
+ template<typename Key, class Comparator>
232
+ inline void SkipList<Key,Comparator>::Iterator::SeekToLast() {
233
+ node_ = list_->FindLast();
234
+ if (node_ == list_->head_) {
235
+ node_ = NULL;
236
+ }
237
+ }
238
+
239
+ template<typename Key, class Comparator>
240
+ int SkipList<Key,Comparator>::RandomHeight() {
241
+ // Increase height with probability 1 in kBranching
242
+ static const unsigned int kBranching = 4;
243
+ int height = 1;
244
+ while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) {
245
+ height++;
246
+ }
247
+ assert(height > 0);
248
+ assert(height <= kMaxHeight);
249
+ return height;
250
+ }
251
+
252
+ template<typename Key, class Comparator>
253
+ bool SkipList<Key,Comparator>::KeyIsAfterNode(const Key& key, Node* n) const {
254
+ // NULL n is considered infinite
255
+ return (n != NULL) && (compare_(n->key, key) < 0);
256
+ }
257
+
258
+ template<typename Key, class Comparator>
259
+ typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindGreaterOrEqual(const Key& key, Node** prev)
260
+ const {
261
+ Node* x = head_;
262
+ int level = GetMaxHeight() - 1;
263
+ while (true) {
264
+ Node* next = x->Next(level);
265
+ if (KeyIsAfterNode(key, next)) {
266
+ // Keep searching in this list
267
+ x = next;
268
+ } else {
269
+ if (prev != NULL) prev[level] = x;
270
+ if (level == 0) {
271
+ return next;
272
+ } else {
273
+ // Switch to next list
274
+ level--;
275
+ }
276
+ }
277
+ }
278
+ }
279
+
280
+ template<typename Key, class Comparator>
281
+ typename SkipList<Key,Comparator>::Node*
282
+ SkipList<Key,Comparator>::FindLessThan(const Key& key) const {
283
+ Node* x = head_;
284
+ int level = GetMaxHeight() - 1;
285
+ while (true) {
286
+ assert(x == head_ || compare_(x->key, key) < 0);
287
+ Node* next = x->Next(level);
288
+ if (next == NULL || compare_(next->key, key) >= 0) {
289
+ if (level == 0) {
290
+ return x;
291
+ } else {
292
+ // Switch to next list
293
+ level--;
294
+ }
295
+ } else {
296
+ x = next;
297
+ }
298
+ }
299
+ }
300
+
301
+ template<typename Key, class Comparator>
302
+ typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindLast()
303
+ const {
304
+ Node* x = head_;
305
+ int level = GetMaxHeight() - 1;
306
+ while (true) {
307
+ Node* next = x->Next(level);
308
+ if (next == NULL) {
309
+ if (level == 0) {
310
+ return x;
311
+ } else {
312
+ // Switch to next list
313
+ level--;
314
+ }
315
+ } else {
316
+ x = next;
317
+ }
318
+ }
319
+ }
320
+
321
+ template<typename Key, class Comparator>
322
+ SkipList<Key,Comparator>::SkipList(Comparator cmp, Arena* arena)
323
+ : compare_(cmp),
324
+ arena_(arena),
325
+ head_(NewNode(0 /* any key will do */, kMaxHeight)),
326
+ max_height_(reinterpret_cast<void*>(1)),
327
+ rnd_(0xdeadbeef) {
328
+ for (int i = 0; i < kMaxHeight; i++) {
329
+ head_->SetNext(i, NULL);
330
+ }
331
+ }
332
+
333
+ template<typename Key, class Comparator>
334
+ void SkipList<Key,Comparator>::Insert(const Key& key) {
335
+ // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual()
336
+ // here since Insert() is externally synchronized.
337
+ Node* prev[kMaxHeight];
338
+ Node* x = FindGreaterOrEqual(key, prev);
339
+
340
+ // Our data structure does not allow duplicate insertion
341
+ assert(x == NULL || !Equal(key, x->key));
342
+
343
+ int height = RandomHeight();
344
+ if (height > GetMaxHeight()) {
345
+ for (int i = GetMaxHeight(); i < height; i++) {
346
+ prev[i] = head_;
347
+ }
348
+ //fprintf(stderr, "Change height from %d to %d\n", max_height_, height);
349
+
350
+ // It is ok to mutate max_height_ without any synchronization
351
+ // with concurrent readers. A concurrent reader that observes
352
+ // the new value of max_height_ will see either the old value of
353
+ // new level pointers from head_ (NULL), or a new value set in
354
+ // the loop below. In the former case the reader will
355
+ // immediately drop to the next level since NULL sorts after all
356
+ // keys. In the latter case the reader will use the new node.
357
+ max_height_.NoBarrier_Store(reinterpret_cast<void*>(height));
358
+ }
359
+
360
+ x = NewNode(key, height);
361
+ for (int i = 0; i < height; i++) {
362
+ // NoBarrier_SetNext() suffices since we will add a barrier when
363
+ // we publish a pointer to "x" in prev[i].
364
+ x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));
365
+ prev[i]->SetNext(i, x);
366
+ }
367
+ }
368
+
369
+ template<typename Key, class Comparator>
370
+ bool SkipList<Key,Comparator>::Contains(const Key& key) const {
371
+ Node* x = FindGreaterOrEqual(key, NULL);
372
+ if (x != NULL && Equal(key, x->key)) {
373
+ return true;
374
+ } else {
375
+ return false;
376
+ }
377
+ }
378
+
379
+ } // namespace leveldb
@@ -0,0 +1,378 @@
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 "db/skiplist.h"
6
+ #include <set>
7
+ #include "leveldb/env.h"
8
+ #include "util/arena.h"
9
+ #include "util/hash.h"
10
+ #include "util/random.h"
11
+ #include "util/testharness.h"
12
+
13
+ namespace leveldb {
14
+
15
+ typedef uint64_t Key;
16
+
17
+ struct Comparator {
18
+ int operator()(const Key& a, const Key& b) const {
19
+ if (a < b) {
20
+ return -1;
21
+ } else if (a > b) {
22
+ return +1;
23
+ } else {
24
+ return 0;
25
+ }
26
+ }
27
+ };
28
+
29
+ class SkipTest { };
30
+
31
+ TEST(SkipTest, Empty) {
32
+ Arena arena;
33
+ Comparator cmp;
34
+ SkipList<Key, Comparator> list(cmp, &arena);
35
+ ASSERT_TRUE(!list.Contains(10));
36
+
37
+ SkipList<Key, Comparator>::Iterator iter(&list);
38
+ ASSERT_TRUE(!iter.Valid());
39
+ iter.SeekToFirst();
40
+ ASSERT_TRUE(!iter.Valid());
41
+ iter.Seek(100);
42
+ ASSERT_TRUE(!iter.Valid());
43
+ iter.SeekToLast();
44
+ ASSERT_TRUE(!iter.Valid());
45
+ }
46
+
47
+ TEST(SkipTest, InsertAndLookup) {
48
+ const int N = 2000;
49
+ const int R = 5000;
50
+ Random rnd(1000);
51
+ std::set<Key> keys;
52
+ Arena arena;
53
+ Comparator cmp;
54
+ SkipList<Key, Comparator> list(cmp, &arena);
55
+ for (int i = 0; i < N; i++) {
56
+ Key key = rnd.Next() % R;
57
+ if (keys.insert(key).second) {
58
+ list.Insert(key);
59
+ }
60
+ }
61
+
62
+ for (int i = 0; i < R; i++) {
63
+ if (list.Contains(i)) {
64
+ ASSERT_EQ(keys.count(i), 1);
65
+ } else {
66
+ ASSERT_EQ(keys.count(i), 0);
67
+ }
68
+ }
69
+
70
+ // Simple iterator tests
71
+ {
72
+ SkipList<Key, Comparator>::Iterator iter(&list);
73
+ ASSERT_TRUE(!iter.Valid());
74
+
75
+ iter.Seek(0);
76
+ ASSERT_TRUE(iter.Valid());
77
+ ASSERT_EQ(*(keys.begin()), iter.key());
78
+
79
+ iter.SeekToFirst();
80
+ ASSERT_TRUE(iter.Valid());
81
+ ASSERT_EQ(*(keys.begin()), iter.key());
82
+
83
+ iter.SeekToLast();
84
+ ASSERT_TRUE(iter.Valid());
85
+ ASSERT_EQ(*(keys.rbegin()), iter.key());
86
+ }
87
+
88
+ // Forward iteration test
89
+ for (int i = 0; i < R; i++) {
90
+ SkipList<Key, Comparator>::Iterator iter(&list);
91
+ iter.Seek(i);
92
+
93
+ // Compare against model iterator
94
+ std::set<Key>::iterator model_iter = keys.lower_bound(i);
95
+ for (int j = 0; j < 3; j++) {
96
+ if (model_iter == keys.end()) {
97
+ ASSERT_TRUE(!iter.Valid());
98
+ break;
99
+ } else {
100
+ ASSERT_TRUE(iter.Valid());
101
+ ASSERT_EQ(*model_iter, iter.key());
102
+ ++model_iter;
103
+ iter.Next();
104
+ }
105
+ }
106
+ }
107
+
108
+ // Backward iteration test
109
+ {
110
+ SkipList<Key, Comparator>::Iterator iter(&list);
111
+ iter.SeekToLast();
112
+
113
+ // Compare against model iterator
114
+ for (std::set<Key>::reverse_iterator model_iter = keys.rbegin();
115
+ model_iter != keys.rend();
116
+ ++model_iter) {
117
+ ASSERT_TRUE(iter.Valid());
118
+ ASSERT_EQ(*model_iter, iter.key());
119
+ iter.Prev();
120
+ }
121
+ ASSERT_TRUE(!iter.Valid());
122
+ }
123
+ }
124
+
125
+ // We want to make sure that with a single writer and multiple
126
+ // concurrent readers (with no synchronization other than when a
127
+ // reader's iterator is created), the reader always observes all the
128
+ // data that was present in the skip list when the iterator was
129
+ // constructor. Because insertions are happening concurrently, we may
130
+ // also observe new values that were inserted since the iterator was
131
+ // constructed, but we should never miss any values that were present
132
+ // at iterator construction time.
133
+ //
134
+ // We generate multi-part keys:
135
+ // <key,gen,hash>
136
+ // where:
137
+ // key is in range [0..K-1]
138
+ // gen is a generation number for key
139
+ // hash is hash(key,gen)
140
+ //
141
+ // The insertion code picks a random key, sets gen to be 1 + the last
142
+ // generation number inserted for that key, and sets hash to Hash(key,gen).
143
+ //
144
+ // At the beginning of a read, we snapshot the last inserted
145
+ // generation number for each key. We then iterate, including random
146
+ // calls to Next() and Seek(). For every key we encounter, we
147
+ // check that it is either expected given the initial snapshot or has
148
+ // been concurrently added since the iterator started.
149
+ class ConcurrentTest {
150
+ private:
151
+ static const uint32_t K = 4;
152
+
153
+ static uint64_t key(Key key) { return (key >> 40); }
154
+ static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; }
155
+ static uint64_t hash(Key key) { return key & 0xff; }
156
+
157
+ static uint64_t HashNumbers(uint64_t k, uint64_t g) {
158
+ uint64_t data[2] = { k, g };
159
+ return Hash(reinterpret_cast<char*>(data), sizeof(data), 0);
160
+ }
161
+
162
+ static Key MakeKey(uint64_t k, uint64_t g) {
163
+ assert(sizeof(Key) == sizeof(uint64_t));
164
+ assert(k <= K); // We sometimes pass K to seek to the end of the skiplist
165
+ assert(g <= 0xffffffffu);
166
+ return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff));
167
+ }
168
+
169
+ static bool IsValidKey(Key k) {
170
+ return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff);
171
+ }
172
+
173
+ static Key RandomTarget(Random* rnd) {
174
+ switch (rnd->Next() % 10) {
175
+ case 0:
176
+ // Seek to beginning
177
+ return MakeKey(0, 0);
178
+ case 1:
179
+ // Seek to end
180
+ return MakeKey(K, 0);
181
+ default:
182
+ // Seek to middle
183
+ return MakeKey(rnd->Next() % K, 0);
184
+ }
185
+ }
186
+
187
+ // Per-key generation
188
+ struct State {
189
+ port::AtomicPointer generation[K];
190
+ void Set(int k, intptr_t v) {
191
+ generation[k].Release_Store(reinterpret_cast<void*>(v));
192
+ }
193
+ intptr_t Get(int k) {
194
+ return reinterpret_cast<intptr_t>(generation[k].Acquire_Load());
195
+ }
196
+
197
+ State() {
198
+ for (int k = 0; k < K; k++) {
199
+ Set(k, 0);
200
+ }
201
+ }
202
+ };
203
+
204
+ // Current state of the test
205
+ State current_;
206
+
207
+ Arena arena_;
208
+
209
+ // SkipList is not protected by mu_. We just use a single writer
210
+ // thread to modify it.
211
+ SkipList<Key, Comparator> list_;
212
+
213
+ public:
214
+ ConcurrentTest() : list_(Comparator(), &arena_) { }
215
+
216
+ // REQUIRES: External synchronization
217
+ void WriteStep(Random* rnd) {
218
+ const uint32_t k = rnd->Next() % K;
219
+ const intptr_t g = current_.Get(k) + 1;
220
+ const Key key = MakeKey(k, g);
221
+ list_.Insert(key);
222
+ current_.Set(k, g);
223
+ }
224
+
225
+ void ReadStep(Random* rnd) {
226
+ // Remember the initial committed state of the skiplist.
227
+ State initial_state;
228
+ for (int k = 0; k < K; k++) {
229
+ initial_state.Set(k, current_.Get(k));
230
+ }
231
+
232
+ Key pos = RandomTarget(rnd);
233
+ SkipList<Key, Comparator>::Iterator iter(&list_);
234
+ iter.Seek(pos);
235
+ while (true) {
236
+ Key current;
237
+ if (!iter.Valid()) {
238
+ current = MakeKey(K, 0);
239
+ } else {
240
+ current = iter.key();
241
+ ASSERT_TRUE(IsValidKey(current)) << current;
242
+ }
243
+ ASSERT_LE(pos, current) << "should not go backwards";
244
+
245
+ // Verify that everything in [pos,current) was not present in
246
+ // initial_state.
247
+ while (pos < current) {
248
+ ASSERT_LT(key(pos), K) << pos;
249
+
250
+ // Note that generation 0 is never inserted, so it is ok if
251
+ // <*,0,*> is missing.
252
+ ASSERT_TRUE((gen(pos) == 0) ||
253
+ (gen(pos) > initial_state.Get(key(pos)))
254
+ ) << "key: " << key(pos)
255
+ << "; gen: " << gen(pos)
256
+ << "; initgen: "
257
+ << initial_state.Get(key(pos));
258
+
259
+ // Advance to next key in the valid key space
260
+ if (key(pos) < key(current)) {
261
+ pos = MakeKey(key(pos) + 1, 0);
262
+ } else {
263
+ pos = MakeKey(key(pos), gen(pos) + 1);
264
+ }
265
+ }
266
+
267
+ if (!iter.Valid()) {
268
+ break;
269
+ }
270
+
271
+ if (rnd->Next() % 2) {
272
+ iter.Next();
273
+ pos = MakeKey(key(pos), gen(pos) + 1);
274
+ } else {
275
+ Key new_target = RandomTarget(rnd);
276
+ if (new_target > pos) {
277
+ pos = new_target;
278
+ iter.Seek(new_target);
279
+ }
280
+ }
281
+ }
282
+ }
283
+ };
284
+ const uint32_t ConcurrentTest::K;
285
+
286
+ // Simple test that does single-threaded testing of the ConcurrentTest
287
+ // scaffolding.
288
+ TEST(SkipTest, ConcurrentWithoutThreads) {
289
+ ConcurrentTest test;
290
+ Random rnd(test::RandomSeed());
291
+ for (int i = 0; i < 10000; i++) {
292
+ test.ReadStep(&rnd);
293
+ test.WriteStep(&rnd);
294
+ }
295
+ }
296
+
297
+ class TestState {
298
+ public:
299
+ ConcurrentTest t_;
300
+ int seed_;
301
+ port::AtomicPointer quit_flag_;
302
+
303
+ enum ReaderState {
304
+ STARTING,
305
+ RUNNING,
306
+ DONE
307
+ };
308
+
309
+ explicit TestState(int s)
310
+ : seed_(s),
311
+ quit_flag_(NULL),
312
+ state_(STARTING),
313
+ state_cv_(&mu_) {}
314
+
315
+ void Wait(ReaderState s) {
316
+ mu_.Lock();
317
+ while (state_ != s) {
318
+ state_cv_.Wait();
319
+ }
320
+ mu_.Unlock();
321
+ }
322
+
323
+ void Change(ReaderState s) {
324
+ mu_.Lock();
325
+ state_ = s;
326
+ state_cv_.Signal();
327
+ mu_.Unlock();
328
+ }
329
+
330
+ private:
331
+ port::Mutex mu_;
332
+ ReaderState state_;
333
+ port::CondVar state_cv_;
334
+ };
335
+
336
+ static void ConcurrentReader(void* arg) {
337
+ TestState* state = reinterpret_cast<TestState*>(arg);
338
+ Random rnd(state->seed_);
339
+ int64_t reads = 0;
340
+ state->Change(TestState::RUNNING);
341
+ while (!state->quit_flag_.Acquire_Load()) {
342
+ state->t_.ReadStep(&rnd);
343
+ ++reads;
344
+ }
345
+ state->Change(TestState::DONE);
346
+ }
347
+
348
+ static void RunConcurrent(int run) {
349
+ const int seed = test::RandomSeed() + (run * 100);
350
+ Random rnd(seed);
351
+ const int N = 1000;
352
+ const int kSize = 1000;
353
+ for (int i = 0; i < N; i++) {
354
+ if ((i % 100) == 0) {
355
+ fprintf(stderr, "Run %d of %d\n", i, N);
356
+ }
357
+ TestState state(seed + 1);
358
+ Env::Default()->Schedule(ConcurrentReader, &state);
359
+ state.Wait(TestState::RUNNING);
360
+ for (int i = 0; i < kSize; i++) {
361
+ state.t_.WriteStep(&rnd);
362
+ }
363
+ state.quit_flag_.Release_Store(&state); // Any non-NULL arg will do
364
+ state.Wait(TestState::DONE);
365
+ }
366
+ }
367
+
368
+ TEST(SkipTest, Concurrent1) { RunConcurrent(1); }
369
+ TEST(SkipTest, Concurrent2) { RunConcurrent(2); }
370
+ TEST(SkipTest, Concurrent3) { RunConcurrent(3); }
371
+ TEST(SkipTest, Concurrent4) { RunConcurrent(4); }
372
+ TEST(SkipTest, Concurrent5) { RunConcurrent(5); }
373
+
374
+ } // namespace leveldb
375
+
376
+ int main(int argc, char** argv) {
377
+ return leveldb::test::RunAllTests();
378
+ }