Coverage Report

Created: 2025-07-23 07:17

/src/rocksdb/db/compaction/clipping_iterator.h
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 both the GPLv2 (found in the
3
//  COPYING file in the root directory) and Apache 2.0 License
4
//  (found in the LICENSE.Apache file in the root directory).
5
6
#pragma once
7
8
#include <cassert>
9
10
#include "rocksdb/comparator.h"
11
#include "table/internal_iterator.h"
12
13
namespace ROCKSDB_NAMESPACE {
14
15
// An internal iterator that wraps another one and ensures that any keys
16
// returned are strictly within a range [start, end). If the underlying
17
// iterator has already performed the bounds checking, it relies on that result;
18
// otherwise, it performs the necessary key comparisons itself. Both bounds
19
// are optional.
20
class ClippingIterator : public InternalIterator {
21
 public:
22
  ClippingIterator(InternalIterator* iter, const Slice* start, const Slice* end,
23
                   const CompareInterface* cmp)
24
0
      : iter_(iter), start_(start), end_(end), cmp_(cmp), valid_(false) {
25
0
    assert(iter_);
26
0
    assert(cmp_);
27
0
    assert(!start_ || !end_ || cmp_->Compare(*start_, *end_) <= 0);
28
29
0
    UpdateAndEnforceBounds();
30
0
  }
31
32
0
  bool Valid() const override { return valid_; }
33
34
0
  void SeekToFirst() override {
35
0
    if (start_) {
36
0
      iter_->Seek(*start_);
37
0
    } else {
38
0
      iter_->SeekToFirst();
39
0
    }
40
41
0
    UpdateAndEnforceUpperBound();
42
0
  }
43
44
0
  void SeekToLast() override {
45
0
    if (end_) {
46
0
      iter_->SeekForPrev(*end_);
47
48
      // Upper bound is exclusive, so we need a key which is strictly smaller
49
0
      if (iter_->Valid() && cmp_->Compare(iter_->key(), *end_) == 0) {
50
0
        iter_->Prev();
51
0
      }
52
0
    } else {
53
0
      iter_->SeekToLast();
54
0
    }
55
56
0
    UpdateAndEnforceLowerBound();
57
0
  }
58
59
0
  void Seek(const Slice& target) override {
60
0
    if (start_ && cmp_->Compare(target, *start_) < 0) {
61
0
      iter_->Seek(*start_);
62
0
      UpdateAndEnforceUpperBound();
63
0
      return;
64
0
    }
65
66
0
    if (end_ && cmp_->Compare(target, *end_) >= 0) {
67
0
      valid_ = false;
68
0
      return;
69
0
    }
70
71
0
    iter_->Seek(target);
72
0
    UpdateAndEnforceUpperBound();
73
0
  }
74
75
0
  void SeekForPrev(const Slice& target) override {
76
0
    if (start_ && cmp_->Compare(target, *start_) < 0) {
77
0
      valid_ = false;
78
0
      return;
79
0
    }
80
81
0
    if (end_ && cmp_->Compare(target, *end_) >= 0) {
82
0
      iter_->SeekForPrev(*end_);
83
84
      // Upper bound is exclusive, so we need a key which is strictly smaller
85
0
      if (iter_->Valid() && cmp_->Compare(iter_->key(), *end_) == 0) {
86
0
        iter_->Prev();
87
0
      }
88
89
0
      UpdateAndEnforceLowerBound();
90
0
      return;
91
0
    }
92
93
0
    iter_->SeekForPrev(target);
94
0
    UpdateAndEnforceLowerBound();
95
0
  }
96
97
0
  void Next() override {
98
0
    assert(valid_);
99
0
    iter_->Next();
100
0
    UpdateAndEnforceUpperBound();
101
0
  }
102
103
0
  bool NextAndGetResult(IterateResult* result) override {
104
0
    assert(valid_);
105
0
    assert(result);
106
107
0
    IterateResult res;
108
0
    valid_ = iter_->NextAndGetResult(&res);
109
110
0
    if (!valid_) {
111
0
      return false;
112
0
    }
113
114
0
    if (end_) {
115
0
      EnforceUpperBoundImpl(res.bound_check_result);
116
117
0
      if (!valid_) {
118
0
        return false;
119
0
      }
120
0
    }
121
122
0
    res.bound_check_result = IterBoundCheck::kInbound;
123
0
    *result = res;
124
125
0
    return true;
126
0
  }
127
128
0
  void Prev() override {
129
0
    assert(valid_);
130
0
    iter_->Prev();
131
0
    UpdateAndEnforceLowerBound();
132
0
  }
133
134
0
  Slice key() const override {
135
0
    assert(valid_);
136
0
    return iter_->key();
137
0
  }
138
139
0
  Slice user_key() const override {
140
0
    assert(valid_);
141
0
    return iter_->user_key();
142
0
  }
143
144
0
  Slice value() const override {
145
0
    assert(valid_);
146
0
    return iter_->value();
147
0
  }
148
149
0
  Status status() const override { return iter_->status(); }
150
151
0
  bool PrepareValue() override {
152
0
    assert(valid_);
153
154
0
    if (iter_->PrepareValue()) {
155
0
      return true;
156
0
    }
157
158
0
    assert(!iter_->Valid());
159
0
    valid_ = false;
160
0
    return false;
161
0
  }
162
163
0
  bool MayBeOutOfLowerBound() override {
164
0
    assert(valid_);
165
0
    return false;
166
0
  }
167
168
0
  IterBoundCheck UpperBoundCheckResult() override {
169
0
    assert(valid_);
170
0
    return IterBoundCheck::kInbound;
171
0
  }
172
173
0
  void SetPinnedItersMgr(PinnedIteratorsManager* pinned_iters_mgr) override {
174
0
    iter_->SetPinnedItersMgr(pinned_iters_mgr);
175
0
  }
176
177
0
  bool IsKeyPinned() const override {
178
0
    assert(valid_);
179
0
    return iter_->IsKeyPinned();
180
0
  }
181
182
0
  bool IsValuePinned() const override {
183
0
    assert(valid_);
184
0
    return iter_->IsValuePinned();
185
0
  }
186
187
0
  Status GetProperty(std::string prop_name, std::string* prop) override {
188
0
    return iter_->GetProperty(prop_name, prop);
189
0
  }
190
191
0
  bool IsDeleteRangeSentinelKey() const override {
192
0
    assert(valid_);
193
0
    return iter_->IsDeleteRangeSentinelKey();
194
0
  }
195
196
 private:
197
0
  void UpdateValid() {
198
0
    assert(!iter_->Valid() || iter_->status().ok());
199
200
0
    valid_ = iter_->Valid();
201
0
  }
202
203
0
  void EnforceUpperBoundImpl(IterBoundCheck bound_check_result) {
204
0
    if (bound_check_result == IterBoundCheck::kInbound) {
205
0
      return;
206
0
    }
207
208
0
    if (bound_check_result == IterBoundCheck::kOutOfBound) {
209
0
      valid_ = false;
210
0
      return;
211
0
    }
212
213
0
    assert(bound_check_result == IterBoundCheck::kUnknown);
214
215
0
    if (cmp_->Compare(key(), *end_) >= 0) {
216
0
      valid_ = false;
217
0
    }
218
0
  }
219
220
0
  void EnforceUpperBound() {
221
0
    if (!valid_) {
222
0
      return;
223
0
    }
224
225
0
    if (!end_) {
226
0
      return;
227
0
    }
228
229
0
    EnforceUpperBoundImpl(iter_->UpperBoundCheckResult());
230
0
  }
231
232
0
  void EnforceLowerBound() {
233
0
    if (!valid_) {
234
0
      return;
235
0
    }
236
237
0
    if (!start_) {
238
0
      return;
239
0
    }
240
241
0
    if (!iter_->MayBeOutOfLowerBound()) {
242
0
      return;
243
0
    }
244
245
0
    if (cmp_->Compare(key(), *start_) < 0) {
246
0
      valid_ = false;
247
0
    }
248
0
  }
249
250
0
  void AssertBounds() {
251
0
    assert(!valid_ || !start_ || cmp_->Compare(key(), *start_) >= 0);
252
0
    assert(!valid_ || !end_ || cmp_->Compare(key(), *end_) < 0);
253
0
  }
254
255
0
  void UpdateAndEnforceBounds() {
256
0
    UpdateValid();
257
0
    EnforceUpperBound();
258
0
    EnforceLowerBound();
259
0
    AssertBounds();
260
0
  }
261
262
0
  void UpdateAndEnforceUpperBound() {
263
0
    UpdateValid();
264
0
    EnforceUpperBound();
265
0
    AssertBounds();
266
0
  }
267
268
0
  void UpdateAndEnforceLowerBound() {
269
0
    UpdateValid();
270
0
    EnforceLowerBound();
271
0
    AssertBounds();
272
0
  }
273
274
  InternalIterator* iter_;
275
  const Slice* start_;
276
  const Slice* end_;
277
  const CompareInterface* cmp_;
278
  bool valid_;
279
};
280
281
}  // namespace ROCKSDB_NAMESPACE