/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 |