YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/rocksdb/util/heap.h
Line
Count
Source
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2
//  This source code is licensed under the BSD-style license found in the
3
//  LICENSE file in the root directory of this source tree. An additional grant
4
//  of patent rights can be found in the PATENTS file in the same directory.
5
//
6
// The following only applies to changes made to this file as part of YugaByte development.
7
//
8
// Portions Copyright (c) YugaByte, Inc.
9
//
10
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
11
// in compliance with the License.  You may obtain a copy of the License at
12
//
13
// http://www.apache.org/licenses/LICENSE-2.0
14
//
15
// Unless required by applicable law or agreed to in writing, software distributed under the License
16
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17
// or implied.  See the License for the specific language governing permissions and limitations
18
// under the License.
19
//
20
21
#ifndef YB_ROCKSDB_UTIL_HEAP_H
22
#define YB_ROCKSDB_UTIL_HEAP_H
23
24
#pragma once
25
26
#include <algorithm>
27
28
#include <boost/container/small_vector.hpp>
29
30
namespace rocksdb {
31
32
// Binary heap implementation optimized for use in multi-way merge sort.
33
// Comparison to std::priority_queue:
34
// - In libstdc++, std::priority_queue::pop() usually performs just over logN
35
//   comparisons but never fewer.
36
// - std::priority_queue does not have a replace-top operation, requiring a
37
//   pop+push.  If the replacement element is the new top, this requires
38
//   around 2logN comparisons.
39
// - This heap's pop() uses a "schoolbook" downheap which requires up to ~2logN
40
//   comparisons.
41
// - This heap provides a replace_top() operation which requires [1, 2logN]
42
//   comparisons.  When the replacement element is also the new top, this
43
//   takes just 1 or 2 comparisons.
44
//
45
// The last property can yield an order-of-magnitude performance improvement
46
// when merge-sorting real-world non-random data.  If the merge operation is
47
// likely to take chunks of elements from the same input stream, only 1
48
// comparison per element is needed.  In RocksDB-land, this happens when
49
// compacting a database where keys are not randomly distributed across L0
50
// files but nearby keys are likely to be in the same L0 file.
51
//
52
// The container uses the same counterintuitive ordering as
53
// std::priority_queue: the comparison operator is expected to provide the
54
// less-than relation, but top() will return the maximum.
55
56
template<typename T, typename Compare = std::less<T>>
57
class BinaryHeap {
58
 public:
59
  BinaryHeap() { }
60
15.4M
  explicit BinaryHeap(Compare cmp) : cmp_(std::move(cmp)) { }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MinIteratorComparatorEEC2ES3_
Line
Count
Source
60
15.4M
  explicit BinaryHeap(Compare cmp) : cmp_(std::move(cmp)) { }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MaxIteratorComparatorEEC2ES3_
Line
Count
Source
60
4.34k
  explicit BinaryHeap(Compare cmp) : cmp_(std::move(cmp)) { }
61
62
  void push(const T& value) {
63
    data_.push_back(std::move(value));
64
    std::push_heap(data_.begin(), data_.end(), cmp_);
65
  }
66
67
18.7M
  void push(T&& value) {
68
18.7M
    data_.push_back(std::move(value));
69
18.7M
    std::push_heap(data_.begin(), data_.end(), cmp_);
70
18.7M
  }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MinIteratorComparatorEE4pushEOS2_
Line
Count
Source
67
17.1M
  void push(T&& value) {
68
17.1M
    data_.push_back(std::move(value));
69
17.1M
    std::push_heap(data_.begin(), data_.end(), cmp_);
70
17.1M
  }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MaxIteratorComparatorEE4pushEOS2_
Line
Count
Source
67
1.54M
  void push(T&& value) {
68
1.54M
    data_.push_back(std::move(value));
69
1.54M
    std::push_heap(data_.begin(), data_.end(), cmp_);
70
1.54M
  }
71
72
584M
  const T& top() const {
73
584M
    assert(!empty());
74
584M
    return data_.front();
75
584M
  }
_ZNK7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MinIteratorComparatorEE3topEv
Line
Count
Source
72
579M
  const T& top() const {
73
579M
    assert(!empty());
74
579M
    return data_.front();
75
579M
  }
_ZNK7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MaxIteratorComparatorEE3topEv
Line
Count
Source
72
4.48M
  const T& top() const {
73
4.48M
    assert(!empty());
74
4.48M
    return data_.front();
75
4.48M
  }
76
77
288M
  void replace_top(const T& value) {
78
288M
    assert(!empty());
79
288M
    data_.front() = value;
80
288M
    downheap(get_root());
81
288M
  }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MinIteratorComparatorEE11replace_topERKS2_
Line
Count
Source
77
286M
  void replace_top(const T& value) {
78
286M
    assert(!empty());
79
286M
    data_.front() = value;
80
286M
    downheap(get_root());
81
286M
  }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MaxIteratorComparatorEE11replace_topERKS2_
Line
Count
Source
77
2.00M
  void replace_top(const T& value) {
78
2.00M
    assert(!empty());
79
2.00M
    data_.front() = value;
80
2.00M
    downheap(get_root());
81
2.00M
  }
82
83
  void replace_top(T&& value) {
84
    assert(!empty());
85
    data_.front() = std::move(value);
86
    downheap(get_root());
87
  }
88
89
206k
  void pop() {
90
206k
    assert(!empty());
91
206k
    std::pop_heap(data_.begin(), data_.end(), cmp_);
92
206k
    data_.pop_back();
93
206k
  }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MinIteratorComparatorEE3popEv
Line
Count
Source
89
180k
  void pop() {
90
180k
    assert(!empty());
91
180k
    std::pop_heap(data_.begin(), data_.end(), cmp_);
92
180k
    data_.pop_back();
93
180k
  }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MaxIteratorComparatorEE3popEv
Line
Count
Source
89
25.7k
  void pop() {
90
25.7k
    assert(!empty());
91
25.7k
    std::pop_heap(data_.begin(), data_.end(), cmp_);
92
25.7k
    data_.pop_back();
93
25.7k
  }
94
95
  void swap(BinaryHeap &other) {
96
    std::swap(cmp_, other.cmp_);
97
    data_.swap(other.data_);
98
  }
99
100
8.39M
  void clear() {
101
8.39M
    data_.clear();
102
8.39M
  }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MinIteratorComparatorEE5clearEv
Line
Count
Source
100
7.14M
  void clear() {
101
7.14M
    data_.clear();
102
7.14M
  }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MaxIteratorComparatorEE5clearEv
Line
Count
Source
100
1.25M
  void clear() {
101
1.25M
    data_.clear();
102
1.25M
  }
103
104
1.47G
  bool empty() const {
105
1.47G
    return data_.empty();
106
1.47G
  }
_ZNK7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MinIteratorComparatorEE5emptyEv
Line
Count
Source
104
1.45G
  bool empty() const {
105
1.45G
    return data_.empty();
106
1.45G
  }
_ZNK7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MaxIteratorComparatorEE5emptyEv
Line
Count
Source
104
11.0M
  bool empty() const {
105
11.0M
    return data_.empty();
106
11.0M
  }
107
108
  size_t size() const {
109
    return data_.size();
110
  }
111
112
 private:
113
288M
  static inline size_t get_root() { return 0; }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MinIteratorComparatorEE8get_rootEv
Line
Count
Source
113
286M
  static inline size_t get_root() { return 0; }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MaxIteratorComparatorEE8get_rootEv
Line
Count
Source
113
2.00M
  static inline size_t get_root() { return 0; }
114
327M
  static inline size_t get_left(size_t index) { return 2 * index + 1; }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MinIteratorComparatorEE8get_leftEm
Line
Count
Source
114
318M
  static inline size_t get_left(size_t index) { return 2 * index + 1; }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MaxIteratorComparatorEE8get_leftEm
Line
Count
Source
114
8.98M
  static inline size_t get_left(size_t index) { return 2 * index + 1; }
115
289M
  static inline size_t get_right(size_t index) { return 2 * index + 2; }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MinIteratorComparatorEE9get_rightEm
Line
Count
Source
115
281M
  static inline size_t get_right(size_t index) { return 2 * index + 2; }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MaxIteratorComparatorEE9get_rightEm
Line
Count
Source
115
8.06M
  static inline size_t get_right(size_t index) { return 2 * index + 2; }
116
117
288M
  void downheap(size_t index) {
118
288M
    T* data = data_.data();
119
288M
    T v = std::move(data[index]);
120
288M
    size_t size = data_.size();
121
327M
    for(;;) {
122
327M
      const size_t left_child = get_left(index);
123
327M
      if (left_child >= size) {
124
37.8M
        break;
125
37.8M
      }
126
289M
      const size_t right_child = left_child + 1;
127
289M
      DCHECK_EQ(right_child, get_right(index));
128
289M
      T* picked_child = data + left_child;
129
289M
      if (right_child < size) {
130
236M
        T* right_ptr = data + right_child;
131
236M
        if (cmp_(*picked_child, *right_ptr)) {
132
200M
          picked_child = right_ptr;
133
200M
        }
134
236M
      }
135
289M
      if (!cmp_(v, *picked_child)) {
136
251M
        break;
137
251M
      }
138
38.8M
      data[index] = std::move(*picked_child);
139
38.8M
      index = picked_child - data;
140
38.8M
    }
141
288M
    data[index] = std::move(v);
142
288M
  }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MinIteratorComparatorEE8downheapEm
Line
Count
Source
117
286M
  void downheap(size_t index) {
118
286M
    T* data = data_.data();
119
286M
    T v = std::move(data[index]);
120
286M
    size_t size = data_.size();
121
318M
    for(;;) {
122
318M
      const size_t left_child = get_left(index);
123
318M
      if (left_child >= size) {
124
36.9M
        break;
125
36.9M
      }
126
281M
      const size_t right_child = left_child + 1;
127
281M
      DCHECK_EQ(right_child, get_right(index));
128
281M
      T* picked_child = data + left_child;
129
281M
      if (right_child < size) {
130
228M
        T* right_ptr = data + right_child;
131
228M
        if (cmp_(*picked_child, *right_ptr)) {
132
196M
          picked_child = right_ptr;
133
196M
        }
134
228M
      }
135
281M
      if (!cmp_(v, *picked_child)) {
136
249M
        break;
137
249M
      }
138
31.9M
      data[index] = std::move(*picked_child);
139
31.9M
      index = picked_child - data;
140
31.9M
    }
141
286M
    data[index] = std::move(v);
142
286M
  }
_ZN7rocksdb10BinaryHeapIPNS_15IteratorWrapperENS_21MaxIteratorComparatorEE8downheapEm
Line
Count
Source
117
2.00M
  void downheap(size_t index) {
118
2.00M
    T* data = data_.data();
119
2.00M
    T v = std::move(data[index]);
120
2.00M
    size_t size = data_.size();
121
8.98M
    for(;;) {
122
8.98M
      const size_t left_child = get_left(index);
123
8.98M
      if (left_child >= size) {
124
920k
        break;
125
920k
      }
126
8.06M
      const size_t right_child = left_child + 1;
127
8.06M
      DCHECK_EQ(right_child, get_right(index));
128
8.06M
      T* picked_child = data + left_child;
129
8.06M
      if (right_child < size) {
130
7.66M
        T* right_ptr = data + right_child;
131
7.66M
        if (cmp_(*picked_child, *right_ptr)) {
132
3.81M
          picked_child = right_ptr;
133
3.81M
        }
134
7.66M
      }
135
8.06M
      if (!cmp_(v, *picked_child)) {
136
1.08M
        break;
137
1.08M
      }
138
6.97M
      data[index] = std::move(*picked_child);
139
6.97M
      index = picked_child - data;
140
6.97M
    }
141
2.00M
    data[index] = std::move(v);
142
2.00M
  }
143
144
  Compare cmp_;
145
  boost::container::small_vector<T, 8> data_;
146
};
147
148
}  // namespace rocksdb
149
150
#endif // YB_ROCKSDB_UTIL_HEAP_H