/bitcoin/src/leveldb/table/two_level_iterator.cc
Line | Count | Source |
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 | 376 | bool Valid() const override { return data_iter_.Valid(); } |
32 | 78 | Slice key() const override { |
33 | 78 | assert(Valid()); Branch (33:5): [True: 78, False: 0]
|
34 | 78 | return data_iter_.key(); |
35 | 78 | } |
36 | 114 | Slice value() const override { |
37 | 114 | assert(Valid()); Branch (37:5): [True: 114, False: 0]
|
38 | 114 | return data_iter_.value(); |
39 | 114 | } |
40 | 31 | Status status() const override { |
41 | | // It'd be nice if status() returned a const Status& instead of a Status |
42 | 31 | if (!index_iter_.status().ok()) { Branch (42:9): [True: 0, False: 31]
|
43 | 0 | return index_iter_.status(); |
44 | 31 | } else if (data_iter_.iter() != nullptr && !data_iter_.status().ok()) { Branch (44:16): [True: 0, False: 31]
Branch (44:16): [True: 0, False: 31]
Branch (44:48): [True: 0, False: 0]
|
45 | 0 | return data_iter_.status(); |
46 | 31 | } else { |
47 | 31 | return status_; |
48 | 31 | } |
49 | 31 | } |
50 | | |
51 | | private: |
52 | 14 | void SaveError(const Status& s) { |
53 | 14 | if (status_.ok() && !s.ok()) status_ = s; Branch (53:9): [True: 14, False: 0]
Branch (53:25): [True: 0, False: 14]
|
54 | 14 | } |
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 | 38 | : block_function_(block_function), |
75 | 38 | arg_(arg), |
76 | 38 | options_(options), |
77 | 38 | index_iter_(index_iter), |
78 | 38 | data_iter_(nullptr) {} |
79 | | |
80 | 38 | TwoLevelIterator::~TwoLevelIterator() = default; |
81 | | |
82 | 14 | void TwoLevelIterator::Seek(const Slice& target) { |
83 | 14 | index_iter_.Seek(target); |
84 | 14 | InitDataBlock(); |
85 | 14 | if (data_iter_.iter() != nullptr) data_iter_.Seek(target); Branch (85:7): [True: 14, False: 0]
|
86 | 14 | SkipEmptyDataBlocksForward(); |
87 | 14 | } |
88 | | |
89 | 0 | void TwoLevelIterator::SeekToFirst() { |
90 | 0 | index_iter_.SeekToFirst(); |
91 | 0 | InitDataBlock(); |
92 | 0 | if (data_iter_.iter() != nullptr) data_iter_.SeekToFirst(); Branch (92:7): [True: 0, False: 0]
|
93 | 0 | SkipEmptyDataBlocksForward(); |
94 | 0 | } |
95 | | |
96 | 0 | void TwoLevelIterator::SeekToLast() { |
97 | 0 | index_iter_.SeekToLast(); |
98 | 0 | InitDataBlock(); |
99 | 0 | if (data_iter_.iter() != nullptr) data_iter_.SeekToLast(); Branch (99:7): [True: 0, False: 0]
|
100 | 0 | SkipEmptyDataBlocksBackward(); |
101 | 0 | } |
102 | | |
103 | 78 | void TwoLevelIterator::Next() { |
104 | 78 | assert(Valid()); Branch (104:3): [True: 78, False: 0]
|
105 | 78 | data_iter_.Next(); |
106 | 78 | SkipEmptyDataBlocksForward(); |
107 | 78 | } |
108 | | |
109 | 0 | void TwoLevelIterator::Prev() { |
110 | 0 | assert(Valid()); Branch (110:3): [True: 0, False: 0]
|
111 | 0 | data_iter_.Prev(); |
112 | 0 | SkipEmptyDataBlocksBackward(); |
113 | 0 | } |
114 | | |
115 | 92 | void TwoLevelIterator::SkipEmptyDataBlocksForward() { |
116 | 106 | while (data_iter_.iter() == nullptr || !data_iter_.Valid()) { Branch (116:10): [True: 14, False: 92]
Branch (116:42): [True: 14, False: 78]
|
117 | | // Move to next block |
118 | 28 | if (!index_iter_.Valid()) { Branch (118:9): [True: 14, False: 14]
|
119 | 14 | SetDataIterator(nullptr); |
120 | 14 | return; |
121 | 14 | } |
122 | 14 | index_iter_.Next(); |
123 | 14 | InitDataBlock(); |
124 | 14 | if (data_iter_.iter() != nullptr) data_iter_.SeekToFirst(); Branch (124:9): [True: 0, False: 14]
|
125 | 14 | } |
126 | 92 | } |
127 | | |
128 | 0 | void TwoLevelIterator::SkipEmptyDataBlocksBackward() { |
129 | 0 | while (data_iter_.iter() == nullptr || !data_iter_.Valid()) { Branch (129:10): [True: 0, False: 0]
Branch (129:42): [True: 0, False: 0]
|
130 | | // Move to next block |
131 | 0 | if (!index_iter_.Valid()) { Branch (131:9): [True: 0, False: 0]
|
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(); Branch (137:9): [True: 0, False: 0]
|
138 | 0 | } |
139 | 0 | } |
140 | | |
141 | 42 | void TwoLevelIterator::SetDataIterator(Iterator* data_iter) { |
142 | 42 | if (data_iter_.iter() != nullptr) SaveError(data_iter_.status()); Branch (142:7): [True: 14, False: 28]
|
143 | 42 | data_iter_.Set(data_iter); |
144 | 42 | } |
145 | | |
146 | 28 | void TwoLevelIterator::InitDataBlock() { |
147 | 28 | if (!index_iter_.Valid()) { Branch (147:7): [True: 14, False: 14]
|
148 | 14 | SetDataIterator(nullptr); |
149 | 14 | } else { |
150 | 14 | Slice handle = index_iter_.value(); |
151 | 14 | if (data_iter_.iter() != nullptr && Branch (151:9): [True: 0, False: 14]
Branch (151:9): [True: 0, False: 14]
|
152 | 14 | handle.compare(data_block_handle_) == 0) { Branch (152:9): [True: 0, False: 0]
|
153 | | // data_iter_ is already constructed with this iterator, so |
154 | | // no need to change anything |
155 | 14 | } else { |
156 | 14 | Iterator* iter = (*block_function_)(arg_, options_, handle); |
157 | 14 | data_block_handle_.assign(handle.data(), handle.size()); |
158 | 14 | SetDataIterator(iter); |
159 | 14 | } |
160 | 14 | } |
161 | 28 | } |
162 | | |
163 | | } // namespace |
164 | | |
165 | | Iterator* NewTwoLevelIterator(Iterator* index_iter, |
166 | | BlockFunction block_function, void* arg, |
167 | 38 | const ReadOptions& options) { |
168 | 38 | return new TwoLevelIterator(index_iter, block_function, arg, options); |
169 | 38 | } |
170 | | |
171 | | } // namespace leveldb |