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,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
+ // 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 reinterpret_cast<intptr_t>(max_height_.NoBarrier_Load());
109
+ }
110
+
111
+ // Read/written only by Insert().
112
+ Random rnd_;
113
+
114
+ Node* NewNode(const Key& key, int height);
115
+ int RandomHeight();
116
+ bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); }
117
+
118
+ // Return true if key is greater than the data stored in "n"
119
+ bool KeyIsAfterNode(const Key& key, Node* n) const;
120
+
121
+ // Return the earliest node that comes at or after key.
122
+ // Return NULL if there is no such node.
123
+ //
124
+ // If prev is non-NULL, fills prev[level] with pointer to previous
125
+ // node at "level" for every level in [0..max_height_-1].
126
+ Node* FindGreaterOrEqual(const Key& key, Node** prev) const;
127
+
128
+ // Return the latest node with a key < key.
129
+ // Return head_ if there is no such node.
130
+ Node* FindLessThan(const Key& key) const;
131
+
132
+ // Return the last node in the list.
133
+ // Return head_ if list is empty.
134
+ Node* FindLast() const;
135
+
136
+ // No copying allowed
137
+ SkipList(const SkipList&);
138
+ void operator=(const SkipList&);
139
+ };
140
+
141
+ // Implementation details follow
142
+ template<typename Key, class Comparator>
143
+ struct SkipList<Key,Comparator>::Node {
144
+ explicit Node(const Key& k) : key(k) { }
145
+
146
+ Key const key;
147
+
148
+ // Accessors/mutators for links. Wrapped in methods so we can
149
+ // add the appropriate barriers as necessary.
150
+ Node* Next(int n) {
151
+ assert(n >= 0);
152
+ // Use an 'acquire load' so that we observe a fully initialized
153
+ // version of the returned Node.
154
+ return reinterpret_cast<Node*>(next_[n].Acquire_Load());
155
+ }
156
+ void SetNext(int n, Node* x) {
157
+ assert(n >= 0);
158
+ // Use a 'release store' so that anybody who reads through this
159
+ // pointer observes a fully initialized version of the inserted node.
160
+ next_[n].Release_Store(x);
161
+ }
162
+
163
+ // No-barrier variants that can be safely used in a few locations.
164
+ Node* NoBarrier_Next(int n) {
165
+ assert(n >= 0);
166
+ return reinterpret_cast<Node*>(next_[n].NoBarrier_Load());
167
+ }
168
+ void NoBarrier_SetNext(int n, Node* x) {
169
+ assert(n >= 0);
170
+ next_[n].NoBarrier_Store(x);
171
+ }
172
+
173
+ private:
174
+ // Array of length equal to the node height. next_[0] is lowest level link.
175
+ port::AtomicPointer next_[1];
176
+ };
177
+
178
+ template<typename Key, class Comparator>
179
+ typename SkipList<Key,Comparator>::Node*
180
+ SkipList<Key,Comparator>::NewNode(const Key& key, int height) {
181
+ char* mem = arena_->AllocateAligned(
182
+ sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1));
183
+ return new (mem) Node(key);
184
+ }
185
+
186
+ template<typename Key, class Comparator>
187
+ inline SkipList<Key,Comparator>::Iterator::Iterator(const SkipList* list) {
188
+ list_ = list;
189
+ node_ = NULL;
190
+ }
191
+
192
+ template<typename Key, class Comparator>
193
+ inline bool SkipList<Key,Comparator>::Iterator::Valid() const {
194
+ return node_ != NULL;
195
+ }
196
+
197
+ template<typename Key, class Comparator>
198
+ inline const Key& SkipList<Key,Comparator>::Iterator::key() const {
199
+ assert(Valid());
200
+ return node_->key;
201
+ }
202
+
203
+ template<typename Key, class Comparator>
204
+ inline void SkipList<Key,Comparator>::Iterator::Next() {
205
+ assert(Valid());
206
+ node_ = node_->Next(0);
207
+ }
208
+
209
+ template<typename Key, class Comparator>
210
+ inline void SkipList<Key,Comparator>::Iterator::Prev() {
211
+ // Instead of using explicit "prev" links, we just search for the
212
+ // last node that falls before key.
213
+ assert(Valid());
214
+ node_ = list_->FindLessThan(node_->key);
215
+ if (node_ == list_->head_) {
216
+ node_ = NULL;
217
+ }
218
+ }
219
+
220
+ template<typename Key, class Comparator>
221
+ inline void SkipList<Key,Comparator>::Iterator::Seek(const Key& target) {
222
+ node_ = list_->FindGreaterOrEqual(target, NULL);
223
+ }
224
+
225
+ template<typename Key, class Comparator>
226
+ inline void SkipList<Key,Comparator>::Iterator::SeekToFirst() {
227
+ node_ = list_->head_->Next(0);
228
+ }
229
+
230
+ template<typename Key, class Comparator>
231
+ inline void SkipList<Key,Comparator>::Iterator::SeekToLast() {
232
+ node_ = list_->FindLast();
233
+ if (node_ == list_->head_) {
234
+ node_ = NULL;
235
+ }
236
+ }
237
+
238
+ template<typename Key, class Comparator>
239
+ int SkipList<Key,Comparator>::RandomHeight() {
240
+ // Increase height with probability 1 in kBranching
241
+ static const unsigned int kBranching = 4;
242
+ int height = 1;
243
+ while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) {
244
+ height++;
245
+ }
246
+ assert(height > 0);
247
+ assert(height <= kMaxHeight);
248
+ return height;
249
+ }
250
+
251
+ template<typename Key, class Comparator>
252
+ bool SkipList<Key,Comparator>::KeyIsAfterNode(const Key& key, Node* n) const {
253
+ // NULL n is considered infinite
254
+ return (n != NULL) && (compare_(n->key, key) < 0);
255
+ }
256
+
257
+ template<typename Key, class Comparator>
258
+ typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindGreaterOrEqual(const Key& key, Node** prev)
259
+ const {
260
+ Node* x = head_;
261
+ int level = GetMaxHeight() - 1;
262
+ while (true) {
263
+ Node* next = x->Next(level);
264
+ if (KeyIsAfterNode(key, next)) {
265
+ // Keep searching in this list
266
+ x = next;
267
+ } else {
268
+ if (prev != NULL) prev[level] = x;
269
+ if (level == 0) {
270
+ return next;
271
+ } else {
272
+ // Switch to next list
273
+ level--;
274
+ }
275
+ }
276
+ }
277
+ }
278
+
279
+ template<typename Key, class Comparator>
280
+ typename SkipList<Key,Comparator>::Node*
281
+ SkipList<Key,Comparator>::FindLessThan(const Key& key) const {
282
+ Node* x = head_;
283
+ int level = GetMaxHeight() - 1;
284
+ while (true) {
285
+ assert(x == head_ || compare_(x->key, key) < 0);
286
+ Node* next = x->Next(level);
287
+ if (next == NULL || compare_(next->key, key) >= 0) {
288
+ if (level == 0) {
289
+ return x;
290
+ } else {
291
+ // Switch to next list
292
+ level--;
293
+ }
294
+ } else {
295
+ x = next;
296
+ }
297
+ }
298
+ }
299
+
300
+ template<typename Key, class Comparator>
301
+ typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindLast()
302
+ const {
303
+ Node* x = head_;
304
+ int level = GetMaxHeight() - 1;
305
+ while (true) {
306
+ Node* next = x->Next(level);
307
+ if (next == NULL) {
308
+ if (level == 0) {
309
+ return x;
310
+ } else {
311
+ // Switch to next list
312
+ level--;
313
+ }
314
+ } else {
315
+ x = next;
316
+ }
317
+ }
318
+ }
319
+
320
+ template<typename Key, class Comparator>
321
+ SkipList<Key,Comparator>::SkipList(Comparator cmp, Arena* arena)
322
+ : compare_(cmp),
323
+ arena_(arena),
324
+ head_(NewNode(0 /* any key will do */, kMaxHeight)),
325
+ max_height_(reinterpret_cast<void*>(1)),
326
+ rnd_(0xdeadbeef) {
327
+ for (int i = 0; i < kMaxHeight; i++) {
328
+ head_->SetNext(i, NULL);
329
+ }
330
+ }
331
+
332
+ template<typename Key, class Comparator>
333
+ void SkipList<Key,Comparator>::Insert(const Key& key) {
334
+ // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual()
335
+ // here since Insert() is externally synchronized.
336
+ Node* prev[kMaxHeight];
337
+ Node* x = FindGreaterOrEqual(key, prev);
338
+
339
+ // Our data structure does not allow duplicate insertion
340
+ assert(x == NULL || !Equal(key, x->key));
341
+
342
+ int height = RandomHeight();
343
+ if (height > GetMaxHeight()) {
344
+ for (int i = GetMaxHeight(); i < height; i++) {
345
+ prev[i] = head_;
346
+ }
347
+ //fprintf(stderr, "Change height from %d to %d\n", max_height_, height);
348
+
349
+ // It is ok to mutate max_height_ without any synchronization
350
+ // with concurrent readers. A concurrent reader that observes
351
+ // the new value of max_height_ will see either the old value of
352
+ // new level pointers from head_ (NULL), or a new value set in
353
+ // the loop below. In the former case the reader will
354
+ // immediately drop to the next level since NULL sorts after all
355
+ // keys. In the latter case the reader will use the new node.
356
+ max_height_.NoBarrier_Store(reinterpret_cast<void*>(height));
357
+ }
358
+
359
+ x = NewNode(key, height);
360
+ for (int i = 0; i < height; i++) {
361
+ // NoBarrier_SetNext() suffices since we will add a barrier when
362
+ // we publish a pointer to "x" in prev[i].
363
+ x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));
364
+ prev[i]->SetNext(i, x);
365
+ }
366
+ }
367
+
368
+ template<typename Key, class Comparator>
369
+ bool SkipList<Key,Comparator>::Contains(const Key& key) const {
370
+ Node* x = FindGreaterOrEqual(key, NULL);
371
+ if (x != NULL && Equal(key, x->key)) {
372
+ return true;
373
+ } else {
374
+ return false;
375
+ }
376
+ }
377
+
378
+ }
@@ -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)) << std::hex << 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) << std::hex << 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
+ }
375
+
376
+ int main(int argc, char** argv) {
377
+ return leveldb::test::RunAllTests();
378
+ }