Delete unused nway_merger.hh
Signed-off-by: Duarte Nunes <duarte@scylladb.com> Message-Id: <1514463536-7732-1-git-send-email-duarte@scylladb.com>
This commit is contained in:
@@ -31,7 +31,6 @@
|
||||
#include "db/config.hh"
|
||||
#include "to_string.hh"
|
||||
#include "query-result-writer.hh"
|
||||
#include "nway_merger.hh"
|
||||
#include "cql3/column_identifier.hh"
|
||||
#include "core/seastar.hh"
|
||||
#include <seastar/core/sleep.hh>
|
||||
|
||||
267
nway_merger.hh
267
nway_merger.hh
@@ -1,267 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 ScyllaDB
|
||||
*
|
||||
* This work is open source software, licensed under the terms of the
|
||||
* BSD license as described in the LICENSE file in the top-level directory.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Scylla.
|
||||
*
|
||||
* Scylla is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Scylla is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file nway_merger.hh
|
||||
* Implementation of a osv::nway_merger class.
|
||||
* nway_merger::merge() function merges N sorted containers with the complexity
|
||||
* of O(M*log(N)), where M is a total number of elements in all merged
|
||||
* containers.
|
||||
*/
|
||||
|
||||
#ifndef _NWAY_MERGE_HH
|
||||
#define _NWAY_MERGE_HH
|
||||
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
|
||||
/** @class Ptr
|
||||
* Compares two containers by the elemnt at the head
|
||||
*/
|
||||
template <class Ptr>
|
||||
class std_ptr_front_comparator {
|
||||
public:
|
||||
/**
|
||||
* We want out heap to sort the elements in an increasing order.
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
bool operator()(const Ptr a, const Ptr b)
|
||||
{
|
||||
return a->front() > b->front();
|
||||
}
|
||||
};
|
||||
|
||||
/** @class nway_merger "nway_merger.hh"
|
||||
* Merge N containers S sorted in an increasing order into an iterator as a
|
||||
* sorted sequence in an increasing order. The containers collection is passed
|
||||
* to the method merge() in a container C.
|
||||
*
|
||||
* @note
|
||||
* In order to invert the ordering of the elements in the output stream one may
|
||||
* invert the semantics in the operator>(const S::value_type) to return "<="
|
||||
* result and sort the input streams in a descreasing order. The resulting
|
||||
* stream will have a decreasing order then.
|
||||
*
|
||||
* #### Algorithm:
|
||||
* merge() method implements the "ideal merge" algorithm as described at
|
||||
* http://xlinux.nist.gov/dads//HTML/idealmerge.html
|
||||
*
|
||||
* @note
|
||||
* stl::priority_queue(heap) as we defined it will hold the "smallest" element
|
||||
* at the "top".
|
||||
*
|
||||
* 1. Input containers should be sorted in an increasing order.
|
||||
* 2. Push all the containers into the heap sorting by their front() elements.
|
||||
* 3. Remove the container from the top of the heap. It'll have the smallest
|
||||
* element among all containers.
|
||||
* 4. Remove the front() element from this container and push it into the output
|
||||
* iterator.
|
||||
* 5. If this container still has elements, push it back to the heap.
|
||||
* 6. Repeat steps (3)-(5) until there are containers in the heap.
|
||||
*
|
||||
* #### Complexity:
|
||||
* O(M*log(N)), where M is a total number of elements in all merged containers
|
||||
* (provided the complexity of a comparison between two S values is constant).
|
||||
*
|
||||
* @note S::value_type must implement operator>().
|
||||
*/
|
||||
template <class C,
|
||||
class Comp = std_ptr_front_comparator<typename C::value_type> >
|
||||
class nway_merger {
|
||||
public:
|
||||
nway_merger(Comp comp = Comp()) : _comp(comp), _heads_heap(comp) {}
|
||||
/**
|
||||
* Merges the containers and outputs the resulting stream into the output
|
||||
* iterator res (see class description for more details).
|
||||
*
|
||||
* The input (sorted) container should implement:
|
||||
* - front() - return the element from the HEAD element.
|
||||
* - empty() - returns true if there are no more elements left
|
||||
* - begin() - return the iterator pointing to the HEAD element:
|
||||
* - pop_front() - deleting the element returned by front().
|
||||
*
|
||||
* Output iterator should implement:
|
||||
* - Required operators to implement the *it = xx in order to consume the
|
||||
* xx value.
|
||||
* - operator++() - to move to the next output position.
|
||||
*
|
||||
* @param sorted_lists collection of the pointers to the sorted collections
|
||||
* to merge
|
||||
* @param res Output stream for the results of an nway_merge
|
||||
*/
|
||||
template <class OutputIt>
|
||||
void merge(const C& sorted_lists, OutputIt res)
|
||||
{
|
||||
create_heap(sorted_lists, _comp);
|
||||
|
||||
while (!_heads_heap.empty()) {
|
||||
SPtr t = _heads_heap.top();
|
||||
_heads_heap.pop();
|
||||
auto t_it = t->begin();
|
||||
|
||||
/* Get the element from the "HEAD" of the container */
|
||||
*res = *t_it;
|
||||
++res;
|
||||
|
||||
/* Erase the "HEAD" */
|
||||
t->pop_front();
|
||||
|
||||
if (!t->empty()) {
|
||||
_heads_heap.push(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops the "smallest" element from the merged stream and pushes it into the
|
||||
* output stream.
|
||||
*
|
||||
* The input ordering requirements is the same as described in
|
||||
* merge() above.
|
||||
* This functions performs a single step of the nway_merge algorithm:
|
||||
* 1) Sorts the front elements.
|
||||
* 2) Pushes the least among them into the output iterator.
|
||||
*
|
||||
* This function is convenient when you want to merge the input streams that
|
||||
* are sometimes empty in a step-by-step manner.
|
||||
*
|
||||
* @param sorted_lists
|
||||
* @param res
|
||||
*
|
||||
* @return true if the element has been popped and false if there was nothing
|
||||
* to pop (all input sequences were empty).
|
||||
*/
|
||||
template <class OutputIt>
|
||||
bool pop(OutputIt res)
|
||||
{
|
||||
refill_heap();
|
||||
|
||||
if (!_heads_heap.empty()) {
|
||||
SPtr t = _heads_heap.top();
|
||||
_heads_heap.pop();
|
||||
auto t_it = t->begin();
|
||||
|
||||
/* Get the element from the "HEAD" of the container */
|
||||
*res = *t_it;
|
||||
++res;
|
||||
|
||||
/* Erase the "HEAD" */
|
||||
t->pop_front();
|
||||
|
||||
if (!t->empty()) {
|
||||
_heads_heap.push(t);
|
||||
} else {
|
||||
_empty_lists.emplace_back(t);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void clear() { _heads_heap = heap_type(_comp); }
|
||||
|
||||
/**
|
||||
* Create a new heap from the sorted sequences.
|
||||
* @param sorted_lists
|
||||
*/
|
||||
void create_heap(const C& sorted_lists) {
|
||||
|
||||
clear();
|
||||
|
||||
/* Create a heap */
|
||||
for (SPtr c : sorted_lists) {
|
||||
if (!c->empty()) {
|
||||
_heads_heap.emplace(c);
|
||||
} else {
|
||||
_empty_lists.emplace_back(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push back all sequences from the _empty_list back to the heap.
|
||||
*
|
||||
* TODO:
|
||||
* Come up with something better that walking on the whole list and check
|
||||
* each list. One option is to use bitfield array and then use
|
||||
* count_leading_zeros() based function to efficiently get the next set bit
|
||||
* which may represent the non-empty list.
|
||||
*
|
||||
* This inefficiency may count in case of VMs with a large number of vCPUs
|
||||
* when most of the queues would be empty.
|
||||
*/
|
||||
void refill_heap() {
|
||||
/* TODO: Improve this by iterating only on those that are not empty */
|
||||
auto it = _empty_lists.begin();
|
||||
while (it != _empty_lists.end()) {
|
||||
if (!(*it)->empty()) {
|
||||
_heads_heap.emplace(*it);
|
||||
|
||||
auto tmp_it = it;
|
||||
++it;
|
||||
|
||||
_empty_lists.erase(tmp_it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class EmptyChecker>
|
||||
bool empty(EmptyChecker checker) const {
|
||||
return checker();
|
||||
}
|
||||
|
||||
// A stupid implementation of an empty_checker()
|
||||
bool silly_empty_checker() const {
|
||||
if (!_heads_heap.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (SPtr c : _empty_lists) {
|
||||
if (!c->empty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef typename C::value_type SPtr;
|
||||
typedef std::priority_queue<SPtr, std::vector<SPtr>, Comp> heap_type;
|
||||
|
||||
Comp _comp;
|
||||
heap_type _heads_heap;
|
||||
C* _sorted_lists;
|
||||
std::list<SPtr> _empty_lists;
|
||||
};
|
||||
|
||||
#endif /* _NWAY_MERGE_HH */
|
||||
Reference in New Issue
Block a user