/src/leveldb/table/two_level_iterator.cc
Line | Count | Source (jump to first uncovered line) |
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(Iterator* index_iter, BlockFunction block_function, |
21 | | void* arg, const ReadOptions& options); |
22 | | |
23 | | ~TwoLevelIterator() override; |
24 | | |
25 | | void Seek(const Slice& target) override; |
26 | | void SeekToFirst() override; |
27 | | void SeekToLast() override; |
28 | | void Next() override; |
29 | | void Prev() override; |
30 | | |
31 | 10.6M | bool Valid() const override { return data_iter_.Valid(); } |
32 | 9.15M | Slice key() const override { |
33 | 9.15M | assert(Valid()); |
34 | 9.15M | return data_iter_.key(); |
35 | 9.15M | } |
36 | 8.00M | Slice value() const override { |
37 | 8.00M | assert(Valid()); |
38 | 8.00M | return data_iter_.value(); |
39 | 8.00M | } |
40 | 524k | Status status() const override { |
41 | | // It'd be nice if status() returned a const Status& instead of a Status |
42 | 524k | if (!index_iter_.status().ok()) { |
43 | 0 | return index_iter_.status(); |
44 | 524k | } else if (data_iter_.iter() != nullptr && !data_iter_.status().ok()) { |
45 | 0 | return data_iter_.status(); |
46 | 524k | } else { |
47 | 524k | return status_; |
48 | 524k | } |
49 | 524k | } |
50 | | |
51 | | private: |
52 | 935k | void SaveError(const Status& s) { |
53 | 935k | if (status_.ok() && !s.ok()) status_ = s; |
54 | 935k | } |
55 | | void SkipEmptyDataBlocksForward(); |
56 | | void SkipEmptyDataBlocksBackward(); |
57 | | void SetDataIterator(Iterator* data_iter); |
58 | | void InitDataBlock(); |
59 | | |
60 | | BlockFunction block_function_; |
61 | | void* arg_; |
62 | | const ReadOptions options_; |
63 | | Status status_; |
64 | | IteratorWrapper index_iter_; |
65 | | IteratorWrapper data_iter_; // May be nullptr |
66 | | // If data_iter_ is non-null, then "data_block_handle_" holds the |
67 | | // "index_value" passed to block_function_ to create the data_iter_. |
68 | | std::string data_block_handle_; |
69 | | }; |
70 | | |
71 | | TwoLevelIterator::TwoLevelIterator(Iterator* index_iter, |
72 | | BlockFunction block_function, void* arg, |
73 | | const ReadOptions& options) |
74 | 989k | : block_function_(block_function), |
75 | 989k | arg_(arg), |
76 | 989k | options_(options), |
77 | 989k | index_iter_(index_iter), |
78 | 989k | data_iter_(nullptr) {} |
79 | | |
80 | 989k | TwoLevelIterator::~TwoLevelIterator() = default; |
81 | | |
82 | 0 | void TwoLevelIterator::Seek(const Slice& target) { |
83 | 0 | index_iter_.Seek(target); |
84 | 0 | InitDataBlock(); |
85 | 0 | if (data_iter_.iter() != nullptr) data_iter_.Seek(target); |
86 | 0 | SkipEmptyDataBlocksForward(); |
87 | 0 | } |
88 | | |
89 | 652k | void TwoLevelIterator::SeekToFirst() { |
90 | 652k | index_iter_.SeekToFirst(); |
91 | 652k | InitDataBlock(); |
92 | 652k | if (data_iter_.iter() != nullptr) data_iter_.SeekToFirst(); |
93 | 652k | SkipEmptyDataBlocksForward(); |
94 | 652k | } |
95 | | |
96 | 0 | void TwoLevelIterator::SeekToLast() { |
97 | 0 | index_iter_.SeekToLast(); |
98 | 0 | InitDataBlock(); |
99 | 0 | if (data_iter_.iter() != nullptr) data_iter_.SeekToLast(); |
100 | 0 | SkipEmptyDataBlocksBackward(); |
101 | 0 | } |
102 | | |
103 | 9.12M | void TwoLevelIterator::Next() { |
104 | 9.12M | assert(Valid()); |
105 | 9.12M | data_iter_.Next(); |
106 | 9.12M | SkipEmptyDataBlocksForward(); |
107 | 9.12M | } |
108 | | |
109 | 0 | void TwoLevelIterator::Prev() { |
110 | 0 | assert(Valid()); |
111 | 0 | data_iter_.Prev(); |
112 | 0 | SkipEmptyDataBlocksBackward(); |
113 | 0 | } |
114 | | |
115 | 9.75M | void TwoLevelIterator::SkipEmptyDataBlocksForward() { |
116 | 10.6M | while (data_iter_.iter() == nullptr || !data_iter_.Valid()) { |
117 | | // Move to next block |
118 | 1.54M | if (!index_iter_.Valid()) { |
119 | 605k | SetDataIterator(nullptr); |
120 | 605k | return; |
121 | 605k | } |
122 | 935k | index_iter_.Next(); |
123 | 935k | InitDataBlock(); |
124 | 935k | if (data_iter_.iter() != nullptr) data_iter_.SeekToFirst(); |
125 | 935k | } |
126 | 9.75M | } |
127 | | |
128 | 0 | void TwoLevelIterator::SkipEmptyDataBlocksBackward() { |
129 | 0 | while (data_iter_.iter() == nullptr || !data_iter_.Valid()) { |
130 | | // Move to next block |
131 | 0 | if (!index_iter_.Valid()) { |
132 | 0 | SetDataIterator(nullptr); |
133 | 0 | return; |
134 | 0 | } |
135 | 0 | index_iter_.Prev(); |
136 | 0 | InitDataBlock(); |
137 | 0 | if (data_iter_.iter() != nullptr) data_iter_.SeekToLast(); |
138 | 0 | } |
139 | 0 | } |
140 | | |
141 | 2.19M | void TwoLevelIterator::SetDataIterator(Iterator* data_iter) { |
142 | 2.19M | if (data_iter_.iter() != nullptr) SaveError(data_iter_.status()); |
143 | 2.19M | data_iter_.Set(data_iter); |
144 | 2.19M | } |
145 | | |
146 | 1.58M | void TwoLevelIterator::InitDataBlock() { |
147 | 1.58M | if (!index_iter_.Valid()) { |
148 | 605k | SetDataIterator(nullptr); |
149 | 982k | } else { |
150 | 982k | Slice handle = index_iter_.value(); |
151 | 982k | if (data_iter_.iter() != nullptr && |
152 | 982k | handle.compare(data_block_handle_) == 0) { |
153 | | // data_iter_ is already constructed with this iterator, so |
154 | | // no need to change anything |
155 | 982k | } else { |
156 | 982k | Iterator* iter = (*block_function_)(arg_, options_, handle); |
157 | 982k | data_block_handle_.assign(handle.data(), handle.size()); |
158 | 982k | SetDataIterator(iter); |
159 | 982k | } |
160 | 982k | } |
161 | 1.58M | } |
162 | | |
163 | | } // namespace |
164 | | |
165 | | Iterator* NewTwoLevelIterator(Iterator* index_iter, |
166 | | BlockFunction block_function, void* arg, |
167 | 989k | const ReadOptions& options) { |
168 | 989k | return new TwoLevelIterator(index_iter, block_function, arg, options); |
169 | 989k | } |
170 | | |
171 | | } // namespace leveldb |