From ea0e1ff3b52e6daf3a4018e390d5fda3c3ecfe4e Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Tue, 26 May 2015 15:31:42 +0300 Subject: [PATCH 1/3] types.hh: Add data_value class Add a data_value class that also encodes a value type. This makes it easier to use than plain boost::any for comparing two values. Signed-off-by: Pekka Enberg --- types.hh | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/types.hh b/types.hh index fdb47b5969..677282f124 100644 --- a/types.hh +++ b/types.hh @@ -169,6 +169,28 @@ inline int32_t compare_unsigned(bytes_view v1, bytes_view v2) { return (int32_t) (v1.size() - v2.size()); } +class abstract_type; + +using data_type = shared_ptr; + +class data_value { + boost::any _value; + data_type _type; +public: + data_value(boost::any&& value, data_type type) + : _value{std::move(value)} + , _type{type} + { } + const boost::any& value() const { + return _value; + } + data_type type() const { + return _type; + } + friend inline bool operator==(const data_value& x, const data_value& y); + friend inline bool operator!=(const data_value& x, const data_value& y); +}; + class serialized_compare; class abstract_type : public enable_shared_from_this { @@ -198,6 +220,9 @@ public: } } virtual boost::any deserialize(bytes_view v) const = 0; + data_value deserialize_value(bytes_view v) const { + return data_value{deserialize(v), shared_from_this()}; + }; virtual void validate(bytes_view v) const { // FIXME } @@ -246,6 +271,9 @@ public: virtual boost::any compose(const bytes& v) const { return deserialize(v); } + data_value compose_value(const bytes& v) const { + return deserialize_value(v); + } bytes decompose(const boost::any& value) const { bytes b(bytes::initialized_later(), serialized_size(value)); auto i = b.begin(); @@ -284,7 +312,16 @@ public: friend class list_type_impl; }; -using data_type = shared_ptr; +inline bool operator==(const data_value& x, const data_value& y) +{ + return x._type == y._type && x._type->decompose(x._value) == y._type->decompose(y._value); +} + +inline bool operator!=(const data_value& x, const data_value& y) +{ + return !(x == y); +} + using bytes_view_opt = std::experimental::optional; static inline @@ -394,6 +431,9 @@ public: collection_mutation::one merge(collection_mutation::view a, collection_mutation::view b) const; virtual void serialize(const boost::any& value, bytes::iterator& out, serialization_format sf) const = 0; virtual boost::any deserialize(bytes_view v, serialization_format sf) const = 0; + data_value deserialize_value(bytes_view v, serialization_format sf) const { + return data_value{deserialize(v, sf), shared_from_this()}; + } bytes_opt reserialize(serialization_format from, serialization_format to, bytes_view_opt v) const; }; From 446555f2ded0d136a756ef3cbb241005a3f25555 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Tue, 26 May 2015 15:55:33 +0300 Subject: [PATCH 2/3] query-result-set.hh: Use data_value instead of boost::any Switch to data_value in preparation for adding support for comparison operators. Signed-off-by: Pekka Enberg --- query-result-set.cc | 24 ++++++++++++------------ query-result-set.hh | 17 +++++++++-------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/query-result-set.cc b/query-result-set.cc index 19228a6a66..04d173bb22 100644 --- a/query-result-set.cc +++ b/query-result-set.cc @@ -29,7 +29,7 @@ void result_set_builder::accept_new_row(const clustering_key& key, const result_ auto static_cells = deserialize(static_row, true); auto regular_cells = deserialize(row, false); - std::unordered_map cells; + std::unordered_map cells; cells.insert(_pkey_cells.begin(), _pkey_cells.end()); cells.insert(ckey_cells.begin(), ckey_cells.end()); cells.insert(static_cells.begin(), static_cells.end()); @@ -42,7 +42,7 @@ void result_set_builder::accept_new_row(const query::result_row_view &static_row auto static_cells = deserialize(static_row, true); auto regular_cells = deserialize(row, false); - std::unordered_map cells; + std::unordered_map cells; cells.insert(_pkey_cells.begin(), _pkey_cells.end()); cells.insert(static_cells.begin(), static_cells.end()); cells.insert(regular_cells.begin(), regular_cells.end()); @@ -54,34 +54,34 @@ void result_set_builder::accept_partition_end(const result_row_view& static_row) _pkey_cells.clear(); } -std::unordered_map +std::unordered_map result_set_builder::deserialize(const partition_key& key) { - std::unordered_map cells; + std::unordered_map cells; auto i = key.begin(*_schema); for (auto&& col : _schema->partition_key_columns()) { - cells.emplace(col.name_as_text(), col.type->deserialize(*i)); + cells.emplace(col.name_as_text(), col.type->deserialize_value(*i)); ++i; } return cells; } -std::unordered_map +std::unordered_map result_set_builder::deserialize(const clustering_key& key) { - std::unordered_map cells; + std::unordered_map cells; auto i = key.begin(*_schema); for (auto&& col : _schema->clustering_key_columns()) { - cells.emplace(col.name_as_text(), col.type->deserialize(*i)); + cells.emplace(col.name_as_text(), col.type->deserialize_value(*i)); ++i; } return cells; } -std::unordered_map +std::unordered_map result_set_builder::deserialize(const result_row_view& row, bool is_static) { - std::unordered_map cells; + std::unordered_map cells; auto i = row.iterator(); auto columns = is_static ? _schema->static_columns() : _schema->regular_columns(); for (auto &&col : columns) { @@ -89,14 +89,14 @@ result_set_builder::deserialize(const result_row_view& row, bool is_static) auto cell = i.next_atomic_cell(); if (cell) { auto view = cell.value(); - cells.emplace(col.name_as_text(), col.type->deserialize(view.value())); + cells.emplace(col.name_as_text(), col.type->deserialize_value(view.value())); } } else { auto cell = i.next_collection_cell(); if (cell) { auto ctype = static_pointer_cast(col.type); auto view = cell.value(); - cells.emplace(col.name_as_text(), ctype->deserialize(view.data, serialization_format::internal())); + cells.emplace(col.name_as_text(), ctype->deserialize_value(view.data, serialization_format::internal())); } } } diff --git a/query-result-set.hh b/query-result-set.hh index 605aa762aa..4b7352c030 100644 --- a/query-result-set.hh +++ b/query-result-set.hh @@ -29,9 +29,9 @@ public: // including regular column cells, partition keys, as well as static values. class result_set_row { schema_ptr _schema; - std::unordered_map _cells; + std::unordered_map _cells; public: - result_set_row(schema_ptr schema, std::unordered_map&& cells) + result_set_row(schema_ptr schema, std::unordered_map&& cells) : _schema{schema} , _cells{std::move(cells)} { } @@ -43,10 +43,11 @@ public: if (it == _cells.end()) { throw no_such_column(column_name); } - if (it->second.empty()) { + auto&& value = it->second.value(); + if (value.empty()) { return std::experimental::nullopt; } - return std::experimental::optional{boost::any_cast(it->second)}; + return std::experimental::optional{boost::any_cast(value)}; } template T get_nonnull(const sstring& column_name) const throw (no_such_column, null_column_value) { @@ -84,7 +85,7 @@ public: class result_set_builder { schema_ptr _schema; std::vector _rows; - std::unordered_map _pkey_cells; + std::unordered_map _pkey_cells; public: result_set_builder(schema_ptr schema); lw_shared_ptr build() const; @@ -94,9 +95,9 @@ public: void accept_new_row(const result_row_view &static_row, const result_row_view &row); void accept_partition_end(const result_row_view& static_row); private: - std::unordered_map deserialize(const partition_key& key); - std::unordered_map deserialize(const clustering_key& key); - std::unordered_map deserialize(const result_row_view& row, bool is_static); + std::unordered_map deserialize(const partition_key& key); + std::unordered_map deserialize(const clustering_key& key); + std::unordered_map deserialize(const result_row_view& row, bool is_static); }; } From 6ed0d8c0e4bb0825efd8070b303d3ae3259c6d43 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Tue, 26 May 2015 13:41:05 +0300 Subject: [PATCH 3/3] query-result-set.hh: Add comparison operators Schema merging code needs to be able to compare two result sets to determine if a keyspace, for example, has changed. Add comparison operators for that. Signed-off-by: Pekka Enberg --- query-result-set.hh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/query-result-set.hh b/query-result-set.hh index 4b7352c030..b06dc9e328 100644 --- a/query-result-set.hh +++ b/query-result-set.hh @@ -57,8 +57,18 @@ public: } throw null_column_value(column_name); } + friend inline bool operator==(const result_set_row& x, const result_set_row& y); + friend inline bool operator!=(const result_set_row& x, const result_set_row& y); }; +inline bool operator==(const result_set_row& x, const result_set_row& y) { + return x._schema == y._schema && x._cells == y._cells; +} + +inline bool operator!=(const result_set_row& x, const result_set_row& y) { + return !(x == y); +} + // Result set is an in-memory representation of query results in // deserialized format. To obtain a result set, use the result_set_builder // class as a visitor to query_result::consume() function. @@ -77,8 +87,13 @@ public: } return _rows[idx]; } + friend inline bool operator==(const result_set& x, const result_set& y); }; +inline bool operator==(const result_set& x, const result_set& y) { + return x._rows == y._rows; +} + // Result set builder is passed as a visitor to query_result::consume() // function. You can call the build() method to obtain a result set that // contains cells from the visited results.