This patch moves to_partition_range, from the query namespace to the dht namespace, where it is a more natural fit. Signed-off-by: Duarte Nunes <duarte@scylladb.com> Message-Id: <1468498060-19251-1-git-send-email-duarte@scylladb.com>
226 lines
7.5 KiB
C++
226 lines
7.5 KiB
C++
/*
|
|
* Copyright (C) 2015 ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* 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/>.
|
|
*/
|
|
|
|
#include <limits>
|
|
#include "query-request.hh"
|
|
#include "query-result.hh"
|
|
#include "query-result-writer.hh"
|
|
#include "query-result-set.hh"
|
|
#include "to_string.hh"
|
|
#include "bytes.hh"
|
|
#include "mutation_partition_serializer.hh"
|
|
#include "query-result-reader.hh"
|
|
#include "query_result_merger.hh"
|
|
|
|
namespace query {
|
|
|
|
const partition_range full_partition_range = partition_range::make_open_ended_both_sides();
|
|
|
|
const query::partition_slice full_slice = query::partition_slice({ query::clustering_range::make_open_ended_both_sides() }, { }, { }, { });
|
|
|
|
std::ostream& operator<<(std::ostream& out, const specific_ranges& s);
|
|
|
|
std::ostream& operator<<(std::ostream& out, const partition_slice& ps) {
|
|
out << "{"
|
|
<< "regular_cols=[" << join(", ", ps.regular_columns) << "]"
|
|
<< ", static_cols=[" << join(", ", ps.static_columns) << "]"
|
|
<< ", rows=[" << join(", ", ps._row_ranges) << "]"
|
|
;
|
|
if (ps._specific_ranges) {
|
|
out << ", specific=[" << *ps._specific_ranges << "]";
|
|
}
|
|
out << ", options=" << sprint("%x", ps.options.mask()); // FIXME: pretty print options
|
|
out << ", cql_format=" << ps.cql_format();
|
|
out << ", partition_row_limit=" << ps._partition_row_limit;
|
|
return out << "}";
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& out, const read_command& r) {
|
|
return out << "read_command{"
|
|
<< "cf_id=" << r.cf_id
|
|
<< ", version=" << r.schema_version
|
|
<< ", slice=" << r.slice << ""
|
|
<< ", limit=" << r.row_limit
|
|
<< ", timestamp=" << r.timestamp.time_since_epoch().count() << "}"
|
|
<< ", partition_limit=" << r.partition_limit << "}";
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& out, const specific_ranges& s) {
|
|
return out << "{" << s._pk << " : " << join(", ", s._ranges) << "}";
|
|
}
|
|
|
|
partition_slice::partition_slice(clustering_row_ranges row_ranges,
|
|
std::vector<column_id> static_columns,
|
|
std::vector<column_id> regular_columns,
|
|
option_set options,
|
|
std::unique_ptr<specific_ranges> specific_ranges,
|
|
cql_serialization_format cql_format,
|
|
uint32_t partition_row_limit)
|
|
: _row_ranges(std::move(row_ranges))
|
|
, static_columns(std::move(static_columns))
|
|
, regular_columns(std::move(regular_columns))
|
|
, options(options)
|
|
, _specific_ranges(std::move(specific_ranges))
|
|
, _cql_format(std::move(cql_format))
|
|
, _partition_row_limit(partition_row_limit)
|
|
{}
|
|
|
|
partition_slice::partition_slice(partition_slice&&) = default;
|
|
|
|
// Only needed because selection_statement::execute does copies of its read_command
|
|
// in the map-reduce op.
|
|
partition_slice::partition_slice(const partition_slice& s)
|
|
: _row_ranges(s._row_ranges)
|
|
, static_columns(s.static_columns)
|
|
, regular_columns(s.regular_columns)
|
|
, options(s.options)
|
|
, _specific_ranges(s._specific_ranges ? std::make_unique<specific_ranges>(*s._specific_ranges) : nullptr)
|
|
, _cql_format(s._cql_format)
|
|
, _partition_row_limit(s._partition_row_limit)
|
|
{}
|
|
|
|
partition_slice::~partition_slice()
|
|
{}
|
|
|
|
const clustering_row_ranges& partition_slice::row_ranges(const schema& s, const partition_key& k) const {
|
|
auto* r = _specific_ranges ? _specific_ranges->range_for(s, k) : nullptr;
|
|
return r ? *r : _row_ranges;
|
|
}
|
|
|
|
void partition_slice::set_range(const schema& s, const partition_key& k, clustering_row_ranges range) {
|
|
if (!_specific_ranges) {
|
|
_specific_ranges = std::make_unique<specific_ranges>(k, std::move(range));
|
|
} else {
|
|
_specific_ranges->add(s, k, std::move(range));
|
|
}
|
|
}
|
|
|
|
void partition_slice::clear_range(const schema& s, const partition_key& k) {
|
|
if (_specific_ranges && _specific_ranges->contains(s, k)) {
|
|
// just in case someone changes the impl above,
|
|
// we should do actual remove if specific_ranges suddenly
|
|
// becomes an actual map
|
|
assert(_specific_ranges->size() == 1);
|
|
_specific_ranges = nullptr;
|
|
}
|
|
}
|
|
|
|
sstring
|
|
result::pretty_print(schema_ptr s, const query::partition_slice& slice) const {
|
|
std::ostringstream out;
|
|
out << "{ result: " << result_set::from_raw_result(s, slice, *this);
|
|
out << " digest: ";
|
|
if (_digest) {
|
|
out << std::hex << std::setw(2);
|
|
for (auto&& c : _digest->get()) {
|
|
out << unsigned(c) << " ";
|
|
}
|
|
} else {
|
|
out << "{}";
|
|
}
|
|
out << " }";
|
|
return out.str();
|
|
}
|
|
|
|
query::result::printer
|
|
result::pretty_printer(schema_ptr s, const query::partition_slice& slice) const {
|
|
return query::result::printer{s, slice, *this};
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, const query::result::printer& p) {
|
|
os << p.res.pretty_print(p.s, p.slice);
|
|
return os;
|
|
}
|
|
|
|
uint32_t result::calculate_row_count(const query::partition_slice& slice) {
|
|
struct {
|
|
uint32_t total_count = 0;
|
|
uint32_t current_partition_count = 0;
|
|
void accept_new_partition(const partition_key& key, uint32_t row_count) {
|
|
accept_new_partition(row_count);
|
|
}
|
|
void accept_new_partition(uint32_t row_count) {
|
|
total_count += row_count;
|
|
current_partition_count = row_count;
|
|
}
|
|
void accept_new_row(const clustering_key& key, const result_row_view& static_row, const result_row_view& row) {}
|
|
void accept_new_row(const result_row_view& static_row, const result_row_view& row) {}
|
|
void accept_partition_end(const query::result_row_view& static_row) {
|
|
if (current_partition_count == 0) {
|
|
total_count++;
|
|
}
|
|
}
|
|
} counter;
|
|
|
|
bytes_view v;
|
|
|
|
if (buf().is_linearized()) {
|
|
v = buf().view();
|
|
} else {
|
|
// FIXME: make result_view::consume() work on fragments to avoid linearization.
|
|
bytes_ostream w(buf());
|
|
v = w.linearize();
|
|
}
|
|
|
|
query::result_view view(v);
|
|
view.consume(slice, counter);
|
|
return counter.total_count;
|
|
}
|
|
|
|
result::result()
|
|
: result([] {
|
|
bytes_ostream out;
|
|
ser::writer_of_query_result(out).skip_partitions().end_query_result();
|
|
return out;
|
|
}())
|
|
{ }
|
|
|
|
foreign_ptr<lw_shared_ptr<query::result>> result_merger::get() {
|
|
if (_partial.size() == 1) {
|
|
return std::move(_partial[0]);
|
|
}
|
|
|
|
bytes_ostream w;
|
|
auto partitions = ser::writer_of_query_result(w).start_partitions();
|
|
std::experimental::optional<uint32_t> row_count = 0;
|
|
|
|
for (auto&& r : _partial) {
|
|
if (row_count) {
|
|
if (r->row_count()) {
|
|
row_count = row_count.value() + r->row_count().value();
|
|
} else {
|
|
row_count = std::experimental::nullopt;
|
|
}
|
|
}
|
|
result_view::do_with(*r, [&] (result_view rv) {
|
|
for (auto&& pv : rv._v.partitions()) {
|
|
partitions.add(pv);
|
|
}
|
|
});
|
|
}
|
|
|
|
std::move(partitions).end_partitions().end_query_result();
|
|
|
|
return make_foreign(make_lw_shared<query::result>(std::move(w), row_count));
|
|
}
|
|
|
|
}
|