Status status_;
IterKey saved_key_;
+ // Reusable internal key data structure. This is only used inside one function
+ // and should not be used across functions. Reusing this object can reduce
+ // overhead of calling construction of the function if creating it each time.
+ ParsedInternalKey ikey_;
std::string saved_value_;
Slice pinned_value_;
Direction direction_;
uint64_t num_skipped = 0;
do {
- ParsedInternalKey ikey;
-
- if (!ParseKey(&ikey)) {
+ if (!ParseKey(&ikey_)) {
// Skip corrupted keys.
iter_->Next();
continue;
}
if (iterate_upper_bound_ != nullptr &&
- user_comparator_->Compare(ikey.user_key, *iterate_upper_bound_) >= 0) {
+ user_comparator_->Compare(ikey_.user_key, *iterate_upper_bound_) >= 0) {
break;
}
if (prefix_extractor_ && prefix_check &&
- prefix_extractor_->Transform(ikey.user_key)
- .compare(prefix_start_key_) != 0) {
+ prefix_extractor_->Transform(ikey_.user_key)
+ .compare(prefix_start_key_) != 0) {
break;
}
return;
}
- if (ikey.sequence <= sequence_) {
- if (skipping &&
- user_comparator_->Compare(ikey.user_key, saved_key_.GetUserKey()) <=
- 0) {
+ if (ikey_.sequence <= sequence_) {
+ if (skipping && user_comparator_->Compare(ikey_.user_key,
+ saved_key_.GetUserKey()) <= 0) {
num_skipped++; // skip this entry
PERF_COUNTER_ADD(internal_key_skipped_count, 1);
} else {
num_skipped = 0;
- switch (ikey.type) {
+ switch (ikey_.type) {
case kTypeDeletion:
case kTypeSingleDeletion:
// Arrange to skip all upcoming entries for this key since
// they are hidden by this deletion.
saved_key_.SetUserKey(
- ikey.user_key,
- !iter_->IsKeyPinned() || !pin_thru_lifetime_ /* copy */);
+ ikey_.user_key,
+ !pin_thru_lifetime_ || !iter_->IsKeyPinned() /* copy */);
skipping = true;
PERF_COUNTER_ADD(internal_delete_skipped_count, 1);
break;
case kTypeValue:
saved_key_.SetUserKey(
- ikey.user_key,
- !iter_->IsKeyPinned() || !pin_thru_lifetime_ /* copy */);
+ ikey_.user_key,
+ !pin_thru_lifetime_ || !iter_->IsKeyPinned() /* copy */);
if (range_del_agg_.ShouldDelete(
- ikey, RangeDelAggregator::RangePositioningMode::
- kForwardTraversal)) {
+ ikey_, RangeDelAggregator::RangePositioningMode::
+ kForwardTraversal)) {
// Arrange to skip all upcoming entries for this key since
// they are hidden by this deletion.
skipping = true;
break;
case kTypeMerge:
saved_key_.SetUserKey(
- ikey.user_key,
- !iter_->IsKeyPinned() || !pin_thru_lifetime_ /* copy */);
+ ikey_.user_key,
+ !pin_thru_lifetime_ || !iter_->IsKeyPinned() /* copy */);
if (range_del_agg_.ShouldDelete(
- ikey, RangeDelAggregator::RangePositioningMode::
- kForwardTraversal)) {
+ ikey_, RangeDelAggregator::RangePositioningMode::
+ kForwardTraversal)) {
// Arrange to skip all upcoming entries for this key since
// they are hidden by this deletion.
skipping = true;
// Here saved_key_ may contain some old key, or the default empty key, or
// key assigned by some random other method. We don't care.
- if (user_comparator_->Compare(ikey.user_key, saved_key_.GetUserKey()) <=
+ if (user_comparator_->Compare(ikey_.user_key, saved_key_.GetUserKey()) <=
0) {
num_skipped++;
} else {
saved_key_.SetUserKey(
- ikey.user_key,
+ ikey_.user_key,
!iter_->IsKeyPinned() || !pin_thru_lifetime_ /* copy */);
skipping = false;
num_skipped = 0;
// true for all of the non-current children since current_ is
// the smallest child and key() == current_->key().
if (direction_ != kForward) {
- // Otherwise, advance the non-current children. We advance current_
- // just after the if-block.
- ClearHeaps();
- for (auto& child : children_) {
- if (&child != current_) {
- child.Seek(key());
- if (child.Valid() && comparator_->Equal(key(), child.key())) {
- child.Next();
- }
- }
- if (child.Valid()) {
- minHeap_.push(&child);
- }
- }
- direction_ = kForward;
+ SwitchToForward();
// The loop advanced all non-current children to be > key() so current_
// should still be strictly the smallest key.
assert(current_ == CurrentForward());
std::unique_ptr<MergerMaxIterHeap> maxHeap_;
PinnedIteratorsManager* pinned_iters_mgr_;
+ void SwitchToForward();
+
IteratorWrapper* CurrentForward() const {
assert(direction_ == kForward);
return !minHeap_.empty() ? minHeap_.top() : nullptr;
}
};
+void MergingIterator::SwitchToForward() {
+ // Otherwise, advance the non-current children. We advance current_
+ // just after the if-block.
+ ClearHeaps();
+ for (auto& child : children_) {
+ if (&child != current_) {
+ child.Seek(key());
+ if (child.Valid() && comparator_->Equal(key(), child.key())) {
+ child.Next();
+ }
+ }
+ if (child.Valid()) {
+ minHeap_.push(&child);
+ }
+ }
+ direction_ = kForward;
+}
+
void MergingIterator::ClearHeaps() {
minHeap_.clear();
if (maxHeap_) {