Summary:
This patch reverts "Replace std::priority_queue in MergingIterator
with custom heap" (commit commit b6655a679d
)
as it causes db_stress failure.
Test Plan: ./db_stress --test_batches_snapshots=1 --threads=32 --write_buffer_size=4194304 --destroy_db_initially=0 --reopen=20 --readpercent=45 --prefixpercent=5 --writepercent=35 --delpercent=5 --iterpercent=10 --db=/tmp/rocksdb_crashtest_KdCI5F --max_key=100000000 --mmap_read=0 --block_size=16384 --cache_size=1048576 --open_files=500000 --verify_checksum=1 --sync=0 --progress_reports=0 --disable_wal=0 --disable_data_sync=1 --target_file_size_base=2097152 --target_file_size_multiplier=2 --max_write_buffer_number=3 --max_background_compactions=20 --max_bytes_for_level_base=10485760 --filter_deletes=0 --memtablerep=prefix_hash --prefix_size=7 --ops_per_thread=200 --kill_random_test=97
Reviewers: igor, anthony, lovro, sdong
Reviewed By: sdong
Subscribers: dhruba, leveldb
Differential Revision: https://reviews.facebook.net/D41343
main
parent
c0b23dd5b0
commit
b7a2369fb2
@ -1,140 +0,0 @@ |
|||||||
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
|
||||||
// This source code is licensed under the BSD-style license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
// of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
|
|
||||||
#pragma once |
|
||||||
|
|
||||||
#include <algorithm> |
|
||||||
#include <cstdint> |
|
||||||
#include <functional> |
|
||||||
#include "util/autovector.h" |
|
||||||
|
|
||||||
namespace rocksdb { |
|
||||||
|
|
||||||
// Binary heap implementation optimized for use in multi-way merge sort.
|
|
||||||
// Comparison to std::priority_queue:
|
|
||||||
// - In libstdc++, std::priority_queue::pop() usually performs just over logN
|
|
||||||
// comparisons but never fewer.
|
|
||||||
// - std::priority_queue does not have a replace-top operation, requiring a
|
|
||||||
// pop+push. If the replacement element is the new top, this requires
|
|
||||||
// around 2logN comparisons.
|
|
||||||
// - This heap's pop() uses a "schoolbook" downheap which requires up to ~2logN
|
|
||||||
// comparisons.
|
|
||||||
// - This heap provides a replace_top() operation which requires [1, 2logN]
|
|
||||||
// comparisons. When the replacement element is also the new top, this
|
|
||||||
// takes just 1 or 2 comparisons.
|
|
||||||
//
|
|
||||||
// The last property can yield an order-of-magnitude performance improvement
|
|
||||||
// when merge-sorting real-world non-random data. If the merge operation is
|
|
||||||
// likely to take chunks of elements from the same input stream, only 1
|
|
||||||
// comparison per element is needed. In RocksDB-land, this happens when
|
|
||||||
// compacting a database where keys are not randomly distributed across L0
|
|
||||||
// files but nearby keys are likely to be in the same L0 file.
|
|
||||||
//
|
|
||||||
// The container uses the same counterintuitive ordering as
|
|
||||||
// std::priority_queue: the comparison operator is expected to provide the
|
|
||||||
// less-than relation, but top() will return the maximum.
|
|
||||||
|
|
||||||
template<typename T, typename Compare = std::less<T>> |
|
||||||
class BinaryHeap { |
|
||||||
public: |
|
||||||
BinaryHeap() { } |
|
||||||
explicit BinaryHeap(Compare cmp) : cmp_(std::move(cmp)) { } |
|
||||||
|
|
||||||
void push(const T& value) { |
|
||||||
data_.push_back(value); |
|
||||||
upheap(data_.size() - 1); |
|
||||||
} |
|
||||||
|
|
||||||
void push(T&& value) { |
|
||||||
data_.push_back(std::move(value)); |
|
||||||
upheap(data_.size() - 1); |
|
||||||
} |
|
||||||
|
|
||||||
const T& top() const { |
|
||||||
assert(!empty()); |
|
||||||
return data_.front(); |
|
||||||
} |
|
||||||
|
|
||||||
void replace_top(const T& value) { |
|
||||||
assert(!empty()); |
|
||||||
data_.front() = value; |
|
||||||
downheap(get_root()); |
|
||||||
} |
|
||||||
|
|
||||||
void replace_top(T&& value) { |
|
||||||
assert(!empty()); |
|
||||||
data_.front() = std::move(value); |
|
||||||
downheap(get_root()); |
|
||||||
} |
|
||||||
|
|
||||||
void pop() { |
|
||||||
assert(!empty()); |
|
||||||
data_.front() = std::move(data_.back()); |
|
||||||
data_.pop_back(); |
|
||||||
if (!empty()) { |
|
||||||
downheap(get_root()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void swap(BinaryHeap &other) { |
|
||||||
std::swap(cmp_, other.cmp_); |
|
||||||
data_.swap(other.data_); |
|
||||||
} |
|
||||||
|
|
||||||
void clear() { |
|
||||||
data_.clear(); |
|
||||||
} |
|
||||||
|
|
||||||
bool empty() const { |
|
||||||
return data_.empty(); |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
static inline size_t get_root() { return 0; } |
|
||||||
static inline size_t get_parent(size_t index) { return (index - 1) / 2; } |
|
||||||
static inline size_t get_left(size_t index) { return 2 * index + 1; } |
|
||||||
static inline size_t get_right(size_t index) { return 2 * index + 2; } |
|
||||||
|
|
||||||
void upheap(size_t index) { |
|
||||||
T v = std::move(data_[index]); |
|
||||||
while (index > get_root()) { |
|
||||||
const size_t parent = get_parent(index); |
|
||||||
if (!cmp_(data_[parent], v)) { |
|
||||||
break; |
|
||||||
} |
|
||||||
data_[index] = std::move(data_[parent]); |
|
||||||
index = parent; |
|
||||||
} |
|
||||||
data_[index] = std::move(v); |
|
||||||
} |
|
||||||
|
|
||||||
void downheap(size_t index) { |
|
||||||
T v = std::move(data_[index]); |
|
||||||
while (1) { |
|
||||||
const size_t left_child = get_left(index); |
|
||||||
if (get_left(index) >= data_.size()) { |
|
||||||
break; |
|
||||||
} |
|
||||||
const size_t right_child = left_child + 1; |
|
||||||
assert(right_child == get_right(index)); |
|
||||||
size_t picked_child = left_child; |
|
||||||
if (right_child < data_.size() && |
|
||||||
cmp_(data_[left_child], data_[right_child])) { |
|
||||||
picked_child = right_child; |
|
||||||
} |
|
||||||
if (!cmp_(v, data_[picked_child])) { |
|
||||||
break; |
|
||||||
} |
|
||||||
data_[index] = std::move(data_[picked_child]); |
|
||||||
index = picked_child; |
|
||||||
} |
|
||||||
data_[index] = std::move(v); |
|
||||||
} |
|
||||||
|
|
||||||
Compare cmp_; |
|
||||||
autovector<T> data_; |
|
||||||
}; |
|
||||||
|
|
||||||
} // namespace rocksdb
|
|
Loading…
Reference in new issue