Coverage Report

Created: 2025-06-10 13:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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