/Users/deen/code/yugabyte-db/src/yb/rocksdb/table/two_level_iterator.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under the BSD-style license found in the |
3 | | // LICENSE file in the root directory of this source tree. An additional grant |
4 | | // of patent rights can be found in the PATENTS file in the same directory. |
5 | | // |
6 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
21 | | // Use of this source code is governed by a BSD-style license that can be |
22 | | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
23 | | |
24 | | #include "yb/rocksdb/table/two_level_iterator.h" |
25 | | |
26 | | #include "yb/rocksdb/table/iterator_wrapper.h" |
27 | | #include "yb/rocksdb/util/arena.h" |
28 | | |
29 | | namespace rocksdb { |
30 | | |
31 | | namespace { |
32 | | |
33 | | class TwoLevelIterator : public InternalIterator { |
34 | | public: |
35 | | explicit TwoLevelIterator(TwoLevelIteratorState* state, |
36 | | InternalIterator* first_level_iter, |
37 | | bool need_free_iter_and_state); |
38 | | |
39 | 14.6M | virtual ~TwoLevelIterator() { |
40 | 14.6M | first_level_iter_.DeleteIter(!need_free_iter_and_state_); |
41 | 14.6M | second_level_iter_.DeleteIter(false); |
42 | 14.6M | if (need_free_iter_and_state_) { |
43 | 14.6M | delete state_; |
44 | 14.6M | } else { |
45 | 12.2k | state_->~TwoLevelIteratorState(); |
46 | 12.2k | } |
47 | 14.6M | } |
48 | | |
49 | | void Seek(const Slice& target) override; |
50 | | void SeekToFirst() override; |
51 | | void SeekToLast() override; |
52 | | void Next() override; |
53 | | void Prev() override; |
54 | | |
55 | 4.57G | bool Valid() const override { return second_level_iter_.Valid(); } |
56 | 833M | Slice key() const override { |
57 | 833M | assert(Valid()); |
58 | 0 | return second_level_iter_.key(); |
59 | 833M | } |
60 | 2.15G | Slice value() const override { |
61 | 2.15G | assert(Valid()); |
62 | 0 | return second_level_iter_.value(); |
63 | 2.15G | } |
64 | 3.41M | Status status() const override { |
65 | | // It'd be nice if status() returned a const Status& instead of a Status |
66 | 3.41M | if (!first_level_iter_.status().ok()) { |
67 | 0 | return first_level_iter_.status(); |
68 | 3.41M | } else if (second_level_iter_.iter() != nullptr && |
69 | 3.41M | !second_level_iter_.status().ok()3.15M ) { |
70 | 54 | return second_level_iter_.status(); |
71 | 3.41M | } else { |
72 | 3.41M | return status_; |
73 | 3.41M | } |
74 | 3.41M | } |
75 | 116k | Status PinData() override { return second_level_iter_.PinData(); } |
76 | 0 | Status ReleasePinnedData() override { |
77 | 0 | return second_level_iter_.ReleasePinnedData(); |
78 | 0 | } |
79 | 753k | bool IsKeyPinned() const override { |
80 | 753k | return second_level_iter_.iter() ? second_level_iter_.IsKeyPinned() : false0 ; |
81 | 753k | } |
82 | | |
83 | | private: |
84 | 18.6M | void SaveError(const Status& s) { |
85 | 18.6M | if (status_.ok()18.6M && !s.ok()) status_ = s1 ; |
86 | 18.6M | } |
87 | | void SkipEmptyDataBlocksForward(); |
88 | | void SkipEmptyDataBlocksBackward(); |
89 | | void SetSecondLevelIterator(InternalIterator* iter); |
90 | | void InitDataBlock(); |
91 | | |
92 | | TwoLevelIteratorState* state_; |
93 | | IteratorWrapper first_level_iter_; |
94 | | IteratorWrapper second_level_iter_; // May be nullptr |
95 | | bool need_free_iter_and_state_; |
96 | | Status status_; |
97 | | // If second_level_iter is non-nullptr, then "data_block_handle_" holds the |
98 | | // "index_value" passed to block_function_ to create the second_level_iter. |
99 | | std::string data_block_handle_; |
100 | | }; |
101 | | |
102 | | TwoLevelIterator::TwoLevelIterator(TwoLevelIteratorState* state, |
103 | | InternalIterator* first_level_iter, |
104 | | bool need_free_iter_and_state) |
105 | | : state_(state), |
106 | | first_level_iter_(first_level_iter), |
107 | 14.6M | need_free_iter_and_state_(need_free_iter_and_state) {} |
108 | | |
109 | 81.2M | void TwoLevelIterator::Seek(const Slice& target) { |
110 | 81.2M | if (state_->check_prefix_may_match && |
111 | 81.2M | !state_->PrefixMayMatch(target)15.8k ) { |
112 | 31 | SetSecondLevelIterator(nullptr); |
113 | 31 | return; |
114 | 31 | } |
115 | 81.2M | first_level_iter_.Seek(target); |
116 | | |
117 | 81.2M | InitDataBlock(); |
118 | 81.2M | if (second_level_iter_.iter() != nullptr) { |
119 | 81.2M | second_level_iter_.Seek(target); |
120 | 81.2M | } |
121 | 81.2M | SkipEmptyDataBlocksForward(); |
122 | 81.2M | } |
123 | | |
124 | 299k | void TwoLevelIterator::SeekToFirst() { |
125 | 299k | first_level_iter_.SeekToFirst(); |
126 | 299k | InitDataBlock(); |
127 | 299k | if (second_level_iter_.iter() != nullptr) { |
128 | 297k | second_level_iter_.SeekToFirst(); |
129 | 297k | } |
130 | 299k | SkipEmptyDataBlocksForward(); |
131 | 299k | } |
132 | | |
133 | 1.44M | void TwoLevelIterator::SeekToLast() { |
134 | 1.44M | first_level_iter_.SeekToLast(); |
135 | 1.44M | InitDataBlock(); |
136 | 1.44M | if (second_level_iter_.iter() != nullptr) { |
137 | 1.44M | second_level_iter_.SeekToLast(); |
138 | 1.44M | } |
139 | 1.44M | SkipEmptyDataBlocksBackward(); |
140 | 1.44M | } |
141 | | |
142 | 746M | void TwoLevelIterator::Next() { |
143 | 746M | assert(Valid()); |
144 | 0 | second_level_iter_.Next(); |
145 | 746M | SkipEmptyDataBlocksForward(); |
146 | 746M | } |
147 | | |
148 | 6.64M | void TwoLevelIterator::Prev() { |
149 | 6.64M | assert(Valid()); |
150 | 0 | second_level_iter_.Prev(); |
151 | 6.64M | SkipEmptyDataBlocksBackward(); |
152 | 6.64M | } |
153 | | |
154 | | |
155 | 826M | void TwoLevelIterator::SkipEmptyDataBlocksForward() { |
156 | 830M | while (second_level_iter_.iter() == nullptr || |
157 | 830M | (829M !second_level_iter_.Valid()829M && |
158 | 829M | !second_level_iter_.status().IsIncomplete()4.39M )) { |
159 | | // Move to next block |
160 | 5.48M | if (!first_level_iter_.Valid()) { |
161 | 1.09M | SetSecondLevelIterator(nullptr); |
162 | 1.09M | return; |
163 | 1.09M | } |
164 | 4.39M | first_level_iter_.Next(); |
165 | 4.39M | InitDataBlock(); |
166 | 4.39M | if (second_level_iter_.iter() != nullptr) { |
167 | 3.32M | second_level_iter_.SeekToFirst(); |
168 | 3.32M | } |
169 | 4.39M | } |
170 | 826M | } |
171 | | |
172 | 8.09M | void TwoLevelIterator::SkipEmptyDataBlocksBackward() { |
173 | 8.37M | while (second_level_iter_.iter() == nullptr || |
174 | 8.37M | (8.16M !second_level_iter_.Valid()8.16M && |
175 | 8.16M | !second_level_iter_.status().IsIncomplete()282k )) { |
176 | | // Move to next block |
177 | 488k | if (!first_level_iter_.Valid()) { |
178 | 206k | SetSecondLevelIterator(nullptr); |
179 | 206k | return; |
180 | 206k | } |
181 | 282k | first_level_iter_.Prev(); |
182 | 282k | InitDataBlock(); |
183 | 282k | if (second_level_iter_.iter() != nullptr) { |
184 | 77.9k | second_level_iter_.SeekToLast(); |
185 | 77.9k | } |
186 | 282k | } |
187 | 8.09M | } |
188 | | |
189 | 35.5M | void TwoLevelIterator::SetSecondLevelIterator(InternalIterator* iter) { |
190 | 35.5M | if (second_level_iter_.iter() != nullptr) { |
191 | 18.6M | SaveError(second_level_iter_.status()); |
192 | 18.6M | } |
193 | 35.5M | second_level_iter_.Set(iter); |
194 | 35.5M | } |
195 | | |
196 | 87.7M | void TwoLevelIterator::InitDataBlock() { |
197 | 87.7M | if (!first_level_iter_.Valid()) { |
198 | 1.29M | SetSecondLevelIterator(nullptr); |
199 | 86.4M | } else { |
200 | 86.4M | Slice handle = first_level_iter_.value(); |
201 | 86.4M | if (second_level_iter_.iter() != nullptr && |
202 | 86.4M | !second_level_iter_.status().IsIncomplete()70.8M && |
203 | 86.4M | handle.compare(data_block_handle_) == 070.8M ) { |
204 | | // second_level_iter is already constructed with this iterator, so |
205 | | // no need to change anything |
206 | 53.4M | } else { |
207 | 32.9M | InternalIterator* iter = state_->NewSecondaryIterator(handle); |
208 | 32.9M | data_block_handle_.assign(handle.cdata(), handle.size()); |
209 | 32.9M | SetSecondLevelIterator(iter); |
210 | 32.9M | } |
211 | 86.4M | } |
212 | 87.7M | } |
213 | | |
214 | | } // namespace |
215 | | |
216 | | InternalIterator* NewTwoLevelIterator( |
217 | | TwoLevelIteratorState* state, InternalIterator* first_level_iter, Arena* arena, |
218 | 14.6M | bool need_free_iter_and_state) { |
219 | 14.6M | if (arena == nullptr) { |
220 | 271k | return new TwoLevelIterator(state, first_level_iter, need_free_iter_and_state); |
221 | 14.4M | } else { |
222 | 14.4M | auto mem = arena->AllocateAligned(sizeof(TwoLevelIterator)); |
223 | 14.4M | return new (mem) |
224 | 14.4M | TwoLevelIterator(state, first_level_iter, need_free_iter_and_state); |
225 | 14.4M | } |
226 | 14.6M | } |
227 | | |
228 | | } // namespace rocksdb |