Coverage Report

Created: 2026-09-28 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/table/merging_iterator.cc
Line
Count
Source
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
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7
// Use of this source code is governed by a BSD-style license that can be
8
// found in the LICENSE file. See the AUTHORS file for names of contributors.
9
10
#include "table/merging_iterator.h"
11
12
#include "db/arena_wrapped_db_iter.h"
13
#include "monitoring/file_read_sample.h"
14
#include "test_util/sync_point.h"
15
16
namespace ROCKSDB_NAMESPACE {
17
// MergingIterator uses a min/max heap to combine data from point iterators.
18
// Range tombstones can be added and keys covered by range tombstones will be
19
// skipped.
20
//
21
// The following are implementation details and can be ignored by user.
22
// For merging iterator to process range tombstones, it treats the start and end
23
// keys of a range tombstone as two keys and put them into minHeap_ or maxHeap_
24
// together with regular point keys. Each range tombstone is active only within
25
// its internal key range [start_key, end_key). An `active_` set is used to
26
// track levels that have an active range tombstone. Take forward scanning
27
// for example. Level j is in active_ if its current range tombstone has its
28
// start_key popped from minHeap_ and its end_key in minHeap_. If the top of
29
// minHeap_ is a point key from level L, we can determine if the point key is
30
// covered by any range tombstone by checking if there is an l <= L in active_.
31
// The case of l == L also involves checking range tombstone's sequence number.
32
//
33
// The following (non-exhaustive) list of invariants are maintained by
34
// MergingIterator during forward scanning. After each InternalIterator API,
35
// i.e., Seek*() and Next(), and FindNextVisibleKey(), if minHeap_ is not empty:
36
// (1) minHeap_.top().type == ITERATOR
37
// (2) minHeap_.top()->key() is not covered by any range tombstone.
38
//
39
// After each call to SeekImpl() in addition to the functions mentioned above:
40
// (3) For all level i and j <= i, range_tombstone_iters_[j].prev.end_key() <
41
// children_[i].iter.key(). That is, range_tombstone_iters_[j] is at or before
42
// the first range tombstone from level j with end_key() >
43
// children_[i].iter.key().
44
// (4) For all level i and j <= i, if j in active_, then
45
// range_tombstone_iters_[j]->start_key() < children_[i].iter.key().
46
// - When range_tombstone_iters_[j] is !Valid(), we consider its `prev` to be
47
// the last range tombstone from that range tombstone iterator.
48
// - When referring to range tombstone start/end keys, assume it is the value of
49
// HeapItem::tombstone_pik. This value has op_type = kMaxValid, which makes
50
// range tombstone keys have distinct values from point keys.
51
//
52
// Applicable class variables have their own (forward scanning) invariants
53
// listed in the comments above their definition.
54
class MergingIterator : public InternalIterator {
55
 public:
56
  MergingIterator(const InternalKeyComparator* comparator,
57
                  InternalIterator** children, int n, bool is_arena_mode,
58
                  bool prefix_seek_mode,
59
                  const Slice* iterate_upper_bound = nullptr)
60
16.1k
      : is_arena_mode_(is_arena_mode),
61
16.1k
        prefix_seek_mode_(prefix_seek_mode),
62
16.1k
        direction_(kForward),
63
16.1k
        comparator_(comparator),
64
16.1k
        current_(nullptr),
65
16.1k
        minHeap_(MinHeapItemComparator(comparator_)),
66
16.1k
        pinned_iters_mgr_(nullptr),
67
16.1k
        iterate_upper_bound_(iterate_upper_bound) {
68
16.1k
    children_.resize(n);
69
16.1k
    for (int i = 0; i < n; i++) {
70
0
      children_[i].level = i;
71
0
      children_[i].iter.Set(children[i]);
72
0
    }
73
16.1k
  }
74
75
28.1k
  void considerStatus(Status s) {
76
28.1k
    if (!s.ok() && status_.ok()) {
77
0
      status_ = s;
78
0
    }
79
28.1k
  }
80
81
26.4k
  virtual void AddIterator(InternalIterator* iter) {
82
26.4k
    children_.emplace_back(children_.size(), iter);
83
26.4k
    if (pinned_iters_mgr_) {
84
0
      iter->SetPinnedItersMgr(pinned_iters_mgr_);
85
0
    }
86
    // Invalidate to ensure `Seek*()` is called to construct the heaps before
87
    // use.
88
26.4k
    current_ = nullptr;
89
26.4k
  }
90
91
  // There must be either no range tombstone iterator or the same number of
92
  // range tombstone iterators as point iterators after all iters are added.
93
  // The i-th added range tombstone iterator and the i-th point iterator
94
  // must point to the same LSM level.
95
  // Merging iterator takes ownership of `iter` and is responsible for freeing
96
  // it. One exception to this is when a LevelIterator moves to a different SST
97
  // file or when Iterator::Refresh() is called, the range tombstone iterator
98
  // could be updated. In that case, this merging iterator is only responsible
99
  // for freeing the new range tombstone iterator that it has pointers to in
100
  // range_tombstone_iters_.
101
  void AddRangeTombstoneIterator(
102
17.7k
      std::unique_ptr<TruncatedRangeDelIterator>&& iter) {
103
17.7k
    range_tombstone_iters_.emplace_back(std::move(iter));
104
17.7k
  }
105
106
  // Called by MergingIteratorBuilder when all point iterators and range
107
  // tombstone iterators are added. Initializes HeapItems for range tombstone
108
  // iterators.
109
9.70k
  void Finish() {
110
9.70k
    if (!range_tombstone_iters_.empty()) {
111
6.34k
      assert(range_tombstone_iters_.size() == children_.size());
112
6.34k
      pinned_heap_item_.resize(range_tombstone_iters_.size());
113
24.0k
      for (size_t i = 0; i < range_tombstone_iters_.size(); ++i) {
114
17.7k
        pinned_heap_item_[i].level = i;
115
        // Range tombstone end key is exclusive. If a point internal key has the
116
        // same user key and sequence number as the start or end key of a range
117
        // tombstone, the order will be start < end key < internal key with the
118
        // following op_type change. This is helpful to ensure keys popped from
119
        // heap are in expected order since range tombstone start/end keys will
120
        // be distinct from point internal keys. Strictly speaking, this is only
121
        // needed for tombstone end points that are truncated in
122
        // TruncatedRangeDelIterator since untruncated tombstone end points
123
        // always have kMaxSequenceNumber and kTypeRangeDeletion (see
124
        // TruncatedRangeDelIterator::start_key()/end_key()).
125
17.7k
        pinned_heap_item_[i].tombstone_pik.type = kTypeMaxValid;
126
17.7k
      }
127
6.34k
    }
128
9.70k
  }
129
130
16.1k
  ~MergingIterator() override {
131
16.1k
    range_tombstone_iters_.clear();
132
133
26.4k
    for (auto& child : children_) {
134
26.4k
      child.iter.DeleteIter(is_arena_mode_);
135
26.4k
    }
136
16.1k
    status_.PermitUncheckedError();
137
16.1k
  }
138
139
0
  void SetRangeDelReadSeqno(SequenceNumber read_seqno) override {
140
0
    for (auto& child : children_) {
141
      // This should only be needed for LevelIterator (iterators from L1+).
142
0
      child.iter.SetRangeDelReadSeqno(read_seqno);
143
0
    }
144
0
    for (auto& child : range_tombstone_iters_) {
145
0
      if (child) {
146
0
        child->SetRangeDelReadSeqno(read_seqno);
147
0
      }
148
0
    }
149
0
  }
150
151
81.7k
  bool Valid() const override { return current_ != nullptr && status_.ok(); }
152
153
6.87k
  Status status() const override { return status_; }
154
155
  // Add range_tombstone_iters_[level] into min heap.
156
  // Updates active_ if the end key of a range tombstone is inserted.
157
  // pinned_heap_items_[level].type is updated based on `start_key`.
158
  //
159
  // If range_tombstone_iters_[level] is after iterate_upper_bound_,
160
  // it is removed from the heap.
161
  // @param start_key specifies which end point of the range tombstone to add.
162
  void InsertRangeTombstoneToMinHeap(size_t level, bool start_key = true,
163
187k
                                     bool replace_top = false) {
164
187k
    assert(!range_tombstone_iters_.empty() &&
165
187k
           range_tombstone_iters_[level]->Valid());
166
    // Maintains Invariant(phi)
167
187k
    if (start_key) {
168
93.9k
      pinned_heap_item_[level].type = HeapItem::Type::DELETE_RANGE_START;
169
93.9k
      ParsedInternalKey pik = range_tombstone_iters_[level]->start_key();
170
      // iterate_upper_bound does not have timestamp
171
93.9k
      if (iterate_upper_bound_ &&
172
0
          comparator_->user_comparator()->CompareWithoutTimestamp(
173
0
              pik.user_key, true /* a_has_ts */, *iterate_upper_bound_,
174
0
              false /* b_has_ts */) >= 0) {
175
0
        if (replace_top) {
176
          // replace_top implies this range tombstone iterator is still in
177
          // minHeap_ and at the top.
178
0
          minHeap_.pop();
179
0
        }
180
0
        return;
181
0
      }
182
93.9k
      pinned_heap_item_[level].SetTombstoneKey(std::move(pik));
183
      // Checks Invariant(active_)
184
93.9k
      assert(active_.count(level) == 0);
185
93.9k
    } else {
186
      // allow end key to go over upper bound (if present) since start key is
187
      // before upper bound and the range tombstone could still cover a
188
      // range before upper bound.
189
      // Maintains Invariant(active_)
190
93.9k
      pinned_heap_item_[level].SetTombstoneKey(
191
93.9k
          range_tombstone_iters_[level]->end_key());
192
93.9k
      pinned_heap_item_[level].type = HeapItem::Type::DELETE_RANGE_END;
193
93.9k
      active_.insert(level);
194
93.9k
    }
195
187k
    if (replace_top) {
196
184k
      minHeap_.replace_top(&pinned_heap_item_[level]);
197
184k
    } else {
198
2.87k
      minHeap_.push(&pinned_heap_item_[level]);
199
2.87k
    }
200
187k
  }
201
202
  // Add range_tombstone_iters_[level] into max heap.
203
  // Updates active_ if the start key of a range tombstone is inserted.
204
  // @param end_key specifies which end point of the range tombstone to add.
205
  void InsertRangeTombstoneToMaxHeap(size_t level, bool end_key = true,
206
0
                                     bool replace_top = false) {
207
0
    assert(!range_tombstone_iters_.empty() &&
208
0
           range_tombstone_iters_[level]->Valid());
209
0
    if (end_key) {
210
0
      pinned_heap_item_[level].SetTombstoneKey(
211
0
          range_tombstone_iters_[level]->end_key());
212
0
      pinned_heap_item_[level].type = HeapItem::Type::DELETE_RANGE_END;
213
0
      assert(active_.count(level) == 0);
214
0
    } else {
215
0
      pinned_heap_item_[level].SetTombstoneKey(
216
0
          range_tombstone_iters_[level]->start_key());
217
0
      pinned_heap_item_[level].type = HeapItem::Type::DELETE_RANGE_START;
218
0
      active_.insert(level);
219
0
    }
220
0
    if (replace_top) {
221
0
      maxHeap_->replace_top(&pinned_heap_item_[level]);
222
0
    } else {
223
0
      maxHeap_->push(&pinned_heap_item_[level]);
224
0
    }
225
0
  }
226
227
  // Remove HeapItems from top of minHeap_ that are of type DELETE_RANGE_START
228
  // until minHeap_ is empty or the top of the minHeap_ is not of type
229
  // DELETE_RANGE_START. Each such item means a range tombstone becomes active,
230
  // so `active_` is updated accordingly.
231
154k
  void PopDeleteRangeStart() {
232
248k
    while (!minHeap_.empty() &&
233
242k
           minHeap_.top()->type == HeapItem::Type::DELETE_RANGE_START) {
234
93.9k
      TEST_SYNC_POINT_CALLBACK("MergeIterator::PopDeleteRangeStart", nullptr);
235
      // Invariant(rti) holds since
236
      // range_tombstone_iters_[minHeap_.top()->level] is still valid, and
237
      // parameter `replace_top` is set to true here to ensure only one such
238
      // HeapItem is in minHeap_.
239
93.9k
      InsertRangeTombstoneToMinHeap(
240
93.9k
          minHeap_.top()->level, false /* start_key */, true /* replace_top */);
241
93.9k
    }
242
154k
  }
243
244
  // Remove HeapItems from top of maxHeap_ that are of type DELETE_RANGE_END
245
  // until maxHeap_ is empty or the top of the maxHeap_ is not of type
246
  // DELETE_RANGE_END. Each such item means a range tombstone becomes active,
247
  // so `active_` is updated accordingly.
248
17.5k
  void PopDeleteRangeEnd() {
249
17.5k
    while (!maxHeap_->empty() &&
250
14.5k
           maxHeap_->top()->type == HeapItem::Type::DELETE_RANGE_END) {
251
      // insert start key of this range tombstone and updates active_
252
0
      InsertRangeTombstoneToMaxHeap(maxHeap_->top()->level, false /* end_key */,
253
0
                                    true /* replace_top */);
254
0
    }
255
17.5k
  }
256
257
6.67k
  void SeekToFirst() override {
258
6.67k
    ClearHeaps();
259
6.67k
    status_ = Status::OK();
260
16.5k
    for (auto& child : children_) {
261
16.5k
      child.iter.SeekToFirst();
262
16.5k
      AddToMinHeapOrCheckStatus(&child);
263
16.5k
    }
264
265
17.8k
    for (size_t i = 0; i < range_tombstone_iters_.size(); ++i) {
266
11.2k
      if (range_tombstone_iters_[i]) {
267
2.87k
        range_tombstone_iters_[i]->SeekToFirst();
268
2.87k
        if (range_tombstone_iters_[i]->Valid()) {
269
          // It is possible to be invalid due to snapshots.
270
2.87k
          InsertRangeTombstoneToMinHeap(i);
271
2.87k
        }
272
2.87k
      }
273
11.2k
    }
274
6.67k
    FindNextVisibleKey();
275
6.67k
    direction_ = kForward;
276
6.67k
    current_ = CurrentForward();
277
6.67k
  }
278
279
0
  void SeekToLast() override {
280
0
    ClearHeaps();
281
0
    InitMaxHeap();
282
0
    status_ = Status::OK();
283
0
    for (auto& child : children_) {
284
0
      child.iter.SeekToLast();
285
0
      AddToMaxHeapOrCheckStatus(&child);
286
0
    }
287
288
0
    for (size_t i = 0; i < range_tombstone_iters_.size(); ++i) {
289
0
      if (range_tombstone_iters_[i]) {
290
0
        range_tombstone_iters_[i]->SeekToLast();
291
0
        if (range_tombstone_iters_[i]->Valid()) {
292
          // It is possible to be invalid due to snapshots.
293
0
          InsertRangeTombstoneToMaxHeap(i);
294
0
        }
295
0
      }
296
0
    }
297
0
    FindPrevVisibleKey();
298
0
    direction_ = kReverse;
299
0
    current_ = CurrentReverse();
300
0
  }
301
302
  // Position this merging iterator at the first key >= target (internal key).
303
  // If range tombstones are present, keys covered by range tombstones are
304
  // skipped, and this merging iter points to the first non-range-deleted key >=
305
  // target after Seek(). If !Valid() and status().ok() then this iterator
306
  // reaches the end.
307
  //
308
  // If range tombstones are present, cascading seeks may be called (an
309
  // optimization adapted from Pebble https://github.com/cockroachdb/pebble).
310
  // Roughly, if there is a range tombstone [start, end) that covers the
311
  // target user key at level L, then this range tombstone must cover the range
312
  // [target key, end) in all levels > L. So for all levels > L, we can pretend
313
  // the target key is `end`. This optimization is applied at each level and
314
  // hence the name "cascading seek".
315
702
  void Seek(const Slice& target) override {
316
    // Define LevelNextVisible(i, k) to be the first key >= k in level i that is
317
    // not covered by any range tombstone.
318
    // After SeekImpl(target, 0), invariants (3) and (4) hold.
319
    // For all level i, target <= children_[i].iter.key() <= LevelNextVisible(i,
320
    // target). By the contract of FindNextVisibleKey(), Invariants (1)-(4)
321
    // holds after this call, and minHeap_.top().iter points to the
322
    // first key >= target among children_ that is not covered by any range
323
    // tombstone.
324
702
    status_ = Status::OK();
325
702
    SeekImpl(target);
326
702
    FindNextVisibleKey();
327
328
702
    direction_ = kForward;
329
702
    {
330
702
      PERF_TIMER_GUARD(seek_min_heap_time);
331
702
      current_ = CurrentForward();
332
702
    }
333
702
  }
334
335
3.03k
  void SeekForPrev(const Slice& target) override {
336
3.03k
    assert(range_tombstone_iters_.empty() ||
337
3.03k
           range_tombstone_iters_.size() == children_.size());
338
3.03k
    status_ = Status::OK();
339
3.03k
    SeekForPrevImpl(target);
340
3.03k
    FindPrevVisibleKey();
341
342
3.03k
    direction_ = kReverse;
343
3.03k
    {
344
3.03k
      PERF_TIMER_GUARD(seek_max_heap_time);
345
3.03k
      current_ = CurrentReverse();
346
3.03k
    }
347
3.03k
  }
348
349
50.6k
  void Next() override {
350
50.6k
    assert(Valid());
351
    // Ensure that all children are positioned after key().
352
    // If we are moving in the forward direction, it is already
353
    // true for all the non-current children since current_ is
354
    // the smallest child and key() == current_->key().
355
50.6k
    if (direction_ != kForward) {
356
      // The loop advanced all non-current children to be > key() so current_
357
      // should still be strictly the smallest key.
358
0
      SwitchToForward();
359
0
    }
360
361
    // For the heap modifications below to be correct, current_ must be the
362
    // current top of the heap.
363
50.6k
    assert(current_ == CurrentForward());
364
    // as the current points to the current record. move the iterator forward.
365
50.6k
    current_->Next();
366
50.6k
    if (current_->Valid()) {
367
      // current is still valid after the Next() call above.  Call
368
      // replace_top() to restore the heap property.  When the same child
369
      // iterator yields a sequence of keys, this is cheap.
370
42.4k
      assert(current_->status().ok());
371
42.4k
      minHeap_.replace_top(minHeap_.top());
372
42.4k
    } else {
373
      // current stopped being valid, remove it from the heap.
374
8.16k
      considerStatus(current_->status());
375
8.16k
      minHeap_.pop();
376
8.16k
    }
377
    // Invariants (3) and (4) hold when after advancing current_.
378
    // Let k be the smallest key among children_[i].iter.key().
379
    // k <= children_[i].iter.key() <= LevelNextVisible(i, k) holds for all
380
    // level i. After FindNextVisible(), Invariants (1)-(4) hold and
381
    // minHeap_.top()->key() is the first key >= k from any children_ that is
382
    // not covered by any range tombstone.
383
50.6k
    FindNextVisibleKey();
384
50.6k
    current_ = CurrentForward();
385
50.6k
  }
386
387
50.6k
  bool NextAndGetResult(IterateResult* result) override {
388
50.6k
    Next();
389
50.6k
    bool is_valid = Valid();
390
50.6k
    if (is_valid) {
391
44.9k
      result->key = key();
392
44.9k
      result->bound_check_result = UpperBoundCheckResult();
393
44.9k
      result->value_prepared = current_->IsValuePrepared();
394
44.9k
    }
395
50.6k
    return is_valid;
396
50.6k
  }
397
398
10.9k
  void Prev() override {
399
10.9k
    assert(Valid());
400
    // Ensure that all children are positioned before key().
401
    // If we are moving in the reverse direction, it is already
402
    // true for all the non-current children since current_ is
403
    // the largest child and key() == current_->key().
404
10.9k
    if (direction_ != kReverse) {
405
      // Otherwise, retreat the non-current children.  We retreat current_
406
      // just after the if-block.
407
463
      SwitchToBackward();
408
463
    }
409
410
    // For the heap modifications below to be correct, current_ must be the
411
    // current top of the heap.
412
10.9k
    assert(current_ == CurrentReverse());
413
10.9k
    current_->Prev();
414
10.9k
    if (current_->Valid()) {
415
      // current is still valid after the Prev() call above.  Call
416
      // replace_top() to restore the heap property.  When the same child
417
      // iterator yields a sequence of keys, this is cheap.
418
6.32k
      assert(current_->status().ok());
419
6.32k
      maxHeap_->replace_top(maxHeap_->top());
420
6.32k
    } else {
421
      // current stopped being valid, remove it from the heap.
422
4.66k
      considerStatus(current_->status());
423
4.66k
      maxHeap_->pop();
424
4.66k
    }
425
10.9k
    FindPrevVisibleKey();
426
10.9k
    current_ = CurrentReverse();
427
10.9k
  }
428
429
78.6k
  Slice key() const override {
430
78.6k
    assert(Valid());
431
78.6k
    return current_->key();
432
78.6k
  }
433
434
44.1k
  uint64_t write_unix_time() const override {
435
44.1k
    assert(Valid());
436
44.1k
    return current_->write_unix_time();
437
44.1k
  }
438
439
44.1k
  Slice value() const override {
440
44.1k
    assert(Valid());
441
44.1k
    return current_->value();
442
44.1k
  }
443
444
15.8k
  bool PrepareValue() override {
445
15.8k
    assert(Valid());
446
15.8k
    if (current_->PrepareValue()) {
447
15.8k
      return true;
448
15.8k
    }
449
450
0
    considerStatus(current_->status());
451
0
    assert(!status_.ok());
452
0
    return false;
453
15.8k
  }
454
455
  // Here we simply relay MayBeOutOfLowerBound/MayBeOutOfUpperBound result
456
  // from current child iterator. Potentially as long as one of child iterator
457
  // report out of bound is not possible, we know current key is within bound.
458
0
  bool MayBeOutOfLowerBound() override {
459
0
    assert(Valid());
460
0
    return current_->MayBeOutOfLowerBound();
461
0
  }
462
463
44.9k
  IterBoundCheck UpperBoundCheckResult() override {
464
44.9k
    assert(Valid());
465
44.9k
    return current_->UpperBoundCheckResult();
466
44.9k
  }
467
468
9.70k
  void SetPinnedItersMgr(PinnedIteratorsManager* pinned_iters_mgr) override {
469
9.70k
    pinned_iters_mgr_ = pinned_iters_mgr;
470
26.4k
    for (auto& child : children_) {
471
26.4k
      child.iter.SetPinnedItersMgr(pinned_iters_mgr);
472
26.4k
    }
473
9.70k
  }
474
475
8.64k
  bool IsKeyPinned() const override {
476
8.64k
    assert(Valid());
477
8.64k
    return pinned_iters_mgr_ && pinned_iters_mgr_->PinningEnabled() &&
478
113
           current_->IsKeyPinned();
479
8.64k
  }
480
481
6.65k
  bool IsValuePinned() const override {
482
6.65k
    assert(Valid());
483
6.65k
    return pinned_iters_mgr_ && pinned_iters_mgr_->PinningEnabled() &&
484
6.65k
           current_->IsValuePinned();
485
6.65k
  }
486
487
0
  void Prepare(const MultiScanArgs* scan_opts) override {
488
0
    for (auto& child : children_) {
489
0
      child.iter.Prepare(scan_opts);
490
0
    }
491
0
  }
492
493
 private:
494
  // Represents an element in the min/max heap. Each HeapItem corresponds to a
495
  // point iterator or a range tombstone iterator, differentiated by
496
  // HeapItem::type.
497
  struct HeapItem {
498
17.7k
    HeapItem() = default;
499
500
    // corresponding point iterator
501
    IteratorWrapper iter;
502
    size_t level = 0;
503
    // corresponding range tombstone iterator's start or end key value
504
    // depending on value of `type`.
505
    ParsedInternalKey tombstone_pik;
506
    // Will be overwritten before use, initialize here so compiler does not
507
    // complain.
508
    enum class Type { ITERATOR, DELETE_RANGE_START, DELETE_RANGE_END };
509
    Type type = Type::ITERATOR;
510
511
    explicit HeapItem(size_t _level, InternalIteratorBase<Slice>* _iter)
512
26.4k
        : level(_level), type(Type::ITERATOR) {
513
26.4k
      iter.Set(_iter);
514
26.4k
    }
515
516
187k
    void SetTombstoneKey(ParsedInternalKey&& pik) {
517
      // op_type is already initialized in MergingIterator::Finish().
518
187k
      tombstone_pik.user_key = pik.user_key;
519
187k
      tombstone_pik.sequence = pik.sequence;
520
187k
    }
521
  };
522
523
  class MinHeapItemComparator {
524
   public:
525
    explicit MinHeapItemComparator(const InternalKeyComparator* comparator)
526
16.1k
        : comparator_(comparator) {}
527
528
150k
    bool operator()(HeapItem* a, HeapItem* b) const {
529
150k
      if (LIKELY(a->type == HeapItem::Type::ITERATOR)) {
530
37.8k
        if (LIKELY(b->type == HeapItem::Type::ITERATOR)) {
531
15.5k
          return comparator_->Compare(a->iter.key(), b->iter.key()) > 0;
532
22.3k
        } else {
533
22.3k
          return comparator_->Compare(a->iter.key(), b->tombstone_pik) > 0;
534
22.3k
        }
535
112k
      } else {
536
112k
        if (LIKELY(b->type == HeapItem::Type::ITERATOR)) {
537
112k
          return comparator_->Compare(a->tombstone_pik, b->iter.key()) > 0;
538
112k
        } else {
539
0
          return comparator_->Compare(a->tombstone_pik, b->tombstone_pik) > 0;
540
0
        }
541
112k
      }
542
150k
    }
543
544
   private:
545
    const InternalKeyComparator* comparator_;
546
  };
547
548
  class MaxHeapItemComparator {
549
   public:
550
    explicit MaxHeapItemComparator(const InternalKeyComparator* comparator)
551
3.03k
        : comparator_(comparator) {}
552
553
14.9k
    bool operator()(HeapItem* a, HeapItem* b) const {
554
14.9k
      if (LIKELY(a->type == HeapItem::Type::ITERATOR)) {
555
14.9k
        if (LIKELY(b->type == HeapItem::Type::ITERATOR)) {
556
14.9k
          return comparator_->Compare(a->iter.key(), b->iter.key()) < 0;
557
14.9k
        } else {
558
0
          return comparator_->Compare(a->iter.key(), b->tombstone_pik) < 0;
559
0
        }
560
14.9k
      } else {
561
0
        if (LIKELY(b->type == HeapItem::Type::ITERATOR)) {
562
0
          return comparator_->Compare(a->tombstone_pik, b->iter.key()) < 0;
563
0
        } else {
564
0
          return comparator_->Compare(a->tombstone_pik, b->tombstone_pik) < 0;
565
0
        }
566
0
      }
567
14.9k
    }
568
569
   private:
570
    const InternalKeyComparator* comparator_;
571
  };
572
573
  using MergerMinIterHeap = BinaryHeap<HeapItem*, MinHeapItemComparator>;
574
  using MergerMaxIterHeap = BinaryHeap<HeapItem*, MaxHeapItemComparator>;
575
576
  friend class MergeIteratorBuilder;
577
  // Clears heaps for both directions, used when changing direction or seeking
578
  void ClearHeaps(bool clear_active = true);
579
  // Ensures that maxHeap_ is initialized when starting to go in the reverse
580
  // direction
581
  void InitMaxHeap();
582
  // Advance this merging iterator until the current key (minHeap_.top()) is
583
  // from a point iterator and is not covered by any range tombstone,
584
  // or that there is no more keys (heap is empty). SeekImpl() may be called
585
  // to seek to the end of a range tombstone as an optimization.
586
  void FindNextVisibleKey();
587
  void FindPrevVisibleKey();
588
589
  // Advance this merging iterators to the first key >= `target` for all
590
  // components from levels >= starting_level. All iterators before
591
  // starting_level are untouched.
592
  //
593
  // @param range_tombstone_reseek Whether target is some range tombstone
594
  // end, i.e., whether this SeekImpl() call is a part of a "cascading seek".
595
  // This is used only for recoding relevant perf_context.
596
  void SeekImpl(const Slice& target, size_t starting_level = 0,
597
                bool range_tombstone_reseek = false);
598
599
  // Seek to fist key <= target key (internal key) for
600
  // children_[starting_level:].
601
  void SeekForPrevImpl(const Slice& target, size_t starting_level = 0,
602
                       bool range_tombstone_reseek = false);
603
604
  bool is_arena_mode_;
605
  bool prefix_seek_mode_;
606
  // Which direction is the iterator moving?
607
  enum Direction : uint8_t { kForward, kReverse };
608
  Direction direction_;
609
  const InternalKeyComparator* comparator_;
610
  // HeapItem for all child point iterators.
611
  // Invariant(children_): children_[i] is in minHeap_ iff
612
  // children_[i].iter.Valid(), and at most one children_[i] is in minHeap_.
613
  // TODO: We could use an autovector with a larger reserved size.
614
  std::vector<HeapItem> children_;
615
  // HeapItem for range tombstone start and end keys.
616
  // pinned_heap_item_[i] corresponds to range_tombstone_iters_[i].
617
  // Invariant(phi): If range_tombstone_iters_[i]->Valid(),
618
  // pinned_heap_item_[i].tombstone_pik is equal to
619
  // range_tombstone_iters_[i]->start_key() when
620
  // pinned_heap_item_[i].type is DELETE_RANGE_START and
621
  // range_tombstone_iters_[i]->end_key() when
622
  // pinned_heap_item_[i].type is DELETE_RANGE_END (ignoring op_type which is
623
  // kMaxValid for all pinned_heap_item_.tombstone_pik).
624
  // pinned_heap_item_[i].type is either DELETE_RANGE_START or DELETE_RANGE_END.
625
  std::vector<HeapItem> pinned_heap_item_;
626
  // range_tombstone_iters_[i] contains range tombstones in the sorted run that
627
  // corresponds to children_[i]. range_tombstone_iters_.empty() means not
628
  // handling range tombstones in merging iterator. range_tombstone_iters_[i] ==
629
  // nullptr means the sorted run of children_[i] does not have range
630
  // tombstones.
631
  // Invariant(rti): pinned_heap_item_[i] is in minHeap_ iff
632
  // range_tombstone_iters_[i]->Valid() and at most one pinned_heap_item_[i] is
633
  // in minHeap_.
634
  std::vector<std::unique_ptr<TruncatedRangeDelIterator>>
635
      range_tombstone_iters_;
636
637
  // Levels (indices into range_tombstone_iters_/children_ ) that currently have
638
  // "active" range tombstones. See comments above MergingIterator for meaning
639
  // of "active".
640
  // Invariant(active_): i is in active_ iff range_tombstone_iters_[i]->Valid()
641
  // and pinned_heap_item_[i].type == DELETE_RANGE_END.
642
  std::set<size_t> active_;
643
644
  bool SkipNextDeleted();
645
646
  bool SkipPrevDeleted();
647
648
  // Invariant: at the end of each InternalIterator API,
649
  // current_ points to minHeap_.top().iter (maxHeap_ if backward scanning)
650
  // or nullptr if no child iterator is valid.
651
  // This follows from that current_ = CurrentForward()/CurrentReverse() is
652
  // called at the end of each InternalIterator API.
653
  IteratorWrapper* current_;
654
  // If any of the children have non-ok status, this is one of them.
655
  Status status_;
656
  // Invariant: min heap property is maintained (parent is always <= child).
657
  // This holds by using only BinaryHeap APIs to modify heap. One
658
  // exception is to modify heap top item directly (by caller iter->Next()), and
659
  // it should be followed by a call to replace_top() or pop().
660
  MergerMinIterHeap minHeap_;
661
662
  // Max heap is used for reverse iteration, which is way less common than
663
  // forward. Lazily initialize it to save memory.
664
  std::unique_ptr<MergerMaxIterHeap> maxHeap_;
665
  PinnedIteratorsManager* pinned_iters_mgr_;
666
667
  // Used to bound range tombstones. For point keys, DBIter and SSTable iterator
668
  // take care of boundary checking.
669
  const Slice* iterate_upper_bound_;
670
671
  // In forward direction, process a child that is not in the min heap.
672
  // If valid, add to the min heap. Otherwise, check status.
673
  void AddToMinHeapOrCheckStatus(HeapItem*);
674
675
  // In backward direction, process a child that is not in the max heap.
676
  // If valid, add to the min heap. Otherwise, check status.
677
  void AddToMaxHeapOrCheckStatus(HeapItem*);
678
679
  void SwitchToForward();
680
681
  // Switch the direction from forward to backward without changing the
682
  // position. Iterator should still be valid.
683
  void SwitchToBackward();
684
685
58.0k
  IteratorWrapper* CurrentForward() const {
686
58.0k
    assert(direction_ == kForward);
687
58.0k
    assert(minHeap_.empty() ||
688
58.0k
           minHeap_.top()->type == HeapItem::Type::ITERATOR);
689
58.0k
    return !minHeap_.empty() ? &minHeap_.top()->iter : nullptr;
690
58.0k
  }
691
692
14.4k
  IteratorWrapper* CurrentReverse() const {
693
14.4k
    assert(direction_ == kReverse);
694
14.4k
    assert(maxHeap_);
695
14.4k
    assert(maxHeap_->empty() ||
696
14.4k
           maxHeap_->top()->type == HeapItem::Type::ITERATOR);
697
14.4k
    return !maxHeap_->empty() ? &maxHeap_->top()->iter : nullptr;
698
14.4k
  }
699
};
700
701
// Pre-condition:
702
// - Invariants (3) and (4) hold for i < starting_level
703
// - For i < starting_level, range_tombstone_iters_[i].prev.end_key() <
704
// `target`.
705
// - For i < starting_level, if i in active_, then
706
// range_tombstone_iters_[i]->start_key() < `target`.
707
//
708
// Post-condition:
709
// - Invariants (3) and (4) hold for all level i.
710
// - (*) target <= children_[i].iter.key() <= LevelNextVisible(i, target)
711
// for i >= starting_level
712
// - (**) target < pinned_heap_item_[i].tombstone_pik if
713
// range_tombstone_iters_[i].Valid() for i >= starting_level
714
//
715
// Proof sketch:
716
// Invariant (3) holds for all level i.
717
// For j <= i < starting_level, it follows from Pre-condition that (3) holds
718
// and that SeekImpl(-, starting_level) does not update children_[i] or
719
// range_tombstone_iters_[j].
720
// For j < starting_level and i >= starting_level, it follows from
721
// - Pre-condition that range_tombstone_iters_[j].prev.end_key() < `target`
722
// - range_tombstone_iters_[j] is not updated in SeekImpl(), and
723
// - children_[i].iter.Seek(current_search_key) is called with
724
// current_search_key >= target (shown below).
725
//   When current_search_key is updated, it is updated to some
726
//   range_tombstone_iter->end_key() after
727
//   range_tombstone_iter->SeekInternalKey(current_search_key) was called. So
728
//   current_search_key increases if updated and >= target.
729
// For starting_level <= j <= i:
730
// children_[i].iter.Seek(k1) and range_tombstone_iters_[j]->SeekInternalKey(k2)
731
// are called in SeekImpl(). Seek(k1) positions children_[i] at the first key >=
732
// k1 from level i. SeekInternalKey(k2) positions range_tombstone_iters_[j] at
733
// the first range tombstone from level j with end_key() > k2. It suffices to
734
// show that k1 >= k2. Since k1 and k2 are values of current_search_key where
735
// k1 = k2 or k1 is value of a later current_search_key than k2, so k1 >= k2.
736
//
737
// Invariant (4) holds for all level >= 0.
738
// By Pre-condition Invariant (4) holds for i < starting_level.
739
// Since children_[i], range_tombstone_iters_[i] and contents of active_ for
740
// i < starting_level do not change (4) holds for j <= i < starting_level.
741
// By Pre-condition: for all j < starting_level, if j in active_, then
742
// range_tombstone_iters_[j]->start_key() < target. For i >= starting_level,
743
// children_[i].iter.Seek(k) is called for k >= target. So
744
// children_[i].iter.key() >= target > range_tombstone_iters_[j]->start_key()
745
// for j < starting_level and i >= starting_level. So invariant (4) holds for
746
// j < starting_level and i >= starting_level.
747
// For starting_level <= j <= i, j is added to active_ only if
748
// - range_tombstone_iters_[j]->SeekInternalKey(k1) was called
749
// - range_tombstone_iters_[j]->start_key() <= k1
750
// Since children_[i].iter.Seek(k2) is called for some k2 >= k1 and for all
751
// starting_level <= j <= i, (4) also holds for all starting_level <= j <= i.
752
//
753
// Post-condition (*): target <= children_[i].iter.key() <= LevelNextVisible(i,
754
// target) for i >= starting_level.
755
// target <= children_[i].iter.key() follows from that Seek() is called on some
756
// current_search_key >= target for children_[i].iter. If current_search_key
757
// is updated from k1 to k2 when level = i, we show that the range [k1, k2) is
758
// not visible for children_[j] for any j > i. When current_search_key is
759
// updated from k1 to k2,
760
//  - range_tombstone_iters_[i]->SeekInternalKey(k1) was called
761
//  - range_tombstone_iters_[i]->Valid()
762
//  - range_tombstone_iters_[i]->start_key().user_key <= k1.user_key
763
//  - k2 = range_tombstone_iters_[i]->end_key()
764
// We assume that range_tombstone_iters_[i]->start_key() has a higher sequence
765
// number compared to any key from levels > i that has the same user key. So no
766
// point key from levels > i in range [k1, k2) is visible. So
767
// children_[i].iter.key() <= LevelNextVisible(i, target).
768
//
769
// Post-condition (**) target < pinned_heap_item_[i].tombstone_pik for i >=
770
// starting_level if range_tombstone_iters_[i].Valid(). This follows from that
771
// SeekInternalKey() being called for each range_tombstone_iters_ with some key
772
// >= `target` and that we pick start/end key that is > `target` to insert to
773
// minHeap_.
774
void MergingIterator::SeekImpl(const Slice& target, size_t starting_level,
775
702
                               bool range_tombstone_reseek) {
776
  // active range tombstones before `starting_level` remain active
777
702
  ClearHeaps(false /* clear_active */);
778
702
  ParsedInternalKey pik;
779
702
  if (!range_tombstone_iters_.empty()) {
780
    // pik is only used in InsertRangeTombstoneToMinHeap().
781
519
    ParseInternalKey(target, &pik, false).PermitUncheckedError();
782
519
  }
783
784
  // TODO: perhaps we could save some upheap cost by add all child iters first
785
  //  and then do a single heapify.
786
  // Invariant(children_) for level < starting_level
787
702
  for (size_t level = 0; level < starting_level; ++level) {
788
0
    PERF_TIMER_GUARD(seek_min_heap_time);
789
0
    AddToMinHeapOrCheckStatus(&children_[level]);
790
0
  }
791
702
  if (!range_tombstone_iters_.empty()) {
792
    // Add range tombstones from levels < starting_level. We can insert from
793
    // pinned_heap_item_ for the following reasons:
794
    // - pinned_heap_item_[level] is in minHeap_ iff
795
    // range_tombstone_iters[level]->Valid().
796
    // - If `level` is in active_, then range_tombstone_iters_[level]->Valid()
797
    // and pinned_heap_item_[level] is of type RANGE_DELETION_END.
798
519
    for (size_t level = 0; level < starting_level; ++level) {
799
      // Restores Invariants(rti), (phi) and (active_) for level <
800
      // starting_level
801
0
      if (range_tombstone_iters_[level] &&
802
0
          range_tombstone_iters_[level]->Valid()) {
803
        // use an iterator on active_ if performance becomes an issue here
804
0
        if (active_.count(level) > 0) {
805
0
          assert(pinned_heap_item_[level].type ==
806
0
                 HeapItem::Type::DELETE_RANGE_END);
807
          // if it was active, then start key must be within upper_bound,
808
          // so we can add to minHeap_ directly.
809
0
          minHeap_.push(&pinned_heap_item_[level]);
810
0
        } else {
811
0
          assert(pinned_heap_item_[level].type ==
812
0
                 HeapItem::Type::DELETE_RANGE_START);
813
          // this takes care of checking iterate_upper_bound, but with an extra
814
          // key comparison if range_tombstone_iters_[level] was already out of
815
          // bound. Consider using a new HeapItem type or some flag to remember
816
          // boundary checking result.
817
0
          InsertRangeTombstoneToMinHeap(level);
818
0
        }
819
0
      } else {
820
0
        assert(!active_.count(level));
821
0
      }
822
0
    }
823
    // levels >= starting_level will be reseeked below, so clearing their active
824
    // state here.
825
519
    active_.erase(active_.lower_bound(starting_level), active_.end());
826
519
  }
827
828
702
  IterKey current_search_key;
829
702
  current_search_key.SetInternalKey(target, false /* copy */);
830
  // Seek target might change to some range tombstone end key, so
831
  // we need to remember them for async requests.
832
  // (level, target) pairs
833
702
  autovector<std::pair<size_t, std::string>> prefetched_target;
834
3.48k
  for (auto level = starting_level; level < children_.size(); ++level) {
835
2.78k
    {
836
2.78k
      PERF_TIMER_GUARD(seek_child_seek_time);
837
2.78k
      children_[level].iter.Seek(current_search_key.GetInternalKey());
838
2.78k
    }
839
840
2.78k
    PERF_COUNTER_ADD(seek_child_seek_count, 1);
841
842
2.78k
    if (!range_tombstone_iters_.empty()) {
843
2.23k
      if (range_tombstone_reseek) {
844
        // This seek is to some range tombstone end key.
845
        // Should only happen when there are range tombstones.
846
0
        PERF_COUNTER_ADD(internal_range_del_reseek_count, 1);
847
0
      }
848
2.23k
      if (children_[level].iter.status().IsTryAgain()) {
849
0
        prefetched_target.emplace_back(
850
0
            level, current_search_key.GetInternalKey().ToString());
851
0
      }
852
2.23k
      UnownedPtr<TruncatedRangeDelIterator> range_tombstone_iter =
853
2.23k
          range_tombstone_iters_[level].get();
854
2.23k
      if (range_tombstone_iter) {
855
0
        range_tombstone_iter->SeekInternalKey(
856
0
            current_search_key.GetInternalKey());
857
        // Invariants (rti) and (phi)
858
0
        if (range_tombstone_iter->Valid()) {
859
          // If range tombstone starts after `current_search_key`,
860
          // we should insert start key to heap as the range tombstone is not
861
          // active yet.
862
0
          InsertRangeTombstoneToMinHeap(
863
0
              level, comparator_->Compare(range_tombstone_iter->start_key(),
864
0
                                          pik) > 0 /* start_key */);
865
          // current_search_key < end_key guaranteed by the SeekInternalKey()
866
          // and Valid() calls above. Here we only need to compare user_key
867
          // since if target.user_key ==
868
          // range_tombstone_iter->start_key().user_key and target <
869
          // range_tombstone_iter->start_key(), no older level would have any
870
          // key in range [target, range_tombstone_iter->start_key()], so no
871
          // keys in range [target, range_tombstone_iter->end_key()) from older
872
          // level would be visible. So it is safe to seek to
873
          // range_tombstone_iter->end_key().
874
          //
875
          // TODO: range_tombstone_iter->Seek() finds the max covering
876
          //  sequence number, can make it cheaper by not looking for max.
877
0
          if (comparator_->user_comparator()->Compare(
878
0
                  range_tombstone_iter->start_key().user_key,
879
0
                  current_search_key.GetUserKey()) <= 0) {
880
0
            range_tombstone_reseek = true;
881
            // Note that for prefix seek case, it is possible that the prefix
882
            // is not the same as the original target, it should not affect
883
            // correctness. Besides, in most cases, range tombstone start and
884
            // end key should have the same prefix?
885
0
            current_search_key.SetInternalKey(range_tombstone_iter->end_key());
886
0
          }
887
0
        }
888
0
      }
889
2.23k
    }
890
    // child.iter.status() is set to Status::TryAgain indicating asynchronous
891
    // request for retrieval of data blocks has been submitted. So it should
892
    // return at this point and Seek should be called again to retrieve the
893
    // requested block and add the child to min heap.
894
2.78k
    if (children_[level].iter.status().IsTryAgain()) {
895
0
      continue;
896
0
    }
897
2.78k
    {
898
      // Strictly, we timed slightly more than min heap operation,
899
      // but these operations are very cheap.
900
2.78k
      PERF_TIMER_GUARD(seek_min_heap_time);
901
2.78k
      AddToMinHeapOrCheckStatus(&children_[level]);
902
2.78k
    }
903
2.78k
  }
904
905
702
  if (range_tombstone_iters_.empty()) {
906
549
    for (auto& child : children_) {
907
549
      if (child.iter.status().IsTryAgain()) {
908
0
        child.iter.Seek(target);
909
0
        {
910
0
          PERF_TIMER_GUARD(seek_min_heap_time);
911
0
          AddToMinHeapOrCheckStatus(&child);
912
0
        }
913
0
        PERF_COUNTER_ADD(number_async_seek, 1);
914
0
      }
915
549
    }
916
519
  } else {
917
519
    for (auto& prefetch : prefetched_target) {
918
      // (level, target) pairs
919
0
      children_[prefetch.first].iter.Seek(prefetch.second);
920
0
      {
921
0
        PERF_TIMER_GUARD(seek_min_heap_time);
922
0
        AddToMinHeapOrCheckStatus(&children_[prefetch.first]);
923
0
      }
924
0
      PERF_COUNTER_ADD(number_async_seek, 1);
925
0
    }
926
519
  }
927
702
}
928
929
// Returns true iff the current key (min heap top) should not be returned
930
// to user (of the merging iterator). This can be because the current key
931
// is deleted by some range tombstone, the current key is some fake file
932
// boundary sentinel key, or the current key is an end point of a range
933
// tombstone. Advance the iterator at heap top if needed. Heap order is restored
934
// and `active_` is updated accordingly.
935
// See FindNextVisibleKey() for more detail on internal implementation
936
// of advancing child iters.
937
// When false is returned, if minHeap is not empty, then minHeap_.top().type
938
// == ITERATOR
939
//
940
// REQUIRES:
941
// - min heap is currently not empty, and iter is in kForward direction.
942
// - minHeap_ top is not DELETE_RANGE_START (so that `active_` is current).
943
110k
bool MergingIterator::SkipNextDeleted() {
944
  // 3 types of keys:
945
  // - point key
946
  // - file boundary sentinel keys
947
  // - range deletion end key
948
110k
  auto current = minHeap_.top();
949
110k
  if (current->type == HeapItem::Type::DELETE_RANGE_END) {
950
    // Invariant(active_): range_tombstone_iters_[current->level] is about to
951
    // become !Valid() or that its start key is going to be added to minHeap_.
952
93.9k
    active_.erase(current->level);
953
93.9k
    assert(range_tombstone_iters_[current->level] &&
954
93.9k
           range_tombstone_iters_[current->level]->Valid());
955
93.9k
    range_tombstone_iters_[current->level]->Next();
956
    // Maintain Invariants (rti) and (phi)
957
93.9k
    if (range_tombstone_iters_[current->level]->Valid()) {
958
91.0k
      InsertRangeTombstoneToMinHeap(current->level, true /* start_key */,
959
91.0k
                                    true /* replace_top */);
960
91.0k
    } else {
961
      // TruncatedRangeDelIterator does not have status
962
2.87k
      minHeap_.pop();
963
2.87k
    }
964
93.9k
    return true /* current key deleted */;
965
93.9k
  }
966
16.8k
  if (current->iter.IsDeleteRangeSentinelKey()) {
967
    // If the file boundary is defined by a range deletion, the range
968
    // tombstone's end key must come before this sentinel key (see op_type in
969
    // SetTombstoneKey()).
970
3.00k
    assert(ExtractValueType(current->iter.key()) != kTypeRangeDeletion ||
971
3.00k
           active_.count(current->level) == 0);
972
    // When entering a new file, range tombstone iter from the old file is
973
    // freed, but the last key from that range tombstone iter may still be in
974
    // the heap. We need to ensure the data underlying its corresponding key
975
    // Slice is still alive. We do so by popping the range tombstone key from
976
    // heap before calling iter->Next(). Technically, this change is not needed:
977
    // if there is a range tombstone end key that is after file boundary
978
    // sentinel key in minHeap_, the range tombstone end key must have been
979
    // truncated at file boundary. The underlying data of the range tombstone
980
    // end key Slice is the SST file's largest internal key stored as file
981
    // metadata in Version. However, since there are too many implicit
982
    // assumptions made, it is safer to just ensure range tombstone iter is
983
    // still alive.
984
3.00k
    minHeap_.pop();
985
    // Remove last SST file's range tombstone end key if there is one.
986
    // This means file boundary is before range tombstone end key,
987
    // which could happen when a range tombstone and a user key
988
    // straddle two SST files. Note that in TruncatedRangeDelIterator
989
    // constructor, parsed_largest.sequence is decremented 1 in this case.
990
    // Maintains Invariant(rti) that at most one
991
    // pinned_heap_item_[current->level] is in minHeap_.
992
3.00k
    if (range_tombstone_iters_[current->level] &&
993
0
        range_tombstone_iters_[current->level]->Valid()) {
994
0
      if (!minHeap_.empty() && minHeap_.top()->level == current->level) {
995
0
        assert(minHeap_.top()->type == HeapItem::Type::DELETE_RANGE_END);
996
0
        minHeap_.pop();
997
        // Invariant(active_): we are about to enter a new SST file with new
998
        // range_tombstone_iters[current->level]. Either it is !Valid() or its
999
        // start key is going to be added to minHeap_.
1000
0
        active_.erase(current->level);
1001
0
      } else {
1002
        // range tombstone is still valid, but it is not on heap.
1003
        // This should only happen if the range tombstone is over iterator
1004
        // upper bound.
1005
0
        assert(iterate_upper_bound_ &&
1006
0
               comparator_->user_comparator()->CompareWithoutTimestamp(
1007
0
                   range_tombstone_iters_[current->level]->start_key().user_key,
1008
0
                   true /* a_has_ts */, *iterate_upper_bound_,
1009
0
                   false /* b_has_ts */) >= 0);
1010
0
      }
1011
0
    }
1012
    // LevelIterator enters a new SST file
1013
3.00k
    current->iter.Next();
1014
    // Invariant(children_): current is popped from heap and added back only if
1015
    // it is valid
1016
3.00k
    if (current->iter.Valid()) {
1017
1.56k
      assert(current->iter.status().ok());
1018
1.56k
      minHeap_.push(current);
1019
1.56k
    } else {
1020
      // TODO(cbi): check status and early return if non-ok.
1021
1.44k
      considerStatus(current->iter.status());
1022
1.44k
    }
1023
    // Invariants (rti) and (phi)
1024
3.00k
    if (range_tombstone_iters_[current->level] &&
1025
0
        range_tombstone_iters_[current->level]->Valid()) {
1026
0
      InsertRangeTombstoneToMinHeap(current->level);
1027
0
    }
1028
3.00k
    return true /* current key deleted */;
1029
3.00k
  }
1030
16.8k
  assert(current->type == HeapItem::Type::ITERATOR);
1031
  // Point key case: check active_ for range tombstone coverage.
1032
13.8k
  ParsedInternalKey pik;
1033
13.8k
  ParseInternalKey(current->iter.key(), &pik, false).PermitUncheckedError();
1034
13.8k
  if (!active_.empty()) {
1035
13.8k
    auto i = *active_.begin();
1036
13.8k
    if (i < current->level) {
1037
      // range tombstone is from a newer level, definitely covers
1038
0
      assert(comparator_->Compare(range_tombstone_iters_[i]->start_key(),
1039
0
                                  pik) <= 0);
1040
0
      assert(comparator_->Compare(pik, range_tombstone_iters_[i]->end_key()) <
1041
0
             0);
1042
0
      std::string target;
1043
0
      AppendInternalKey(&target, range_tombstone_iters_[i]->end_key());
1044
0
      SeekImpl(target, current->level, true);
1045
0
      return true /* current key deleted */;
1046
13.8k
    } else if (i == current->level) {
1047
      // range tombstone is from the same level as current, check sequence
1048
      // number. By `active_` we know current key is between start key and end
1049
      // key.
1050
13.8k
      assert(comparator_->Compare(range_tombstone_iters_[i]->start_key(),
1051
13.8k
                                  pik) <= 0);
1052
13.8k
      assert(comparator_->Compare(pik, range_tombstone_iters_[i]->end_key()) <
1053
13.8k
             0);
1054
13.8k
      if (pik.sequence < range_tombstone_iters_[current->level]->seq()) {
1055
        // covered by range tombstone
1056
0
        current->iter.Next();
1057
        // Invariant (children_)
1058
0
        if (current->iter.Valid()) {
1059
0
          minHeap_.replace_top(current);
1060
0
        } else {
1061
0
          considerStatus(current->iter.status());
1062
0
          minHeap_.pop();
1063
0
        }
1064
0
        return true /* current key deleted */;
1065
13.8k
      } else {
1066
13.8k
        return false /* current key not deleted */;
1067
13.8k
      }
1068
13.8k
    } else {
1069
0
      return false /* current key not deleted */;
1070
      // range tombstone from an older sorted run with current key < end key.
1071
      // current key is not deleted and the older sorted run will have its range
1072
      // tombstone updated when the range tombstone's end key are popped from
1073
      // minHeap_.
1074
0
    }
1075
13.8k
  }
1076
  // we can reach here only if active_ is empty
1077
13.8k
  assert(active_.empty());
1078
0
  assert(minHeap_.top()->type == HeapItem::Type::ITERATOR);
1079
0
  return false /* current key not deleted */;
1080
13.8k
}
1081
1082
void MergingIterator::SeekForPrevImpl(const Slice& target,
1083
                                      size_t starting_level,
1084
3.03k
                                      bool range_tombstone_reseek) {
1085
  // active range tombstones before `starting_level` remain active
1086
3.03k
  ClearHeaps(false /* clear_active */);
1087
3.03k
  InitMaxHeap();
1088
3.03k
  ParsedInternalKey pik;
1089
3.03k
  if (!range_tombstone_iters_.empty()) {
1090
1.94k
    ParseInternalKey(target, &pik, false).PermitUncheckedError();
1091
1.94k
  }
1092
3.03k
  for (size_t level = 0; level < starting_level; ++level) {
1093
0
    PERF_TIMER_GUARD(seek_max_heap_time);
1094
0
    AddToMaxHeapOrCheckStatus(&children_[level]);
1095
0
  }
1096
3.03k
  if (!range_tombstone_iters_.empty()) {
1097
    // Add range tombstones before starting_level.
1098
1.94k
    for (size_t level = 0; level < starting_level; ++level) {
1099
0
      if (range_tombstone_iters_[level] &&
1100
0
          range_tombstone_iters_[level]->Valid()) {
1101
0
        assert(static_cast<bool>(active_.count(level)) ==
1102
0
               (pinned_heap_item_[level].type ==
1103
0
                HeapItem::Type::DELETE_RANGE_START));
1104
0
        maxHeap_->push(&pinned_heap_item_[level]);
1105
0
      } else {
1106
0
        assert(!active_.count(level));
1107
0
      }
1108
0
    }
1109
    // levels >= starting_level will be reseeked below,
1110
1.94k
    active_.erase(active_.lower_bound(starting_level), active_.end());
1111
1.94k
  }
1112
1113
3.03k
  IterKey current_search_key;
1114
3.03k
  current_search_key.SetInternalKey(target, false /* copy */);
1115
  // Seek target might change to some range tombstone end key, so
1116
  // we need to remember them for async requests.
1117
  // (level, target) pairs
1118
3.03k
  autovector<std::pair<size_t, std::string>> prefetched_target;
1119
12.9k
  for (auto level = starting_level; level < children_.size(); ++level) {
1120
9.95k
    {
1121
9.95k
      PERF_TIMER_GUARD(seek_child_seek_time);
1122
9.95k
      children_[level].iter.SeekForPrev(current_search_key.GetInternalKey());
1123
9.95k
    }
1124
1125
9.95k
    PERF_COUNTER_ADD(seek_child_seek_count, 1);
1126
1127
9.95k
    if (!range_tombstone_iters_.empty()) {
1128
6.55k
      if (range_tombstone_reseek) {
1129
        // This seek is to some range tombstone end key.
1130
        // Should only happen when there are range tombstones.
1131
0
        PERF_COUNTER_ADD(internal_range_del_reseek_count, 1);
1132
0
      }
1133
6.55k
      if (children_[level].iter.status().IsTryAgain()) {
1134
0
        prefetched_target.emplace_back(
1135
0
            level, current_search_key.GetInternalKey().ToString());
1136
0
      }
1137
6.55k
      UnownedPtr<TruncatedRangeDelIterator> range_tombstone_iter =
1138
6.55k
          range_tombstone_iters_[level].get();
1139
6.55k
      if (range_tombstone_iter) {
1140
0
        range_tombstone_iter->SeekForPrev(current_search_key.GetUserKey());
1141
0
        if (range_tombstone_iter->Valid()) {
1142
0
          InsertRangeTombstoneToMaxHeap(
1143
0
              level, comparator_->Compare(range_tombstone_iter->end_key(),
1144
0
                                          pik) <= 0 /* end_key */);
1145
          // start key <= current_search_key guaranteed by the Seek() call above
1146
          // Only interested in user key coverage since older sorted runs must
1147
          // have smaller sequence numbers than this tombstone.
1148
0
          if (comparator_->user_comparator()->Compare(
1149
0
                  current_search_key.GetUserKey(),
1150
0
                  range_tombstone_iter->end_key().user_key) < 0) {
1151
0
            range_tombstone_reseek = true;
1152
0
            current_search_key.SetInternalKey(
1153
0
                range_tombstone_iter->start_key().user_key, kMaxSequenceNumber,
1154
0
                kValueTypeForSeekForPrev);
1155
0
          }
1156
0
        }
1157
0
      }
1158
6.55k
    }
1159
    // child.iter.status() is set to Status::TryAgain indicating asynchronous
1160
    // request for retrieval of data blocks has been submitted. So it should
1161
    // return at this point and Seek should be called again to retrieve the
1162
    // requested block and add the child to min heap.
1163
9.95k
    if (children_[level].iter.status().IsTryAgain()) {
1164
0
      continue;
1165
0
    }
1166
9.95k
    {
1167
      // Strictly, we timed slightly more than min heap operation,
1168
      // but these operations are very cheap.
1169
9.95k
      PERF_TIMER_GUARD(seek_max_heap_time);
1170
9.95k
      AddToMaxHeapOrCheckStatus(&children_[level]);
1171
9.95k
    }
1172
9.95k
  }
1173
1174
3.03k
  if (range_tombstone_iters_.empty()) {
1175
3.40k
    for (auto& child : children_) {
1176
3.40k
      if (child.iter.status().IsTryAgain()) {
1177
0
        child.iter.SeekForPrev(target);
1178
0
        {
1179
0
          PERF_TIMER_GUARD(seek_min_heap_time);
1180
0
          AddToMaxHeapOrCheckStatus(&child);
1181
0
        }
1182
0
        PERF_COUNTER_ADD(number_async_seek, 1);
1183
0
      }
1184
3.40k
    }
1185
1.94k
  } else {
1186
1.94k
    for (auto& prefetch : prefetched_target) {
1187
      // (level, target) pairs
1188
0
      children_[prefetch.first].iter.SeekForPrev(prefetch.second);
1189
0
      {
1190
0
        PERF_TIMER_GUARD(seek_max_heap_time);
1191
0
        AddToMaxHeapOrCheckStatus(&children_[prefetch.first]);
1192
0
      }
1193
0
      PERF_COUNTER_ADD(number_async_seek, 1);
1194
0
    }
1195
1.94k
  }
1196
3.03k
}
1197
1198
// See more in comments above SkipNextDeleted().
1199
// REQUIRES:
1200
// - max heap is currently not empty, and iter is in kReverse direction.
1201
// - maxHeap_ top is not DELETE_RANGE_END (so that `active_` is current).
1202
3.51k
bool MergingIterator::SkipPrevDeleted() {
1203
  // 3 types of keys:
1204
  // - point key
1205
  // - file boundary sentinel keys
1206
  // - range deletion start key
1207
3.51k
  auto current = maxHeap_->top();
1208
3.51k
  if (current->type == HeapItem::Type::DELETE_RANGE_START) {
1209
0
    active_.erase(current->level);
1210
0
    assert(range_tombstone_iters_[current->level] &&
1211
0
           range_tombstone_iters_[current->level]->Valid());
1212
0
    range_tombstone_iters_[current->level]->Prev();
1213
0
    if (range_tombstone_iters_[current->level]->Valid()) {
1214
0
      InsertRangeTombstoneToMaxHeap(current->level, true /* end_key */,
1215
0
                                    true /* replace_top */);
1216
0
    } else {
1217
0
      maxHeap_->pop();
1218
0
    }
1219
0
    return true /* current key deleted */;
1220
0
  }
1221
3.51k
  if (current->iter.IsDeleteRangeSentinelKey()) {
1222
    // LevelIterator enters a new SST file
1223
3.51k
    maxHeap_->pop();
1224
    // Remove last SST file's range tombstone key if there is one.
1225
3.51k
    if (!maxHeap_->empty() && maxHeap_->top()->level == current->level &&
1226
0
        maxHeap_->top()->type == HeapItem::Type::DELETE_RANGE_START) {
1227
0
      maxHeap_->pop();
1228
0
      active_.erase(current->level);
1229
0
    }
1230
3.51k
    current->iter.Prev();
1231
3.51k
    if (current->iter.Valid()) {
1232
1.83k
      assert(current->iter.status().ok());
1233
1.83k
      maxHeap_->push(current);
1234
1.83k
    } else {
1235
1.68k
      considerStatus(current->iter.status());
1236
1.68k
    }
1237
1238
3.51k
    if (range_tombstone_iters_[current->level] &&
1239
0
        range_tombstone_iters_[current->level]->Valid()) {
1240
0
      InsertRangeTombstoneToMaxHeap(current->level);
1241
0
    }
1242
3.51k
    return true /* current key deleted */;
1243
3.51k
  }
1244
3.51k
  assert(current->type == HeapItem::Type::ITERATOR);
1245
  // Point key case: check active_ for range tombstone coverage.
1246
0
  ParsedInternalKey pik;
1247
0
  ParseInternalKey(current->iter.key(), &pik, false).PermitUncheckedError();
1248
0
  if (!active_.empty()) {
1249
0
    auto i = *active_.begin();
1250
0
    if (i < current->level) {
1251
      // range tombstone is from a newer level, definitely covers
1252
0
      assert(comparator_->Compare(range_tombstone_iters_[i]->start_key(),
1253
0
                                  pik) <= 0);
1254
0
      assert(comparator_->Compare(pik, range_tombstone_iters_[i]->end_key()) <
1255
0
             0);
1256
0
      std::string target;
1257
0
      AppendInternalKey(&target, range_tombstone_iters_[i]->start_key());
1258
      // This is different from SkipNextDeleted() which does reseek at sorted
1259
      // runs >= level (instead of i+1 here). With min heap, if level L is at
1260
      // top of the heap, then levels <L all have internal keys > level L's
1261
      // current internal key, which means levels <L are already at a different
1262
      // user key. With max heap, if level L is at top of the heap, then levels
1263
      // <L all have internal keys smaller than level L's current internal key,
1264
      // which might still be the same user key.
1265
0
      SeekForPrevImpl(target, i + 1, true);
1266
0
      return true /* current key deleted */;
1267
0
    } else if (i == current->level) {
1268
      // By `active_` we know current key is between start key and end key.
1269
0
      assert(comparator_->Compare(range_tombstone_iters_[i]->start_key(),
1270
0
                                  pik) <= 0);
1271
0
      assert(comparator_->Compare(pik, range_tombstone_iters_[i]->end_key()) <
1272
0
             0);
1273
0
      if (pik.sequence < range_tombstone_iters_[current->level]->seq()) {
1274
0
        current->iter.Prev();
1275
0
        if (current->iter.Valid()) {
1276
0
          maxHeap_->replace_top(current);
1277
0
        } else {
1278
0
          considerStatus(current->iter.status());
1279
0
          maxHeap_->pop();
1280
0
        }
1281
0
        return true /* current key deleted */;
1282
0
      } else {
1283
0
        return false /* current key not deleted */;
1284
0
      }
1285
0
    } else {
1286
0
      return false /* current key not deleted */;
1287
0
    }
1288
0
  }
1289
1290
0
  assert(active_.empty());
1291
0
  assert(maxHeap_->top()->type == HeapItem::Type::ITERATOR);
1292
0
  return false /* current key not deleted */;
1293
0
}
1294
1295
19.3k
void MergingIterator::AddToMinHeapOrCheckStatus(HeapItem* child) {
1296
  // Invariant(children_)
1297
19.3k
  if (child->iter.Valid()) {
1298
12.0k
    assert(child->iter.status().ok());
1299
12.0k
    minHeap_.push(child);
1300
12.0k
  } else {
1301
7.22k
    considerStatus(child->iter.status());
1302
7.22k
  }
1303
19.3k
}
1304
1305
11.8k
void MergingIterator::AddToMaxHeapOrCheckStatus(HeapItem* child) {
1306
11.8k
  if (child->iter.Valid()) {
1307
6.94k
    assert(child->iter.status().ok());
1308
6.94k
    maxHeap_->push(child);
1309
6.94k
  } else {
1310
4.91k
    considerStatus(child->iter.status());
1311
4.91k
  }
1312
11.8k
}
1313
1314
// Advance all non current_ child to > current_.key().
1315
// We advance current_ after the this function call as it does not require
1316
// Seek().
1317
// Advance all range tombstones iters, including the one corresponding to
1318
// current_, to the first tombstone with end_key > current_.key().
1319
// TODO: potentially do cascading seek here too
1320
// TODO: show that invariants hold
1321
0
void MergingIterator::SwitchToForward() {
1322
0
  ClearHeaps();
1323
0
  Slice target = key();
1324
0
  for (auto& child : children_) {
1325
0
    if (&child.iter != current_) {
1326
0
      child.iter.Seek(target);
1327
      // child.iter.status() is set to Status::TryAgain indicating asynchronous
1328
      // request for retrieval of data blocks has been submitted. So it should
1329
      // return at this point and Seek should be called again to retrieve the
1330
      // requested block and add the child to min heap.
1331
0
      if (child.iter.status() == Status::TryAgain()) {
1332
0
        continue;
1333
0
      }
1334
0
      if (child.iter.Valid() && comparator_->Equal(target, child.iter.key())) {
1335
0
        assert(child.iter.status().ok());
1336
0
        child.iter.Next();
1337
0
      }
1338
0
    }
1339
0
    AddToMinHeapOrCheckStatus(&child);
1340
0
  }
1341
1342
0
  for (auto& child : children_) {
1343
0
    if (child.iter.status() == Status::TryAgain()) {
1344
0
      child.iter.Seek(target);
1345
0
      if (child.iter.Valid() && comparator_->Equal(target, child.iter.key())) {
1346
0
        assert(child.iter.status().ok());
1347
0
        child.iter.Next();
1348
0
      }
1349
0
      AddToMinHeapOrCheckStatus(&child);
1350
0
    }
1351
0
  }
1352
1353
  // Current range tombstone iter also needs to seek for the following case:
1354
  // Previous direction is backward, so range tombstone iter may point to a
1355
  // tombstone before current_. If there is no such tombstone, then the range
1356
  // tombstone iter is !Valid(). Need to reseek here to make it valid again.
1357
0
  if (!range_tombstone_iters_.empty()) {
1358
0
    ParsedInternalKey pik;
1359
0
    ParseInternalKey(target, &pik, false /* log_err_key */)
1360
0
        .PermitUncheckedError();
1361
0
    for (size_t i = 0; i < range_tombstone_iters_.size(); ++i) {
1362
0
      UnownedPtr<TruncatedRangeDelIterator> iter =
1363
0
          range_tombstone_iters_[i].get();
1364
0
      if (iter) {
1365
0
        iter->Seek(pik.user_key);
1366
        // The while loop is needed as the Seek() call above is only for user
1367
        // key. We could have a range tombstone with end_key covering user_key,
1368
        // but still is smaller than target. This happens when the range
1369
        // tombstone is truncated at iter.largest_.
1370
0
        while (iter->Valid() &&
1371
0
               comparator_->Compare(iter->end_key(), pik) <= 0) {
1372
0
          iter->Next();
1373
0
        }
1374
0
        if (range_tombstone_iters_[i]->Valid()) {
1375
0
          InsertRangeTombstoneToMinHeap(
1376
0
              i, comparator_->Compare(range_tombstone_iters_[i]->start_key(),
1377
0
                                      pik) > 0 /* start_key */);
1378
0
        }
1379
0
      }
1380
0
    }
1381
0
  }
1382
1383
0
  direction_ = kForward;
1384
0
  assert(current_ == CurrentForward());
1385
0
}
1386
1387
// Advance all range tombstones iters, including the one corresponding to
1388
// current_, to the first tombstone with start_key <= current_.key().
1389
463
void MergingIterator::SwitchToBackward() {
1390
463
  ClearHeaps();
1391
463
  InitMaxHeap();
1392
463
  Slice target = key();
1393
1.90k
  for (auto& child : children_) {
1394
1.90k
    if (&child.iter != current_) {
1395
1.44k
      child.iter.SeekForPrev(target);
1396
1.44k
      TEST_SYNC_POINT_CALLBACK("MergeIterator::Prev:BeforePrev", &child);
1397
1.44k
      if (child.iter.Valid() && comparator_->Equal(target, child.iter.key())) {
1398
0
        assert(child.iter.status().ok());
1399
0
        child.iter.Prev();
1400
0
      }
1401
1.44k
    }
1402
1.90k
    AddToMaxHeapOrCheckStatus(&child);
1403
1.90k
  }
1404
1405
463
  ParsedInternalKey pik;
1406
463
  ParseInternalKey(target, &pik, false /* log_err_key */)
1407
463
      .PermitUncheckedError();
1408
2.01k
  for (size_t i = 0; i < range_tombstone_iters_.size(); ++i) {
1409
1.54k
    UnownedPtr<TruncatedRangeDelIterator> iter =
1410
1.54k
        range_tombstone_iters_[i].get();
1411
1.54k
    if (iter) {
1412
0
      iter->SeekForPrev(pik.user_key);
1413
      // Since the SeekForPrev() call above is only for user key,
1414
      // we may end up with some range tombstone with start key having the
1415
      // same user key at current_, but with a smaller sequence number. This
1416
      // makes current_ not at maxHeap_ top for the CurrentReverse() call
1417
      // below. If there is a range tombstone start key with the same user
1418
      // key and the same sequence number as current_.key(), it will be fine as
1419
      // in InsertRangeTombstoneToMaxHeap() we change op_type to be the smallest
1420
      // op_type.
1421
0
      while (iter->Valid() &&
1422
0
             comparator_->Compare(iter->start_key(), pik) > 0) {
1423
0
        iter->Prev();
1424
0
      }
1425
0
      if (iter->Valid()) {
1426
0
        InsertRangeTombstoneToMaxHeap(
1427
0
            i, comparator_->Compare(range_tombstone_iters_[i]->end_key(),
1428
0
                                    pik) <= 0 /* end_key */);
1429
0
      }
1430
0
    }
1431
1.54k
  }
1432
1433
463
  direction_ = kReverse;
1434
463
  if (!prefix_seek_mode_) {
1435
    // Note that we don't do assert(current_ == CurrentReverse()) here
1436
    // because it is possible to have some keys larger than the seek-key
1437
    // inserted between Seek() and SeekToLast(), which makes current_ not
1438
    // equal to CurrentReverse().
1439
463
    current_ = CurrentReverse();
1440
463
  }
1441
463
  assert(current_ == CurrentReverse());
1442
463
}
1443
1444
10.8k
void MergingIterator::ClearHeaps(bool clear_active) {
1445
10.8k
  minHeap_.clear();
1446
10.8k
  if (maxHeap_) {
1447
926
    maxHeap_->clear();
1448
926
  }
1449
10.8k
  if (clear_active) {
1450
7.13k
    active_.clear();
1451
7.13k
  }
1452
10.8k
}
1453
1454
3.49k
void MergingIterator::InitMaxHeap() {
1455
3.49k
  if (!maxHeap_) {
1456
3.03k
    maxHeap_ =
1457
3.03k
        std::make_unique<MergerMaxIterHeap>(MaxHeapItemComparator(comparator_));
1458
3.03k
  }
1459
3.49k
}
1460
1461
// Assume there is a next key that is not covered by range tombstone.
1462
// Pre-condition:
1463
// - Invariants (3) and (4)
1464
// - There is some k where k <= children_[i].iter.key() <= LevelNextVisible(i,
1465
// k) for all levels i (LevelNextVisible() defined in Seek()).
1466
//
1467
// Define NextVisible(k) to be the first key >= k from among children_ that
1468
// is not covered by any range tombstone.
1469
// Post-condition:
1470
// - Invariants (1)-(4) hold
1471
// - (*): minHeap_->top()->key() == NextVisible(k)
1472
//
1473
// Loop invariants:
1474
// - Invariants (3) and (4)
1475
// - (*): k <= children_[i].iter.key() <= LevelNextVisible(i, k)
1476
//
1477
// Progress: minHeap_.top()->key() is non-decreasing and strictly increases in
1478
// a finite number of iterations.
1479
// TODO: it is possible to call SeekImpl(k2) after SeekImpl(k1) with
1480
//  k2 < k1 in the same FindNextVisibleKey(). For example, l1 has a range
1481
//  tombstone [2,3) and l2 has a range tombstone [1, 4). Point key 1 from l5
1482
//  triggers SeekImpl(4 /* target */, 5). Then point key 2 from l3 triggers
1483
//  SeekImpl(3 /* target */, 3).
1484
//  Ideally we should only move iterators forward in SeekImpl(), and the
1485
//  progress condition can be made simpler: iterator only moves forward.
1486
//
1487
// Proof sketch:
1488
// Post-condition:
1489
// Invariant (1) holds when this method returns:
1490
// Ignoring the empty minHeap_ case, there are two cases:
1491
// Case 1: active_ is empty and !minHeap_.top()->iter.IsDeleteRangeSentinelKey()
1492
// By invariants (rti) and (active_), active_ being empty means if a
1493
// pinned_heap_item_[i] is in minHeap_, it has type DELETE_RANGE_START. Note
1494
// that PopDeleteRangeStart() was called right before the while loop condition,
1495
// so minHeap_.top() is not of type DELETE_RANGE_START. So minHeap_.top() must
1496
// be of type ITERATOR.
1497
// Case 2: SkipNextDeleted() returns false. The method returns false only when
1498
// minHeap_.top().type == ITERATOR.
1499
//
1500
// Invariant (2) holds when this method returns:
1501
// From Invariant (1), minHeap_.top().type == ITERATOR. Suppose it is
1502
// children_[i] for some i. Suppose that children_[i].iter.key() is covered by
1503
// some range tombstone. This means there is a j <= i and a range tombstone from
1504
// level j with start_key() < children_[i].iter.key() < end_key().
1505
// - If range_tombstone_iters_[j]->Valid(), by Invariants (rti) and (phi),
1506
// pinned_heap_item_[j] is in minHeap_, and pinned_heap_item_[j].tombstone_pik
1507
// is either start or end key of this range tombstone. If
1508
// pinned_heap_item_[j].tombstone_pik < children_[i].iter.key(), it would be at
1509
// top of minHeap_ which would contradict Invariant (1). So
1510
// pinned_heap_item_[j].tombstone_pik > children_[i].iter.key().
1511
// By Invariant (3), range_tombstone_iters_[j].prev.end_key() <
1512
// children_[i].iter.key(). We assume that in each level, range tombstones
1513
// cover non-overlapping ranges. So range_tombstone_iters_[j] is at
1514
// the range tombstone with start_key() < children_[i].iter.key() < end_key()
1515
// and has its end_key() in minHeap_. By Invariants (phi) and (active_),
1516
// j is in active_. From while loop condition, SkipNextDeleted() must have
1517
// returned false for this method to return.
1518
//   - If j < i, then SeekImpl(range_tombstone_iters_[j']->end_key(), i)
1519
// was called for some j' < i and j' in active_. Note that since j' is in
1520
// active_, pinned_heap_item_[j'] is in minHeap_ and has tombstone_pik =
1521
// range_tombstone_iters_[j']->end_key(). So
1522
// range_tombstone_iters_[j']->end_key() must be larger than
1523
// children_[i].iter.key() to not be at top of minHeap_. This means after
1524
// SeekImpl(), children_[i] would be at a key > children_[i].iter.key()
1525
// -- contradiction.
1526
//   - If j == i, children_[i]->Next() would have been called and children_[i]
1527
// would be at a key > children_[i].iter.key() -- contradiction.
1528
// - If !range_tombstone_iters_[j]->Valid(). Then range_tombstone_iters_[j]
1529
// points to an SST file with all range tombstones from that file exhausted.
1530
// The file must come before the file containing the first
1531
// range tombstone with start_key() < children_[i].iter.key() < end_key().
1532
// Assume files from same level have non-overlapping ranges, the current file's
1533
// meta.largest is less than children_[i].iter.key(). So the file boundary key,
1534
// which has value meta.largest must have been popped from minHeap_ before
1535
// children_[i].iter.key(). So range_tombstone_iters_[j] would not point to
1536
// this SST file -- contradiction.
1537
// So it is impossible for children_[i].iter.key() to be covered by a range
1538
// tombstone.
1539
//
1540
// Post-condition (*) holds when the function returns:
1541
// From loop invariant (*) that k <= children_[i].iter.key() <=
1542
// LevelNextVisible(i, k) and Invariant (2) above, when the function returns,
1543
// minHeap_.top()->key() is the smallest LevelNextVisible(i, k) among all levels
1544
// i. This is equal to NextVisible(k).
1545
//
1546
// Invariant (3) holds after each iteration:
1547
// PopDeleteRangeStart() does not change range tombstone position.
1548
// In SkipNextDeleted():
1549
//   - If DELETE_RANGE_END is popped from minHeap_, it means the range
1550
//   tombstone's end key is < all other point keys, so it is safe to advance to
1551
//   next range tombstone.
1552
//   - If file boundary is popped (current->iter.IsDeleteRangeSentinelKey()),
1553
//   we assume that file's last range tombstone's
1554
//   end_key <= file boundary key < all other point keys. So it is safe to
1555
//   move to the first range tombstone in the next SST file.
1556
//   - If children_[i]->Next() is called, then it is fine as it is advancing a
1557
//   point iterator.
1558
//   - If SeekImpl(target, l) is called, then (3) follows from SeekImpl()'s
1559
//   post-condition if its pre-condition holds. First pre-condition follows
1560
//   from loop invariant where Invariant (3) holds for all levels i.
1561
//   Now we should second pre-condition holds. Since Invariant (3) holds for
1562
//   all i, we have for all j <= l, range_tombstone_iters_[j].prev.end_key()
1563
//   < children_[l].iter.key(). `target` is the value of
1564
//   range_tombstone_iters_[j'].end_key() for some j' < l and j' in active_.
1565
//   By Invariant (active_) and (rti), pinned_heap_item_[j'] is in minHeap_ and
1566
//   pinned_heap_item_[j'].tombstone_pik = range_tombstone_iters_[j'].end_key().
1567
//   This end_key must be larger than children_[l].key() since it was not at top
1568
//   of minHeap_. So for all levels j <= l,
1569
//   range_tombstone_iters_[j].prev.end_key() < children_[l].iter.key() < target
1570
//
1571
// Invariant (4) holds after each iteration:
1572
// A level i is inserted into active_ during calls to PopDeleteRangeStart().
1573
// In that case, range_tombstone_iters_[i].start_key() < all point keys
1574
// by heap property and the assumption that point keys and range tombstone keys
1575
// are distinct.
1576
// If SeekImpl(target, l) is called, then there is a range_tombstone_iters_[j]
1577
// where target = range_tombstone_iters_[j]->end_key() and children_[l]->key()
1578
// < target. By loop invariants, (3) and (4) holds for levels.
1579
// Since target > children_[l]->key(), it also holds that for j < l,
1580
// range_tombstone_iters_[j].prev.end_key() < target and that if j in active_,
1581
// range_tombstone_iters_[i]->start_key() < target. So all pre-conditions of
1582
// SeekImpl(target, l) holds, and (4) follow from its post-condition.
1583
// All other places either in this function either advance point iterators
1584
// or remove some level from active_, so (4) still holds.
1585
//
1586
// Look Invariant (*): for all level i, k <= children_[i] <= LevelNextVisible(i,
1587
// k).
1588
// k <= children_[i] follows from loop `progress` condition.
1589
// Consider when children_[i] is changed for any i. It is through
1590
// children_[i].iter.Next() or SeekImpl() in SkipNextDeleted().
1591
// If children_[i].iter.Next() is called, there is a range tombstone from level
1592
// i where tombstone seqno > children_[i].iter.key()'s seqno and i in active_.
1593
// By Invariant (4), tombstone's start_key < children_[i].iter.key(). By
1594
// invariants (active_), (phi), and (rti), tombstone's end_key is in minHeap_
1595
// and that children_[i].iter.key() < end_key. So children_[i].iter.key() is
1596
// not visible, and it is safe to call Next().
1597
// If SeekImpl(target, l) is called, by its contract, when SeekImpl() returns,
1598
// target <= children_[i]->key() <= LevelNextVisible(i, target) for i >= l,
1599
// and children_[<l] is not touched. We know `target` is
1600
// range_tombstone_iters_[j]->end_key() for some j < i and j is in active_.
1601
// By Invariant (4), range_tombstone_iters_[j]->start_key() <
1602
// children_[i].iter.key() for all i >= l. So for each level i >= l, the range
1603
// [children_[i].iter.key(), target) is not visible. So after SeekImpl(),
1604
// children_[i].iter.key() <= LevelNextVisible(i, target) <=
1605
// LevelNextVisible(i, k).
1606
//
1607
// `Progress` holds for each iteration:
1608
// Very sloppy intuition:
1609
// - in PopDeleteRangeStart(): the value of a pinned_heap_item_.tombstone_pik_
1610
// is updated from the start key to the end key of the same range tombstone.
1611
// We assume that start key <= end key for the same range tombstone.
1612
// - in SkipNextDeleted()
1613
//   - If the top of heap is DELETE_RANGE_END, the range tombstone is advanced
1614
//     and the relevant pinned_heap_item_.tombstone_pik is increased or popped
1615
//     from minHeap_.
1616
//   - If the top of heap is a file boundary key, then both point iter and
1617
//     range tombstone iter are advanced to the next file.
1618
//   - If the top of heap is ITERATOR and current->iter.Next() is called, it
1619
//     moves to a larger point key.
1620
//   - If the top of heap is ITERATOR and SeekImpl(k, l) is called, then all
1621
//     iterators from levels >= l are advanced to some key >= k by its contract.
1622
//     And top of minHeap_ before SeekImpl(k, l) was less than k.
1623
// There are special cases where different heap items have the same key,
1624
// e.g. when two range tombstone end keys share the same value). In
1625
// these cases, iterators are being advanced, so the minimum key should increase
1626
// in a finite number of steps.
1627
58.0k
inline void MergingIterator::FindNextVisibleKey() {
1628
58.0k
  PopDeleteRangeStart();
1629
  // PopDeleteRangeStart() implies heap top is not DELETE_RANGE_START
1630
  // active_ being empty implies no DELETE_RANGE_END in heap.
1631
  // So minHeap_->top() must be of type ITERATOR.
1632
58.0k
  while (
1633
154k
      !minHeap_.empty() &&
1634
148k
      (!active_.empty() || minHeap_.top()->iter.IsDeleteRangeSentinelKey()) &&
1635
110k
      SkipNextDeleted()) {
1636
96.9k
    PopDeleteRangeStart();
1637
96.9k
  }
1638
  // Checks Invariant (1)
1639
58.0k
  assert(minHeap_.empty() || minHeap_.top()->type == HeapItem::Type::ITERATOR);
1640
58.0k
}
1641
1642
14.0k
inline void MergingIterator::FindPrevVisibleKey() {
1643
14.0k
  PopDeleteRangeEnd();
1644
  // PopDeleteRangeEnd() implies heap top is not DELETE_RANGE_END
1645
  // active_ being empty implies no DELETE_RANGE_START in heap.
1646
  // So maxHeap_->top() must be of type ITERATOR.
1647
14.0k
  while (
1648
17.5k
      !maxHeap_->empty() &&
1649
14.5k
      (!active_.empty() || maxHeap_->top()->iter.IsDeleteRangeSentinelKey()) &&
1650
3.51k
      SkipPrevDeleted()) {
1651
3.51k
    PopDeleteRangeEnd();
1652
3.51k
  }
1653
14.0k
}
1654
1655
InternalIterator* NewMergingIterator(const InternalKeyComparator* cmp,
1656
                                     InternalIterator** list, int n,
1657
2.33k
                                     Arena* arena, bool prefix_seek_mode) {
1658
2.33k
  assert(n >= 0);
1659
2.33k
  if (n == 0) {
1660
0
    return NewEmptyInternalIterator<Slice>(arena);
1661
2.33k
  } else if (n == 1) {
1662
2.33k
    return list[0];
1663
2.33k
  } else {
1664
0
    if (arena == nullptr) {
1665
0
      return new MergingIterator(cmp, list, n, false, prefix_seek_mode);
1666
0
    } else {
1667
0
      auto mem = arena->AllocateAligned(sizeof(MergingIterator));
1668
0
      return new (mem) MergingIterator(cmp, list, n, true, prefix_seek_mode);
1669
0
    }
1670
0
  }
1671
2.33k
}
1672
1673
MergeIteratorBuilder::MergeIteratorBuilder(
1674
    const InternalKeyComparator* comparator, Arena* a, bool prefix_seek_mode,
1675
    const Slice* iterate_upper_bound)
1676
16.1k
    : first_iter(nullptr), use_merging_iter(false), arena(a) {
1677
16.1k
  auto mem = arena->AllocateAligned(sizeof(MergingIterator));
1678
16.1k
  merge_iter = new (mem) MergingIterator(comparator, nullptr, 0, true,
1679
16.1k
                                         prefix_seek_mode, iterate_upper_bound);
1680
16.1k
}
1681
1682
16.1k
MergeIteratorBuilder::~MergeIteratorBuilder() {
1683
16.1k
  if (first_iter != nullptr) {
1684
0
    first_iter->~InternalIterator();
1685
0
  }
1686
16.1k
  if (merge_iter != nullptr) {
1687
6.41k
    merge_iter->~MergingIterator();
1688
6.41k
  }
1689
16.1k
}
1690
1691
4.72k
void MergeIteratorBuilder::AddIterator(InternalIterator* iter) {
1692
4.72k
  if (!use_merging_iter && first_iter != nullptr) {
1693
0
    merge_iter->AddIterator(first_iter);
1694
0
    use_merging_iter = true;
1695
0
    first_iter = nullptr;
1696
0
  }
1697
4.72k
  if (use_merging_iter) {
1698
0
    merge_iter->AddIterator(iter);
1699
4.72k
  } else {
1700
4.72k
    first_iter = iter;
1701
4.72k
  }
1702
4.72k
}
1703
1704
void MergeIteratorBuilder::AddPointAndTombstoneIterator(
1705
    InternalIterator* point_iter,
1706
    std::unique_ptr<TruncatedRangeDelIterator>&& tombstone_iter,
1707
28.1k
    std::unique_ptr<TruncatedRangeDelIterator>** tombstone_iter_ptr) {
1708
  // tombstone_iter_ptr != nullptr means point_iter is a LevelIterator.
1709
28.1k
  bool add_range_tombstone = tombstone_iter ||
1710
25.3k
                             !merge_iter->range_tombstone_iters_.empty() ||
1711
25.3k
                             tombstone_iter_ptr;
1712
28.1k
  if (!use_merging_iter && (add_range_tombstone || first_iter)) {
1713
9.70k
    use_merging_iter = true;
1714
9.70k
    if (first_iter) {
1715
9.70k
      merge_iter->AddIterator(first_iter);
1716
9.70k
      first_iter = nullptr;
1717
9.70k
    }
1718
9.70k
  }
1719
28.1k
  if (use_merging_iter) {
1720
16.7k
    merge_iter->AddIterator(point_iter);
1721
16.7k
    if (add_range_tombstone) {
1722
      // If there was a gap, fill in nullptr as empty range tombstone iterators.
1723
17.7k
      while (merge_iter->range_tombstone_iters_.size() <
1724
17.7k
             merge_iter->children_.size() - 1) {
1725
11.4k
        merge_iter->AddRangeTombstoneIterator(nullptr);
1726
11.4k
      }
1727
6.34k
      merge_iter->AddRangeTombstoneIterator(std::move(tombstone_iter));
1728
6.34k
    }
1729
1730
16.7k
    if (tombstone_iter_ptr) {
1731
      // This is needed instead of setting to &range_tombstone_iters_[i]
1732
      // directly here since the memory address of range_tombstone_iters_[i]
1733
      // might change during vector resizing.
1734
3.47k
      range_del_iter_ptrs_.emplace_back(
1735
3.47k
          merge_iter->range_tombstone_iters_.size() - 1, tombstone_iter_ptr);
1736
3.47k
    }
1737
16.7k
  } else {
1738
11.3k
    first_iter = point_iter;
1739
11.3k
  }
1740
28.1k
}
1741
1742
16.1k
InternalIterator* MergeIteratorBuilder::Finish(ArenaWrappedDBIter* db_iter) {
1743
16.1k
  InternalIterator* ret = nullptr;
1744
16.1k
  TEST_SYNC_POINT_CALLBACK("MergeIteratorBuilder::Finish:UseMergingIterator",
1745
16.1k
                           &use_merging_iter);
1746
16.1k
  if (!use_merging_iter) {
1747
6.41k
    ret = first_iter;
1748
6.41k
    first_iter = nullptr;
1749
9.70k
  } else {
1750
9.70k
    for (auto& p : range_del_iter_ptrs_) {
1751
3.47k
      *(p.second) = &(merge_iter->range_tombstone_iters_[p.first]);
1752
3.47k
    }
1753
9.70k
    if (db_iter && !merge_iter->range_tombstone_iters_.empty()) {
1754
      // memtable is always the first level, unless it has been pruned
1755
6.34k
      if (memtable_pruned_) {
1756
0
        db_iter->SetMemtableRangetombstoneIter(nullptr);
1757
6.34k
      } else {
1758
6.34k
        db_iter->SetMemtableRangetombstoneIter(
1759
6.34k
            &merge_iter->range_tombstone_iters_.front());
1760
6.34k
      }
1761
6.34k
    }
1762
9.70k
    merge_iter->Finish();
1763
9.70k
    ret = merge_iter;
1764
9.70k
    merge_iter = nullptr;
1765
9.70k
  }
1766
16.1k
  return ret;
1767
16.1k
}
1768
1769
}  // namespace ROCKSDB_NAMESPACE