leveldb-ruby 0.1

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 (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,57 @@
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_BLOCK_BUILDER_H_
6
+ #define STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_
7
+
8
+ #include <vector>
9
+
10
+ #include <stdint.h>
11
+ #include "leveldb/slice.h"
12
+
13
+ namespace leveldb {
14
+
15
+ struct Options;
16
+
17
+ class BlockBuilder {
18
+ public:
19
+ explicit BlockBuilder(const Options* options);
20
+
21
+ // Reset the contents as if the BlockBuilder was just constructed.
22
+ void Reset();
23
+
24
+ // REQUIRES: Finish() has not been callled since the last call to Reset().
25
+ // REQUIRES: key is larger than any previously added key
26
+ void Add(const Slice& key, const Slice& value);
27
+
28
+ // Finish building the block and return a slice that refers to the
29
+ // block contents. The returned slice will remain valid for the
30
+ // lifetime of this builder or until Reset() is called.
31
+ Slice Finish();
32
+
33
+ // Returns an estimate of the current (uncompressed) size of the block
34
+ // we are building.
35
+ size_t CurrentSizeEstimate() const;
36
+
37
+ // Return true iff no entries have been added since the last Reset()
38
+ bool empty() const {
39
+ return buffer_.empty();
40
+ }
41
+
42
+ private:
43
+ const Options* options_;
44
+ std::string buffer_; // Destination buffer
45
+ std::vector<uint32_t> restarts_; // Restart points
46
+ int counter_; // Number of entries emitted since restart
47
+ bool finished_; // Has Finish() been called?
48
+ std::string last_key_;
49
+
50
+ // No copying allowed
51
+ BlockBuilder(const BlockBuilder&);
52
+ void operator=(const BlockBuilder&);
53
+ };
54
+
55
+ }
56
+
57
+ #endif // STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_
@@ -0,0 +1,131 @@
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/format.h"
6
+
7
+ #include "leveldb/env.h"
8
+ #include "port/port.h"
9
+ #include "table/block.h"
10
+ #include "util/coding.h"
11
+ #include "util/crc32c.h"
12
+
13
+ namespace leveldb {
14
+
15
+ void BlockHandle::EncodeTo(std::string* dst) const {
16
+ // Sanity check that all fields have been set
17
+ assert(offset_ != ~static_cast<uint64_t>(0));
18
+ assert(size_ != ~static_cast<uint64_t>(0));
19
+ PutVarint64(dst, offset_);
20
+ PutVarint64(dst, size_);
21
+ }
22
+
23
+ Status BlockHandle::DecodeFrom(Slice* input) {
24
+ if (GetVarint64(input, &offset_) &&
25
+ GetVarint64(input, &size_)) {
26
+ return Status::OK();
27
+ } else {
28
+ return Status::Corruption("bad block handle");
29
+ }
30
+ }
31
+
32
+ void Footer::EncodeTo(std::string* dst) const {
33
+ #ifndef NDEBUG
34
+ const size_t original_size = dst->size();
35
+ #endif
36
+ metaindex_handle_.EncodeTo(dst);
37
+ index_handle_.EncodeTo(dst);
38
+ dst->resize(2 * BlockHandle::kMaxEncodedLength); // Padding
39
+ PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber & 0xffffffffu));
40
+ PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber >> 32));
41
+ assert(dst->size() == original_size + kEncodedLength);
42
+ }
43
+
44
+ Status Footer::DecodeFrom(Slice* input) {
45
+ const char* magic_ptr = input->data() + kEncodedLength - 8;
46
+ const uint32_t magic_lo = DecodeFixed32(magic_ptr);
47
+ const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4);
48
+ const uint64_t magic = ((static_cast<uint64_t>(magic_hi) << 32) |
49
+ (static_cast<uint64_t>(magic_lo)));
50
+ if (magic != kTableMagicNumber) {
51
+ return Status::InvalidArgument("not an sstable (bad magic number)");
52
+ }
53
+
54
+ Status result = metaindex_handle_.DecodeFrom(input);
55
+ if (result.ok()) {
56
+ result = index_handle_.DecodeFrom(input);
57
+ }
58
+ if (result.ok()) {
59
+ // We skip over any leftover data (just padding for now) in "input"
60
+ const char* end = magic_ptr + 8;
61
+ *input = Slice(end, input->data() + input->size() - end);
62
+ }
63
+ return result;
64
+ }
65
+
66
+ Status ReadBlock(RandomAccessFile* file,
67
+ const ReadOptions& options,
68
+ const BlockHandle& handle,
69
+ Block** block) {
70
+ *block = NULL;
71
+
72
+ // Read the block contents as well as the type/crc footer.
73
+ // See table_builder.cc for the code that built this structure.
74
+ size_t n = static_cast<size_t>(handle.size());
75
+ char* buf = new char[n + kBlockTrailerSize];
76
+ Slice contents;
77
+ Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf);
78
+ if (!s.ok()) {
79
+ delete[] buf;
80
+ return s;
81
+ }
82
+ if (contents.size() != n + kBlockTrailerSize) {
83
+ delete[] buf;
84
+ return Status::Corruption("truncated block read");
85
+ }
86
+
87
+ // Check the crc of the type and the block contents
88
+ const char* data = contents.data(); // Pointer to where Read put the data
89
+ if (options.verify_checksums) {
90
+ const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1));
91
+ const uint32_t actual = crc32c::Value(data, n + 1);
92
+ if (actual != crc) {
93
+ delete[] buf;
94
+ s = Status::Corruption("block checksum mismatch");
95
+ return s;
96
+ }
97
+ }
98
+
99
+ switch (data[n]) {
100
+ case kNoCompression:
101
+ if (data != buf) {
102
+ // File implementation gave us pointer to some other data.
103
+ // Copy into buf[].
104
+ memcpy(buf, data, n + kBlockTrailerSize);
105
+ }
106
+
107
+ // Ok
108
+ break;
109
+ case kSnappyCompression: {
110
+ std::string decompressed;
111
+ if (!port::Snappy_Uncompress(data, n, &decompressed)) {
112
+ delete[] buf;
113
+ s = Status::Corruption("corrupted compressed block contents");
114
+ return s;
115
+ }
116
+ delete[] buf; // Done with uncompressed data
117
+ buf = new char[decompressed.size()];
118
+ memcpy(buf, decompressed.data(), decompressed.size());
119
+ n = decompressed.size();
120
+ break;
121
+ }
122
+ default:
123
+ delete[] buf;
124
+ return Status::Corruption("bad block type");
125
+ }
126
+
127
+ *block = new Block(buf, n); // Block takes ownership of buf[]
128
+ return Status::OK();
129
+ }
130
+
131
+ }
@@ -0,0 +1,103 @@
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_FORMAT_H_
6
+ #define STORAGE_LEVELDB_TABLE_FORMAT_H_
7
+
8
+ #include <string>
9
+ #include <stdint.h>
10
+ #include "leveldb/slice.h"
11
+ #include "leveldb/status.h"
12
+ #include "leveldb/table_builder.h"
13
+
14
+ namespace leveldb {
15
+
16
+ class Block;
17
+ class RandomAccessFile;
18
+ struct ReadOptions;
19
+
20
+ // BlockHandle is a pointer to the extent of a file that stores a data
21
+ // block or a meta block.
22
+ class BlockHandle {
23
+ public:
24
+ BlockHandle();
25
+
26
+ // The offset of the block in the file.
27
+ uint64_t offset() const { return offset_; }
28
+ void set_offset(uint64_t offset) { offset_ = offset; }
29
+
30
+ // The size of the stored block
31
+ uint64_t size() const { return size_; }
32
+ void set_size(uint64_t size) { size_ = size; }
33
+
34
+ void EncodeTo(std::string* dst) const;
35
+ Status DecodeFrom(Slice* input);
36
+
37
+ // Maximum encoding length of a BlockHandle
38
+ enum { kMaxEncodedLength = 10 + 10 };
39
+
40
+ private:
41
+ uint64_t offset_;
42
+ uint64_t size_;
43
+ };
44
+
45
+ // Footer encapsulates the fixed information stored at the tail
46
+ // end of every table file.
47
+ class Footer {
48
+ public:
49
+ Footer() { }
50
+
51
+ // The block handle for the metaindex block of the table
52
+ const BlockHandle& metaindex_handle() const { return metaindex_handle_; }
53
+ void set_metaindex_handle(const BlockHandle& h) { metaindex_handle_ = h; }
54
+
55
+ // The block handle for the index block of the table
56
+ const BlockHandle& index_handle() const {
57
+ return index_handle_;
58
+ }
59
+ void set_index_handle(const BlockHandle& h) {
60
+ index_handle_ = h;
61
+ }
62
+
63
+ void EncodeTo(std::string* dst) const;
64
+ Status DecodeFrom(Slice* input);
65
+
66
+ // Encoded length of a Footer. Note that the serialization of a
67
+ // Footer will always occupy exactly this many bytes. It consists
68
+ // of two block handles and a magic number.
69
+ enum {
70
+ kEncodedLength = 2*BlockHandle::kMaxEncodedLength + 8
71
+ };
72
+
73
+ private:
74
+ BlockHandle metaindex_handle_;
75
+ BlockHandle index_handle_;
76
+ };
77
+
78
+ // kTableMagicNumber was picked by running
79
+ // echo http://code.google.com/p/leveldb/ | sha1sum
80
+ // and taking the leading 64 bits.
81
+ static const uint64_t kTableMagicNumber = 0xdb4775248b80fb57ull;
82
+
83
+ // 1-byte type + 32-bit crc
84
+ static const size_t kBlockTrailerSize = 5;
85
+
86
+ // Read the block identified by "handle" from "file". On success,
87
+ // store a pointer to the heap-allocated result in *block and return
88
+ // OK. On failure store NULL in *block and return non-OK.
89
+ extern Status ReadBlock(RandomAccessFile* file,
90
+ const ReadOptions& options,
91
+ const BlockHandle& handle,
92
+ Block** block);
93
+
94
+ // Implementation details follow. Clients should ignore,
95
+
96
+ inline BlockHandle::BlockHandle()
97
+ : offset_(~static_cast<uint64_t>(0)),
98
+ size_(~static_cast<uint64_t>(0)) {
99
+ }
100
+
101
+ }
102
+
103
+ #endif // STORAGE_LEVELDB_TABLE_FORMAT_H_
@@ -0,0 +1,67 @@
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 "leveldb/iterator.h"
6
+
7
+ namespace leveldb {
8
+
9
+ Iterator::Iterator() {
10
+ cleanup_.function = NULL;
11
+ cleanup_.next = NULL;
12
+ }
13
+
14
+ Iterator::~Iterator() {
15
+ if (cleanup_.function != NULL) {
16
+ (*cleanup_.function)(cleanup_.arg1, cleanup_.arg2);
17
+ for (Cleanup* c = cleanup_.next; c != NULL; ) {
18
+ (*c->function)(c->arg1, c->arg2);
19
+ Cleanup* next = c->next;
20
+ delete c;
21
+ c = next;
22
+ }
23
+ }
24
+ }
25
+
26
+ void Iterator::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) {
27
+ assert(func != NULL);
28
+ Cleanup* c;
29
+ if (cleanup_.function == NULL) {
30
+ c = &cleanup_;
31
+ } else {
32
+ c = new Cleanup;
33
+ c->next = cleanup_.next;
34
+ cleanup_.next = c;
35
+ }
36
+ c->function = func;
37
+ c->arg1 = arg1;
38
+ c->arg2 = arg2;
39
+ }
40
+
41
+ namespace {
42
+ class EmptyIterator : public Iterator {
43
+ public:
44
+ EmptyIterator(const Status& s) : status_(s) { }
45
+ virtual bool Valid() const { return false; }
46
+ virtual void Seek(const Slice& target) { }
47
+ virtual void SeekToFirst() { }
48
+ virtual void SeekToLast() { }
49
+ virtual void Next() { assert(false); }
50
+ virtual void Prev() { assert(false); }
51
+ Slice key() const { assert(false); return Slice(); }
52
+ Slice value() const { assert(false); return Slice(); }
53
+ virtual Status status() const { return status_; }
54
+ private:
55
+ Status status_;
56
+ };
57
+ }
58
+
59
+ Iterator* NewEmptyIterator() {
60
+ return new EmptyIterator(Status::OK());
61
+ }
62
+
63
+ Iterator* NewErrorIterator(const Status& status) {
64
+ return new EmptyIterator(status);
65
+ }
66
+
67
+ }
@@ -0,0 +1,63 @@
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_ITERATOR_WRAPPER_H_
6
+ #define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_
7
+
8
+ namespace leveldb {
9
+
10
+ // A internal wrapper class with an interface similar to Iterator that
11
+ // caches the valid() and key() results for an underlying iterator.
12
+ // This can help avoid virtual function calls and also gives better
13
+ // cache locality.
14
+ class IteratorWrapper {
15
+ public:
16
+ IteratorWrapper(): iter_(NULL), valid_(false) { }
17
+ explicit IteratorWrapper(Iterator* iter): iter_(NULL) {
18
+ Set(iter);
19
+ }
20
+ ~IteratorWrapper() { delete iter_; }
21
+ Iterator* iter() const { return iter_; }
22
+
23
+ // Takes ownership of "iter" and will delete it when destroyed, or
24
+ // when Set() is invoked again.
25
+ void Set(Iterator* iter) {
26
+ delete iter_;
27
+ iter_ = iter;
28
+ if (iter_ == NULL) {
29
+ valid_ = false;
30
+ } else {
31
+ Update();
32
+ }
33
+ }
34
+
35
+
36
+ // Iterator interface methods
37
+ bool Valid() const { return valid_; }
38
+ Slice key() const { assert(Valid()); return key_; }
39
+ Slice value() const { assert(Valid()); return iter_->value(); }
40
+ // Methods below require iter() != NULL
41
+ Status status() const { assert(iter_); return iter_->status(); }
42
+ void Next() { assert(iter_); iter_->Next(); Update(); }
43
+ void Prev() { assert(iter_); iter_->Prev(); Update(); }
44
+ void Seek(const Slice& k) { assert(iter_); iter_->Seek(k); Update(); }
45
+ void SeekToFirst() { assert(iter_); iter_->SeekToFirst(); Update(); }
46
+ void SeekToLast() { assert(iter_); iter_->SeekToLast(); Update(); }
47
+
48
+ private:
49
+ void Update() {
50
+ valid_ = iter_->Valid();
51
+ if (valid_) {
52
+ key_ = iter_->key();
53
+ }
54
+ }
55
+
56
+ Iterator* iter_;
57
+ bool valid_;
58
+ Slice key_;
59
+ };
60
+
61
+ } // namespace leveldb
62
+
63
+ #endif // STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_
@@ -0,0 +1,197 @@
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/merger.h"
6
+
7
+ #include "leveldb/comparator.h"
8
+ #include "leveldb/iterator.h"
9
+ #include "table/iterator_wrapper.h"
10
+
11
+ namespace leveldb {
12
+
13
+ namespace {
14
+ class MergingIterator : public Iterator {
15
+ public:
16
+ MergingIterator(const Comparator* comparator, Iterator** children, int n)
17
+ : comparator_(comparator),
18
+ children_(new IteratorWrapper[n]),
19
+ n_(n),
20
+ current_(NULL),
21
+ direction_(kForward) {
22
+ for (int i = 0; i < n; i++) {
23
+ children_[i].Set(children[i]);
24
+ }
25
+ }
26
+
27
+ virtual ~MergingIterator() {
28
+ delete[] children_;
29
+ }
30
+
31
+ virtual bool Valid() const {
32
+ return (current_ != NULL);
33
+ }
34
+
35
+ virtual void SeekToFirst() {
36
+ for (int i = 0; i < n_; i++) {
37
+ children_[i].SeekToFirst();
38
+ }
39
+ FindSmallest();
40
+ direction_ = kForward;
41
+ }
42
+
43
+ virtual void SeekToLast() {
44
+ for (int i = 0; i < n_; i++) {
45
+ children_[i].SeekToLast();
46
+ }
47
+ FindLargest();
48
+ direction_ = kReverse;
49
+ }
50
+
51
+ virtual void Seek(const Slice& target) {
52
+ for (int i = 0; i < n_; i++) {
53
+ children_[i].Seek(target);
54
+ }
55
+ FindSmallest();
56
+ direction_ = kForward;
57
+ }
58
+
59
+ virtual void Next() {
60
+ assert(Valid());
61
+
62
+ // Ensure that all children are positioned after key().
63
+ // If we are moving in the forward direction, it is already
64
+ // true for all of the non-current_ children since current_ is
65
+ // the smallest child and key() == current_->key(). Otherwise,
66
+ // we explicitly position the non-current_ children.
67
+ if (direction_ != kForward) {
68
+ for (int i = 0; i < n_; i++) {
69
+ IteratorWrapper* child = &children_[i];
70
+ if (child != current_) {
71
+ child->Seek(key());
72
+ if (child->Valid() &&
73
+ comparator_->Compare(key(), child->key()) == 0) {
74
+ child->Next();
75
+ }
76
+ }
77
+ }
78
+ direction_ = kForward;
79
+ }
80
+
81
+ current_->Next();
82
+ FindSmallest();
83
+ }
84
+
85
+ virtual void Prev() {
86
+ assert(Valid());
87
+
88
+ // Ensure that all children are positioned before key().
89
+ // If we are moving in the reverse direction, it is already
90
+ // true for all of the non-current_ children since current_ is
91
+ // the largest child and key() == current_->key(). Otherwise,
92
+ // we explicitly position the non-current_ children.
93
+ if (direction_ != kReverse) {
94
+ for (int i = 0; i < n_; i++) {
95
+ IteratorWrapper* child = &children_[i];
96
+ if (child != current_) {
97
+ child->Seek(key());
98
+ if (child->Valid()) {
99
+ // Child is at first entry >= key(). Step back one to be < key()
100
+ child->Prev();
101
+ } else {
102
+ // Child has no entries >= key(). Position at last entry.
103
+ child->SeekToLast();
104
+ }
105
+ }
106
+ }
107
+ direction_ = kReverse;
108
+ }
109
+
110
+ current_->Prev();
111
+ FindLargest();
112
+ }
113
+
114
+ virtual Slice key() const {
115
+ assert(Valid());
116
+ return current_->key();
117
+ }
118
+
119
+ virtual Slice value() const {
120
+ assert(Valid());
121
+ return current_->value();
122
+ }
123
+
124
+ virtual Status status() const {
125
+ Status status;
126
+ for (int i = 0; i < n_; i++) {
127
+ status = children_[i].status();
128
+ if (!status.ok()) {
129
+ break;
130
+ }
131
+ }
132
+ return status;
133
+ }
134
+
135
+ private:
136
+ void FindSmallest();
137
+ void FindLargest();
138
+
139
+ // We might want to use a heap in case there are lots of children.
140
+ // For now we use a simple array since we expect a very small number
141
+ // of children in leveldb.
142
+ const Comparator* comparator_;
143
+ IteratorWrapper* children_;
144
+ int n_;
145
+ IteratorWrapper* current_;
146
+
147
+ // Which direction is the iterator moving?
148
+ enum Direction {
149
+ kForward,
150
+ kReverse
151
+ };
152
+ Direction direction_;
153
+ };
154
+
155
+ void MergingIterator::FindSmallest() {
156
+ IteratorWrapper* smallest = NULL;
157
+ for (int i = 0; i < n_; i++) {
158
+ IteratorWrapper* child = &children_[i];
159
+ if (child->Valid()) {
160
+ if (smallest == NULL) {
161
+ smallest = child;
162
+ } else if (comparator_->Compare(child->key(), smallest->key()) < 0) {
163
+ smallest = child;
164
+ }
165
+ }
166
+ }
167
+ current_ = smallest;
168
+ }
169
+
170
+ void MergingIterator::FindLargest() {
171
+ IteratorWrapper* largest = NULL;
172
+ for (int i = n_-1; i >= 0; i--) {
173
+ IteratorWrapper* child = &children_[i];
174
+ if (child->Valid()) {
175
+ if (largest == NULL) {
176
+ largest = child;
177
+ } else if (comparator_->Compare(child->key(), largest->key()) > 0) {
178
+ largest = child;
179
+ }
180
+ }
181
+ }
182
+ current_ = largest;
183
+ }
184
+ }
185
+
186
+ Iterator* NewMergingIterator(const Comparator* cmp, Iterator** list, int n) {
187
+ assert(n >= 0);
188
+ if (n == 0) {
189
+ return NewEmptyIterator();
190
+ } else if (n == 1) {
191
+ return list[0];
192
+ } else {
193
+ return new MergingIterator(cmp, list, n);
194
+ }
195
+ }
196
+
197
+ }