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:
Duarte Nunes
2017-12-28 12:18:56 +00:00
committed by Avi Kivity
parent c76356fb39
commit 89b353cd95
2 changed files with 0 additions and 268 deletions

View File

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

View File

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