types: remove linearization from abstract_type::compare

To avoid high latencies caused by large contigous allocations
needed by linearizing, work on fragmented buffers instead.

Signed-off-by: Wojciech Mitros <wojciech.mitros@scylladb.com>
This commit is contained in:
Wojciech Mitros
2021-03-25 13:43:07 +01:00
parent daa31be37f
commit f57fa935a2
4 changed files with 44 additions and 38 deletions

View File

@@ -334,7 +334,8 @@ static sstring to_json_string_aux(const set_type_impl& t, bytes_view bv) {
bool first = true;
auto sf = cql_serialization_format::internal();
out << '[';
std::for_each(llpdi::begin(bv, sf), llpdi::end(bv, sf), [&first, &out, &t] (bytes_view e) {
managed_bytes_view mbv(bv);
std::for_each(llpdi::begin(mbv, sf), llpdi::end(mbv, sf), [&first, &out, &t] (const managed_bytes_view& e) {
if (first) {
first = false;
} else {
@@ -352,7 +353,8 @@ static sstring to_json_string_aux(const list_type_impl& t, bytes_view bv) {
bool first = true;
auto sf = cql_serialization_format::internal();
out << '[';
std::for_each(llpdi::begin(bv, sf), llpdi::end(bv, sf), [&first, &out, &t] (bytes_view e) {
managed_bytes_view mbv(bv);
std::for_each(llpdi::begin(mbv, sf), llpdi::end(mbv, sf), [&first, &out, &t] (const managed_bytes_view& e) {
if (first) {
first = false;
} else {

View File

@@ -150,7 +150,7 @@ static const char* empty_type_name = "org.apache.cassandra.db.marshal.EmptyT
template<typename T>
struct simple_type_traits {
static constexpr size_t serialized_size = sizeof(T);
static T read_nonempty(bytes_view v) {
static T read_nonempty(managed_bytes_view v) {
return read_simple_exactly<T>(v);
}
};
@@ -158,7 +158,7 @@ struct simple_type_traits {
template<>
struct simple_type_traits<bool> {
static constexpr size_t serialized_size = 1;
static bool read_nonempty(bytes_view v) {
static bool read_nonempty(managed_bytes_view v) {
return read_simple_exactly<int8_t>(v) != 0;
}
};
@@ -166,7 +166,7 @@ struct simple_type_traits<bool> {
template<>
struct simple_type_traits<db_clock::time_point> {
static constexpr size_t serialized_size = sizeof(uint64_t);
static db_clock::time_point read_nonempty(bytes_view v) {
static db_clock::time_point read_nonempty(managed_bytes_view v) {
return db_clock::time_point(db_clock::duration(read_simple_exactly<int64_t>(v)));
}
};
@@ -438,7 +438,7 @@ template <> struct int_of_size<float> :
template <typename T>
struct float_type_traits {
static constexpr size_t serialized_size = sizeof(typename int_of_size<T>::itype);
static double read_nonempty(bytes_view v) {
static double read_nonempty(managed_bytes_view v) {
union {
T d;
typename int_of_size<T>::itype i;
@@ -1032,7 +1032,7 @@ map_type_impl::is_value_compatible_with_frozen(const collection_type_impl& previ
}
int32_t
map_type_impl::compare_maps(data_type keys, data_type values, bytes_view o1, bytes_view o2) {
map_type_impl::compare_maps(data_type keys, data_type values, managed_bytes_view o1, managed_bytes_view o2) {
if (o1.empty()) {
return o2.empty() ? 0 : -1;
} else if (o2.empty()) {
@@ -2043,7 +2043,7 @@ template data_value abstract_type::deserialize_impl<>(single_fragmented_view) co
template data_value abstract_type::deserialize_impl<>(ser::buffer_view<bytes_ostream::fragment_iterator>) const;
template data_value abstract_type::deserialize_impl<>(managed_bytes_view) const;
int32_t compare_aux(const tuple_type_impl& t, bytes_view v1, bytes_view v2) {
int32_t compare_aux(const tuple_type_impl& t, const managed_bytes_view& v1, const managed_bytes_view& v2) {
// This is a slight modification of lexicographical_tri_compare:
// when the only difference between the tuples is that one of them has additional trailing nulls,
// we consider them equal. For example, in the following CQL scenario:
@@ -2097,8 +2097,8 @@ int32_t compare_aux(const tuple_type_impl& t, bytes_view v1, bytes_view v2) {
namespace {
struct compare_visitor {
bytes_view v1;
bytes_view v2;
managed_bytes_view v1;
managed_bytes_view v2;
template <typename T> int32_t operator()(const simple_type_impl<T>&) {
if (v1.empty()) {
return v2.empty() ? 0 : -1;
@@ -2125,14 +2125,18 @@ struct compare_visitor {
if (v2.empty()) {
return 1;
}
return utils::timeuuid_tri_compare(v1, v2);
return with_linearized(v1, [&] (bytes_view v1) {
return with_linearized(v2, [&] (bytes_view v2) {
return utils::timeuuid_tri_compare(v1, v2);
});
});
}
int32_t operator()(const listlike_collection_type_impl& l) {
using llpdi = listlike_partial_deserializing_iterator;
auto sf = cql_serialization_format::internal();
return lexicographical_tri_compare(llpdi::begin(v1, sf), llpdi::end(v1, sf), llpdi::begin(v2, sf),
llpdi::end(v2, sf),
[&] (bytes_view o1, bytes_view o2) { return l.get_elements_type()->compare(o1, o2); });
[&] (const managed_bytes_view& o1, const managed_bytes_view& o2) { return l.get_elements_type()->compare(o1, o2); });
}
int32_t operator()(const map_type_impl& m) {
return map_type_impl::compare_maps(m.get_keys_type(), m.get_values_type(), v1, v2);
@@ -2153,7 +2157,11 @@ struct compare_visitor {
}
if (c1 == 1) {
return utils::uuid_tri_compare_timeuuid(v1, v2);
return with_linearized(v1, [&] (bytes_view v1) {
return with_linearized(v2, [&] (bytes_view v2) {
return utils::uuid_tri_compare_timeuuid(v1, v2);
});
});
}
return compare_unsigned(v1, v2);
}
@@ -2218,6 +2226,10 @@ struct compare_visitor {
}
int32_t abstract_type::compare(bytes_view v1, bytes_view v2) const {
return compare(managed_bytes_view(v1), managed_bytes_view(v2));
}
int32_t abstract_type::compare(managed_bytes_view v1, managed_bytes_view v2) const {
try {
return visit(*this, compare_visitor{v1, v2});
} catch (const marshal_exception&) {
@@ -2225,15 +2237,6 @@ int32_t abstract_type::compare(bytes_view v1, bytes_view v2) const {
}
}
int32_t abstract_type::compare(managed_bytes_view v1, managed_bytes_view v2) const {
// FIXME: don't linearize
return with_linearized(v1, [&] (bytes_view v1) {
return with_linearized(v2, [&] (bytes_view v2) {
return compare(v1, v2);
});
});
}
bool abstract_type::equal(bytes_view v1, bytes_view v2) const {
return ::visit(*this, [&](const auto& t) {
if (is_byte_order_equal_visitor{}(t)) {
@@ -2244,11 +2247,11 @@ bool abstract_type::equal(bytes_view v1, bytes_view v2) const {
}
bool abstract_type::equal(managed_bytes_view v1, managed_bytes_view v2) const {
// FIXME: don't linearize
return with_linearized(v1, [&] (bytes_view v1) {
return with_linearized(v2, [&] (bytes_view v2) {
return equal(v1, v2);
});
return ::visit(*this, [&](const auto& t) {
if (is_byte_order_equal_visitor{}(t)) {
return compare_unsigned(v1, v2) == 0;
}
return compare_visitor{v1, v2}(t) == 0;
});
}

View File

@@ -22,8 +22,9 @@
#pragma once
#include <iterator>
#include "bytes.hh"
#include "cql_serialization_format.hh"
#include "utils/fragment_range.hh"
#include "utils/managed_bytes.hh"
int read_collection_size(bytes_view& in, cql_serialization_format sf);
bytes_view read_collection_value(bytes_view& in, cql_serialization_format sf);
@@ -48,18 +49,18 @@ View read_collection_value(View& in, cql_serialization_format sf) {
class listlike_partial_deserializing_iterator {
public:
using iterator_category = std::input_iterator_tag;
using value_type = bytes_view;
using value_type = managed_bytes_view;
using difference_type = std::ptrdiff_t;
using pointer = bytes_view*;
using reference = bytes_view&;
using pointer = managed_bytes_view*;
using reference = managed_bytes_view&;
private:
bytes_view* _in;
managed_bytes_view* _in;
int _remain;
bytes_view _cur;
managed_bytes_view _cur;
cql_serialization_format _sf;
private:
struct end_tag {};
listlike_partial_deserializing_iterator(bytes_view& in, cql_serialization_format sf)
listlike_partial_deserializing_iterator(managed_bytes_view& in, cql_serialization_format sf)
: _in(&in), _sf(sf) {
_remain = read_collection_size(*_in, _sf);
parse();
@@ -68,7 +69,7 @@ private:
: _remain(0), _sf(cql_serialization_format::internal()) { // _sf is bogus, but doesn't matter
}
public:
bytes_view operator*() const { return _cur; }
managed_bytes_view operator*() const { return _cur; }
listlike_partial_deserializing_iterator& operator++() {
--_remain;
parse();
@@ -84,10 +85,10 @@ public:
bool operator!=(const listlike_partial_deserializing_iterator& x) const {
return _remain != x._remain;
}
static listlike_partial_deserializing_iterator begin(bytes_view& in, cql_serialization_format sf) {
static listlike_partial_deserializing_iterator begin(managed_bytes_view& in, cql_serialization_format sf) {
return { in, sf };
}
static listlike_partial_deserializing_iterator end(bytes_view in, cql_serialization_format sf) {
static listlike_partial_deserializing_iterator end(managed_bytes_view in, cql_serialization_format sf) {
return { end_tag() };
}
private:

View File

@@ -53,7 +53,7 @@ public:
virtual bool is_compatible_with_frozen(const collection_type_impl& previous) const override;
virtual bool is_value_compatible_with_frozen(const collection_type_impl& previous) const override;
static int32_t compare_maps(data_type keys_comparator, data_type values_comparator,
bytes_view o1, bytes_view o2);
managed_bytes_view o1, managed_bytes_view o2);
using abstract_type::deserialize;
using collection_type_impl::deserialize;
template <FragmentedView View> data_value deserialize(View v, cql_serialization_format sf) const;