YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/rocksdb/table/index_reader.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#include "yb/rocksdb/table/index_reader.h"
15
16
#include "yb/rocksdb/table/block_based_table_factory.h"
17
#include "yb/rocksdb/table/block_based_table_internal.h"
18
#include "yb/rocksdb/table/iterator_wrapper.h"
19
#include "yb/rocksdb/table/meta_blocks.h"
20
#include "yb/util/slice.h"
21
22
namespace rocksdb {
23
24
using namespace std::placeholders;
25
26
Status BinarySearchIndexReader::Create(
27
    RandomAccessFileReader* file, const Footer& footer,
28
    const BlockHandle& index_handle, Env* env,
29
    const ComparatorPtr& comparator,
30
    std::unique_ptr<IndexReader>* index_reader,
31
8.08k
    const std::shared_ptr<yb::MemTracker>& mem_tracker) {
32
8.08k
  std::unique_ptr<Block> index_block;
33
8.08k
  auto s = block_based_table::ReadBlockFromFile(
34
8.08k
      file, footer, ReadOptions::kDefault, index_handle, &index_block, env, mem_tracker);
35
36
8.08k
  if (s.ok()) {
37
8.08k
    index_reader->reset(new BinarySearchIndexReader(comparator, std::move(index_block)));
38
8.08k
  }
39
40
8.08k
  return s;
41
8.08k
}
42
0
Result<Slice> BinarySearchIndexReader::GetMiddleKey() {
43
0
  return index_block_->GetMiddleKey(kIndexBlockKeyValueEncodingFormat);
44
0
}
45
46
Status HashIndexReader::Create(const SliceTransform* hash_key_extractor,
47
                       const Footer& footer, RandomAccessFileReader* file,
48
                       Env* env, const ComparatorPtr& comparator,
49
                       const BlockHandle& index_handle,
50
                       InternalIterator* meta_index_iter,
51
                       std::unique_ptr<IndexReader>* index_reader,
52
                       bool hash_index_allow_collision,
53
1.66k
                       const std::shared_ptr<yb::MemTracker>& mem_tracker) {
54
1.66k
  std::unique_ptr<Block> index_block;
55
1.66k
  auto s = block_based_table::ReadBlockFromFile(file, footer, ReadOptions::kDefault, index_handle,
56
1.66k
                             &index_block, env, mem_tracker);
57
58
1.66k
  if (!s.ok()) {
59
0
    return s;
60
0
  }
61
62
  // Note, failure to create prefix hash index does not need to be a hard error. We can still fall
63
  // back to the original binary search index.
64
  // So, Create will succeed regardless, from this point on.
65
1.66k
  HashIndexReader* new_index_reader;
66
1.66k
  index_reader->reset(new_index_reader = new HashIndexReader(comparator, std::move(index_block)));
67
68
  // Get prefixes block
69
1.66k
  BlockHandle prefixes_handle;
70
1.66k
  s = FindMetaBlock(meta_index_iter, kHashIndexPrefixesBlock,
71
1.66k
                    &prefixes_handle);
72
1.66k
  if (!s.ok()) {
73
0
    LOG(ERROR) << "Failed to find hash index prefixes block: " << s;
74
0
    return Status::OK();
75
0
  }
76
77
  // Get index metadata block
78
1.66k
  BlockHandle prefixes_meta_handle;
79
1.66k
  s = FindMetaBlock(meta_index_iter, kHashIndexPrefixesMetadataBlock,
80
1.66k
                    &prefixes_meta_handle);
81
1.66k
  if (!s.ok()) {
82
0
    LOG(ERROR) << "Failed to find hash index prefixes metadata block: " << s;
83
0
    return Status::OK();
84
0
  }
85
86
  // Read contents for the blocks
87
1.66k
  BlockContents prefixes_contents;
88
1.66k
  s = ReadBlockContents(file, footer, ReadOptions::kDefault, prefixes_handle,
89
1.66k
                        &prefixes_contents, env, mem_tracker, true /* do decompression */);
90
1.66k
  if (!s.ok()) {
91
0
    return s;
92
0
  }
93
1.66k
  BlockContents prefixes_meta_contents;
94
1.66k
  s = ReadBlockContents(file, footer, ReadOptions::kDefault, prefixes_meta_handle,
95
1.66k
                        &prefixes_meta_contents, env, mem_tracker,
96
1.66k
                        true /* do decompression */);
97
1.66k
  if (!s.ok()) {
98
0
    LOG(ERROR) << "Failed to read hash index prefixes metadata block: " << s;
99
0
    return Status::OK();
100
0
  }
101
102
1.66k
  if (!hash_index_allow_collision) {
103
    // TODO: deprecate once hash_index_allow_collision proves to be stable.
104
0
    BlockHashIndex* hash_index = nullptr;
105
0
    s = CreateBlockHashIndex(hash_key_extractor,
106
0
                             prefixes_contents.data,
107
0
                             prefixes_meta_contents.data,
108
0
                             &hash_index);
109
0
    if (s.ok()) {
110
0
      new_index_reader->index_block_->SetBlockHashIndex(hash_index);
111
0
      new_index_reader->OwnPrefixesContents(std::move(prefixes_contents));
112
0
    } else {
113
0
      LOG(ERROR) << "Failed to create block hash index: " << s;
114
0
    }
115
1.66k
  } else {
116
1.66k
    BlockPrefixIndex* prefix_index = nullptr;
117
1.66k
    s = BlockPrefixIndex::Create(hash_key_extractor,
118
1.66k
                                 prefixes_contents.data,
119
1.66k
                                 prefixes_meta_contents.data,
120
1.66k
                                 &prefix_index);
121
1.66k
    if (s.ok()) {
122
1.66k
      new_index_reader->index_block_->SetBlockPrefixIndex(prefix_index);
123
1.66k
    } else {
124
1
      LOG(ERROR) << "Failed to create block prefix index: " << s;
125
1
    }
126
1.66k
  }
127
128
1.66k
  return Status::OK();
129
1.66k
}
130
131
0
Result<Slice> HashIndexReader::GetMiddleKey() {
132
0
  return index_block_->GetMiddleKey(kIndexBlockKeyValueEncodingFormat);
133
0
}
134
135
class MultiLevelIterator : public InternalIterator {
136
 public:
137
  static constexpr auto kIterChainInitialCapacity = 4;
138
139
  MultiLevelIterator(
140
      TwoLevelIteratorState* state, InternalIterator* top_level_iter, int num_levels,
141
      bool need_free_top_level_iter)
142
    : state_(state), iter_(num_levels), index_block_handle_(num_levels - 1),
143
      bottom_level_iter_(iter_.data() + (num_levels - 1)),
144
22.4M
      need_free_top_level_iter_(need_free_top_level_iter)  {
145
22.4M
    iter_[0].Set(top_level_iter);
146
22.4M
  }
147
148
22.4M
  ~MultiLevelIterator() {
149
22.4M
    IteratorWrapper* iter = iter_.data() + (need_free_top_level_iter_ ? 
014.6M
:
17.80M
);
150
43.9M
    while (iter <= bottom_level_iter_) {
151
21.4M
      iter->DeleteIter(false /* arena_mode */);
152
21.4M
      ++iter;
153
21.4M
    }
154
22.4M
  }
155
156
88.9M
  void Seek(const Slice& target) override {
157
88.9M
    if (state_->check_prefix_may_match && 
!state_->PrefixMayMatch(target)84.0k
) {
158
0
      bottommost_positioned_iter_ = &iter_[0];
159
0
      return;
160
0
    }
161
162
88.9M
    DoSeek(std::bind(&IteratorWrapper::Seek, std::placeholders::_1, target));
163
88.9M
  }
164
165
280k
  void SeekToFirst() override {
166
280k
    DoSeek(std::bind(&IteratorWrapper::SeekToFirst, std::placeholders::_1));
167
280k
  }
168
169
1.44M
  void SeekToLast() override {
170
1.44M
    DoSeek(std::bind(&IteratorWrapper::SeekToLast, std::placeholders::_1));
171
1.44M
  }
172
173
11.4M
  void Next() override {
174
11.4M
    DoMove(
175
11.4M
        std::bind(&IteratorWrapper::Next, std::placeholders::_1),
176
11.4M
        std::bind(&IteratorWrapper::SeekToFirst, std::placeholders::_1)
177
11.4M
    );
178
11.4M
  }
179
180
282k
  void Prev() override {
181
282k
    DoMove(
182
282k
        std::bind(&IteratorWrapper::Prev, std::placeholders::_1),
183
282k
        std::bind(&IteratorWrapper::SeekToLast, std::placeholders::_1)
184
282k
    );
185
282k
  }
186
187
316M
  bool Valid() const override {
188
316M
    return bottommost_positioned_iter_ == bottom_level_iter_ && 
bottom_level_iter_->Valid()301M
;
189
316M
  }
190
191
86.2M
  Slice key() const override {
192
86.2M
    DCHECK(Valid());
193
86.2M
    return bottom_level_iter_->key();
194
86.2M
  }
195
196
101M
  Slice value() const override {
197
101M
    DCHECK(Valid());
198
101M
    return bottom_level_iter_->value();
199
101M
  }
200
201
18.9M
  Status status() const override {
202
18.9M
    if (bottommost_positioned_iter_) {
203
11.1M
      const IteratorWrapper* iter = iter_.data();
204
25.3M
      while (iter <= bottommost_positioned_iter_ && 
iter->iter()14.2M
) {
205
14.2M
        if (!iter->status().ok()) {
206
0
          return iter->status();
207
0
        }
208
14.2M
        ++iter;
209
14.2M
      }
210
11.1M
    }
211
18.9M
    return status_;
212
18.9M
  }
213
214
7.42M
  void SetSubIterator(IteratorWrapper* iter_wrapper, InternalIterator* iter) {
215
7.42M
    if (iter_wrapper->iter() != nullptr) {
216
634k
      SaveError(iter_wrapper->status());
217
634k
    }
218
7.42M
    iter_wrapper->Set(iter);
219
7.42M
  }
220
221
 private:
222
634k
  void SaveError(const Status& s) {
223
634k
    if (status_.ok() && !s.ok()) 
status_ = s0
;
224
634k
  }
225
226
  template <typename F>
227
90.6M
  void DoSeek(F seek_function) {
228
90.6M
    IteratorWrapper* iter = iter_.data();
229
90.6M
    seek_function(iter);
230
90.6M
    bottommost_positioned_iter_ = iter;
231
128M
    while (iter < bottom_level_iter_ && 
iter->Valid()38.2M
) {
232
38.2M
      InitSubIterator(iter);
233
38.2M
      ++iter;
234
38.2M
      seek_function(iter);
235
38.2M
    }
236
90.6M
    bottommost_positioned_iter_ = iter;
237
90.6M
  }
void rocksdb::MultiLevelIterator::DoSeek<std::__1::__bind<void (rocksdb::IteratorWrapper::*)(), std::__1::placeholders::__ph<1> const&> >(std::__1::__bind<void (rocksdb::IteratorWrapper::*)(), std::__1::placeholders::__ph<1> const&>)
Line
Count
Source
227
1.72M
  void DoSeek(F seek_function) {
228
1.72M
    IteratorWrapper* iter = iter_.data();
229
1.72M
    seek_function(iter);
230
1.72M
    bottommost_positioned_iter_ = iter;
231
1.74M
    while (iter < bottom_level_iter_ && 
iter->Valid()19.9k
) {
232
19.9k
      InitSubIterator(iter);
233
19.9k
      ++iter;
234
19.9k
      seek_function(iter);
235
19.9k
    }
236
1.72M
    bottommost_positioned_iter_ = iter;
237
1.72M
  }
void rocksdb::MultiLevelIterator::DoSeek<std::__1::__bind<void (rocksdb::IteratorWrapper::*)(yb::Slice const&), std::__1::placeholders::__ph<1> const&, yb::Slice const&> >(std::__1::__bind<void (rocksdb::IteratorWrapper::*)(yb::Slice const&), std::__1::placeholders::__ph<1> const&, yb::Slice const&>)
Line
Count
Source
227
88.9M
  void DoSeek(F seek_function) {
228
88.9M
    IteratorWrapper* iter = iter_.data();
229
88.9M
    seek_function(iter);
230
88.9M
    bottommost_positioned_iter_ = iter;
231
127M
    while (iter < bottom_level_iter_ && 
iter->Valid()38.2M
) {
232
38.2M
      InitSubIterator(iter);
233
38.2M
      ++iter;
234
38.2M
      seek_function(iter);
235
38.2M
    }
236
88.9M
    bottommost_positioned_iter_ = iter;
237
88.9M
  }
238
239
  template <typename F1, typename F2>
240
11.7M
  void DoMove(F1 move_function, F2 lower_levels_init_function) {
241
11.7M
    DCHECK(Valid());
242
    // First try to move iterator starting with bottom level.
243
11.7M
    IteratorWrapper* iter = bottom_level_iter_;
244
11.7M
    move_function(iter);
245
11.8M
    while (!iter->Valid() && 
iter > iter_.data()1.59M
) {
246
108k
      --iter;
247
108k
      move_function(iter);
248
108k
    }
249
11.7M
    if (!iter->Valid()) {
250
1.48M
      bottommost_positioned_iter_ = iter;
251
1.48M
      return;
252
1.48M
    }
253
    // Once we've moved iterator at some level, we need to reset iterators at levels below.
254
10.3M
    
while (10.2M
iter < bottom_level_iter_) {
255
25.7k
      InitSubIterator(iter);
256
25.7k
      ++iter;
257
25.7k
      lower_levels_init_function(iter);
258
25.7k
    }
259
10.2M
    bottommost_positioned_iter_ = bottom_level_iter_;
260
10.2M
  }
261
262
38.3M
  void InitSubIterator(IteratorWrapper* parent_iter) {
263
38.3M
    DCHECK(parent_iter->Valid());
264
38.3M
    IteratorWrapper* sub_iter = parent_iter + 1;
265
38.3M
    std::string* child_index_block_handle =
266
38.3M
        index_block_handle_.data() + (parent_iter - iter_.data());
267
38.3M
    Slice handle = parent_iter->value();
268
38.3M
    if (sub_iter->iter() && 
!sub_iter->status().IsIncomplete()31.5M
269
38.3M
        && 
handle.compare(*child_index_block_handle) == 031.5M
) {
270
      // wrapper is already set to iterator for this handle, no need to change.
271
30.8M
    } else {
272
7.43M
      InternalIterator* iter = state_->NewSecondaryIterator(handle);
273
7.43M
      handle.CopyToBuffer(child_index_block_handle);
274
7.43M
      SetSubIterator(sub_iter, iter);
275
7.43M
    }
276
38.3M
  }
277
278
  TwoLevelIteratorState* const state_;
279
  boost::container::small_vector<IteratorWrapper, kIterChainInitialCapacity> iter_;
280
  // If iter_[level] holds non-nullptr, then "index_block_handle_[level-1]" holds the
281
  // handle passed to state_->NewSecondaryIterator to create iter_[level].
282
  boost::container::small_vector<std::string, kIterChainInitialCapacity - 1> index_block_handle_;
283
  IteratorWrapper* const bottom_level_iter_;
284
  bool need_free_top_level_iter_;
285
  Status status_ = Status::OK();
286
  IteratorWrapper* bottommost_positioned_iter_ = nullptr;
287
};
288
289
Result<std::unique_ptr<MultiLevelIndexReader>> MultiLevelIndexReader::Create(
290
    RandomAccessFileReader* file, const Footer& footer, const int num_levels,
291
    const BlockHandle& top_level_index_handle, Env* env, const ComparatorPtr& comparator,
292
76.1k
    const std::shared_ptr<yb::MemTracker>& mem_tracker) {
293
76.1k
  std::unique_ptr<Block> index_block;
294
76.1k
  RETURN_NOT_OK(block_based_table::ReadBlockFromFile(
295
76.1k
      file, footer, ReadOptions::kDefault, top_level_index_handle, &index_block, env,
296
76.1k
      mem_tracker));
297
298
76.1k
  return std::make_unique<MultiLevelIndexReader>(comparator, num_levels, std::move(index_block));
299
76.1k
}
300
301
InternalIterator* MultiLevelIndexReader::NewIterator(
302
22.4M
    BlockIter* iter, TwoLevelIteratorState* index_iterator_state, bool) {
303
22.4M
  InternalIterator* top_level_iter = top_level_index_block_->NewIndexIterator(
304
22.4M
      comparator_.get(), iter, true /* total_order_seek */);
305
22.4M
  return new MultiLevelIterator(
306
22.4M
      index_iterator_state, top_level_iter, num_levels_, top_level_iter != iter);
307
22.4M
}
308
309
143
Result<Slice> MultiLevelIndexReader::GetMiddleKey() {
310
143
  return top_level_index_block_->GetMiddleKey(kIndexBlockKeyValueEncodingFormat);
311
143
}
312
313
} // namespace rocksdb