#include #include #include "serialization_format.hh" #include "bytes.hh" #include "schema.hh" #include "keys.hh" #include "sstables/key.hh" #include "../types.hh" #include "utils/data_input.hh" namespace sstables { class internal_serializer { using t_type = std::vector; using it_type = t_type::iterator; t_type _t; it_type _it; public: internal_serializer(t_type types) : _t(types), _it(_t.begin()) {} inline void reset() { _it = _t.begin(); } inline void advance() { assert(_it != _t.end()); _it++; } inline size_t serialized_size(const boost::any& value) { return (*_it)->serialized_size(value); } inline void serialize(const boost::any& value, bytes::iterator& out) { (*_it)->serialize(value, out); } }; class sstable_serializer { public: inline void reset() {} inline void advance() {} inline size_t serialized_size(bytes_view value) { return value.size(); } inline void serialize(bytes_view value, bytes::iterator& out) { out = std::copy_n(value.begin(), value.size(), out); } }; // The iterator has to provide successive elements that are from one of the // type above ( so we know how to serialize them) template inline bytes from_components(Iterator begin, Iterator end, Serializer&& serializer, bool composite = true) { size_t len = 0; for (auto c = begin; c != end; ++c) { auto& component = *c; len += uint8_t(composite) * sizeof(uint16_t); len += serializer.serialized_size(component); len += uint8_t(composite); serializer.advance(); } bytes b(bytes::initialized_later(), len); auto bi = b.begin(); serializer.reset(); for (auto c = begin; c != end; ++c) { auto& component = *c; auto sz = serializer.serialized_size(component); if (sz > std::numeric_limits::max()) { throw runtime_exception(sprint("Cannot serialize component: value too big (%ld bytes)", sz)); } if (composite) { write(bi, sz); } serializer.serialize(component, bi); if (composite) { // Range tombstones are not keys. For collections, only frozen // values can be keys. Therefore, for as long as it is safe to // assume that this code will be used to create representation of // keys, it is safe to assume the trailing byte is always zero. write(bi, uint8_t(0)); } serializer.advance(); } return b; } key key::from_deeply_exploded(const schema& s, const std::vector& v) { auto &pt = s.partition_key_type()->types(); bool composite = pt.size() > 1; return from_components(v.begin(), v.end(), internal_serializer(pt), composite); } key key::from_exploded(const schema& s, const std::vector& v) { auto &pt = s.partition_key_type()->types(); bool composite = pt.size() > 1; return from_components(v.begin(), v.end(), sstable_serializer(), composite); } key key::from_exploded(const schema& s, std::vector&& v) { if (s.partition_key_type()->types().size() == 1) { return key(std::move(v[0])); } return from_components(v.begin(), v.end(), sstable_serializer()); } key key::from_partition_key(const schema& s, const partition_key& pk) { auto &pt = s.partition_key_type()->types(); bool composite = pt.size() > 1; return from_components(pk.begin(s), pk.end(s), sstable_serializer(), composite); } partition_key key::to_partition_key(const schema& s) { return partition_key::from_exploded(s, explode(s)); } template composite composite::from_clustering_element(const schema& s, const ClusteringElement& ce) { return from_components(ce.begin(s), ce.end(s), sstable_serializer()); } template composite composite::from_clustering_element(const schema& s, const clustering_key& ck); template composite composite::from_clustering_element(const schema& s, const clustering_key_prefix& ck); composite composite::from_exploded(const std::vector& v, composite_marker m) { if (v.size() == 0) { return bytes(size_t(1), bytes::value_type(m)); } auto b = from_components(v.begin(), v.end(), sstable_serializer()); b.back() = bytes::value_type(m); return composite(std::move(b)); } composite composite::static_prefix(const schema& s) { static bytes static_marker(size_t(2), bytes::value_type(0xff)); std::vector sv(s.clustering_key_size()); return static_marker + from_components(sv.begin(), sv.end(), sstable_serializer()); } inline std::vector explode_composite(bytes_view _bytes) { std::vector ret; data_input in(_bytes); while (in.has_next()) { auto b = in.read_view_to_blob(); ret.push_back(to_bytes(b)); auto marker = in.read(); // The components will be separated by a null byte, but the last one has special significance. if (in.has_next() && (marker != 0)) { throw runtime_exception(sprint("non-zero component divider found (%d) mid", marker)); } } return ret; } std::vector key::explode(const schema& s) const { if (s.partition_key_size() == 1) { return { _bytes }; } return explode_composite(bytes_view(_bytes)); } std::vector key_view::explode(const schema& s) const { if (s.partition_key_size() == 1) { return { to_bytes(_bytes) }; } return explode_composite(_bytes); } std::vector composite_view::explode() const { return explode_composite(_bytes); } int key_view::tri_compare(const schema& s, partition_key_view other) const { auto lf = other.legacy_form(s); return lexicographical_tri_compare( _bytes.begin(), _bytes.end(), lf.begin(), lf.end(), [] (uint8_t b1, uint8_t b2) { return (int)b1 - b2; }); } }