/* * 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 . */ #include #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 static_columns, std::vector regular_columns, option_set options, std::unique_ptr 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(*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(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> 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 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(std::move(w), row_count)); } }