Files
scylladb/types.cc
Avi Kivity a2519926a6 db: add some iostream output operators
Helps debugging
2015-02-19 15:56:26 +02:00

414 lines
14 KiB
C++

/*
* Copyright (C) 2015 Cloudius Systems, Ltd.
*/
#include <boost/lexical_cast.hpp>
#include "cql3/cql3_type.hh"
#include "types.hh"
#include "core/print.hh"
template<typename T>
struct simple_type_traits {
static T read_nonempty(bytes_view v) {
return read_simple_exactly<T>(v);
}
};
template<>
struct simple_type_traits<bool> {
static bool read_nonempty(bytes_view v) {
return read_simple_exactly<int8_t>(v) != 0;
}
};
template<>
struct simple_type_traits<db_clock::time_point> {
static db_clock::time_point read_nonempty(bytes_view v) {
return db_clock::time_point(db_clock::duration(read_simple_exactly<int64_t>(v)));
}
};
template <typename T>
struct simple_type_impl : abstract_type {
simple_type_impl(sstring name) : abstract_type(std::move(name)) {}
virtual int32_t compare(bytes_view v1, bytes_view v2) override {
if (v1.empty()) {
return v2.empty() ? 0 : -1;
}
if (v2.empty()) {
return 1;
}
T a = simple_type_traits<T>::read_nonempty(v1);
T b = simple_type_traits<T>::read_nonempty(v2);
return a == b ? 0 : a < b ? -1 : 1;
}
virtual bool less(bytes_view v1, bytes_view v2) override {
return compare(v1, v2) < 0;
}
virtual bool is_byte_order_equal() const override {
return true;
}
virtual size_t hash(bytes_view v) override {
return std::hash<bytes_view>()(v);
}
};
struct int32_type_impl : simple_type_impl<int32_t> {
int32_type_impl() : simple_type_impl<int32_t>("int32") {}
virtual void serialize(const boost::any& value, std::ostream& out) override {
auto v = boost::any_cast<const int32_t&>(value);
auto u = net::hton(uint32_t(v));
out.write(reinterpret_cast<const char*>(&u), sizeof(u));
}
virtual object_opt deserialize(bytes_view v) override {
return read_simple_opt<int32_t>(v);
}
int32_t compose_value(const bytes& b) {
if (b.size() != 4) {
throw marshal_exception();
}
return (int32_t)net::ntoh(*reinterpret_cast<const uint32_t*>(b.begin()));
}
bytes decompose_value(int32_t v) {
bytes b(bytes::initialized_later(), sizeof(v));
*reinterpret_cast<int32_t*>(b.begin()) = (int32_t)net::hton((uint32_t)v);
return b;
}
int32_t parse_int(sstring_view s) {
try {
return boost::lexical_cast<int32_t>(s.begin(), s.size());
} catch (const boost::bad_lexical_cast& e) {
throw marshal_exception(sprint("Invalid number format '%s'", s));
}
}
virtual bytes from_string(sstring_view s) override {
return decompose_value(parse_int(s));
}
virtual sstring to_string(const bytes& b) override {
if (b.empty()) {
return {};
}
return to_sstring(compose_value(b));
}
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
return cql3::native_cql3_type::int_;
}
};
struct long_type_impl : simple_type_impl<int64_t> {
long_type_impl() : simple_type_impl<int64_t>("long") {}
virtual void serialize(const boost::any& value, std::ostream& out) override {
auto v = boost::any_cast<const int64_t&>(value);
auto u = net::hton(uint64_t(v));
out.write(reinterpret_cast<const char*>(&u), sizeof(u));
}
virtual object_opt deserialize(bytes_view v) override {
return read_simple_opt<int64_t>(v);
}
virtual bytes from_string(sstring_view s) override {
throw std::runtime_error("not implemented");
}
virtual sstring to_string(const bytes& b) override {
throw std::runtime_error("not implemented");
}
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
return cql3::native_cql3_type::bigint;
}
};
struct string_type_impl : public abstract_type {
string_type_impl(sstring name, shared_ptr<cql3::cql3_type> cql3_type)
: abstract_type(name), _cql3_type(cql3_type) {}
virtual void serialize(const boost::any& value, std::ostream& out) override {
auto& v = boost::any_cast<const sstring&>(value);
out.write(v.c_str(), v.size());
}
virtual object_opt deserialize(bytes_view v) override {
// FIXME: validation?
return boost::any(sstring(v.begin(), v.end()));
}
virtual bool less(bytes_view v1, bytes_view v2) override {
return less_unsigned(v1, v2);
}
virtual bool is_byte_order_equal() const override {
return true;
}
virtual bool is_byte_order_comparable() const override {
return true;
}
virtual size_t hash(bytes_view v) override {
return std::hash<bytes_view>()(v);
}
virtual bytes from_string(sstring_view s) override {
return to_bytes(s);
}
virtual sstring to_string(const bytes& b) override {
return sstring(b);
}
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
return _cql3_type;
}
shared_ptr<cql3::cql3_type> _cql3_type;
};
struct bytes_type_impl final : public abstract_type {
bytes_type_impl() : abstract_type("bytes") {}
virtual void serialize(const boost::any& value, std::ostream& out) override {
auto& v = boost::any_cast<const bytes&>(value);
out.write(v.c_str(), v.size());
}
virtual object_opt deserialize(bytes_view v) override {
return boost::any(bytes(v.begin(), v.end()));
}
virtual bool less(bytes_view v1, bytes_view v2) override {
return less_unsigned(v1, v2);
}
virtual bool is_byte_order_equal() const override {
return true;
}
virtual bool is_byte_order_comparable() const override {
return true;
}
virtual size_t hash(bytes_view v) override {
return std::hash<bytes_view>()(v);
}
virtual bytes from_string(sstring_view s) override {
throw std::runtime_error("not implemented");
}
virtual sstring to_string(const bytes& b) override {
throw std::runtime_error("not implemented");
}
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
return cql3::native_cql3_type::blob;
}
};
struct boolean_type_impl : public simple_type_impl<bool> {
boolean_type_impl() : simple_type_impl<bool>("boolean") {}
virtual void serialize(const boost::any& value, std::ostream& out) override {
auto v = boost::any_cast<bool>(value);
char c = v;
out.put(c);
}
virtual object_opt deserialize(bytes_view v) override {
if (v.empty()) {
return {};
}
if (v.size() != 1) {
throw marshal_exception();
}
return boost::any(*v.begin() != 0);
}
virtual bytes from_string(sstring_view s) override {
throw std::runtime_error("not implemented");
}
virtual sstring to_string(const bytes& b) override {
throw std::runtime_error("not implemented");
}
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
return cql3::native_cql3_type::boolean;
}
};
struct date_type_impl : public abstract_type {
date_type_impl() : abstract_type("date") {}
virtual void serialize(const boost::any& value, std::ostream& out) override {
auto v = boost::any_cast<db_clock::time_point>(value);
int64_t i = v.time_since_epoch().count();
i = net::hton(uint64_t(i));
out.write(reinterpret_cast<char*>(&i), 8);
}
virtual object_opt deserialize(bytes_view v) override {
if (v.empty()) {
return {};
}
auto tmp = read_simple_exactly<uint64_t>(v);
return boost::any(db_clock::time_point(db_clock::duration(tmp)));
}
virtual bool less(bytes_view b1, bytes_view b2) override {
return compare_unsigned(b1, b2);
}
virtual bool is_byte_order_comparable() const override {
return true;
}
virtual size_t hash(bytes_view v) override {
return std::hash<bytes_view>()(v);
}
virtual bytes from_string(sstring_view s) override {
throw std::runtime_error("not implemented");
}
virtual sstring to_string(const bytes& b) override {
throw std::runtime_error("not implemented");
}
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
return cql3::native_cql3_type::timestamp;
}
};
struct timeuuid_type_impl : public abstract_type {
timeuuid_type_impl() : abstract_type("timeuuid") {}
virtual void serialize(const boost::any& value, std::ostream& out) override {
// FIXME: optimize
auto& uuid = boost::any_cast<const utils::UUID&>(value);
out.write(to_bytes(uuid).begin(), 16);
}
virtual object_opt deserialize(bytes_view v) override {
uint64_t msb, lsb;
if (v.empty()) {
return {};
}
msb = read_simple<uint64_t>(v);
lsb = read_simple<uint64_t>(v);
if (!v.empty()) {
throw marshal_exception();
}
return boost::any(utils::UUID(msb, lsb));
}
virtual bool less(bytes_view b1, bytes_view b2) override {
if (b1.empty()) {
return b2.empty() ? false : true;
}
if (b2.empty()) {
return false;
}
auto r = compare_bytes(b1, b2);
if (r != 0) {
return r < 0;
} else {
return std::lexicographical_compare(b1.begin(), b1.end(), b2.begin(), b2.end());
}
}
virtual bool is_byte_order_equal() const override {
return true;
}
virtual size_t hash(bytes_view v) override {
return std::hash<bytes_view>()(v);
}
virtual bytes from_string(sstring_view s) override {
throw std::runtime_error("not implemented");
}
virtual sstring to_string(const bytes& b) override {
throw std::runtime_error("not implemented");
}
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
return cql3::native_cql3_type::timeuuid;
}
private:
static int compare_bytes(bytes_view o1, bytes_view o2) {
auto compare_pos = [&] (unsigned pos, int mask, int ifequal) {
int d = (o1[pos] & mask) - (o2[pos] & mask);
return d ? d : ifequal;
};
return compare_pos(6, 0xf,
compare_pos(7, 0xff,
compare_pos(4, 0xff,
compare_pos(5, 0xff,
compare_pos(0, 0xff,
compare_pos(1, 0xff,
compare_pos(2, 0xff,
compare_pos(3, 0xff, 0))))))));
}
friend class uuid_type_impl;
};
struct timestamp_type_impl : simple_type_impl<db_clock::time_point> {
timestamp_type_impl() : simple_type_impl("timestamp") {}
virtual void serialize(const boost::any& value, std::ostream& out) override {
uint64_t v = boost::any_cast<db_clock::time_point>(value).time_since_epoch().count();
v = net::hton(v);
out.write(reinterpret_cast<char*>(&v), 8);
}
virtual object_opt deserialize(bytes_view in) override {
if (in.empty()) {
return {};
}
auto v = read_simple_exactly<uint64_t>(in);
return boost::any(db_clock::time_point(db_clock::duration(v)));
}
// FIXME: isCompatibleWith(timestampuuid)
virtual bytes from_string(sstring_view s) override {
throw std::runtime_error("not implemented");
}
virtual sstring to_string(const bytes& b) override {
throw std::runtime_error("not implemented");
}
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
return cql3::native_cql3_type::timestamp;
}
};
struct uuid_type_impl : abstract_type {
uuid_type_impl() : abstract_type("uuid") {}
virtual void serialize(const boost::any& value, std::ostream& out) override {
// FIXME: optimize
auto& uuid = boost::any_cast<const utils::UUID&>(value);
out.write(to_bytes(uuid).begin(), 16);
}
virtual object_opt deserialize(bytes_view v) override {
if (v.empty()) {
return {};
}
auto msb = read_simple<uint64_t>(v);
auto lsb = read_simple<uint64_t>(v);
if (!v.empty()) {
throw marshal_exception();
}
return boost::any(utils::UUID(msb, lsb));
}
virtual bool less(bytes_view b1, bytes_view b2) override {
if (b1.size() < 16) {
return b2.size() < 16 ? false : true;
}
if (b2.size() < 16) {
return false;
}
auto v1 = (b1[6] >> 4) & 0x0f;
auto v2 = (b2[6] >> 4) & 0x0f;
if (v1 != v2) {
return v1 < v2;
}
if (v1 == 1) {
auto c1 = timeuuid_type_impl::compare_bytes(b1, b2);
auto c2 = timeuuid_type_impl::compare_bytes(b2, b1);
// Require strict ordering
if (c1 != c2) {
return c1;
}
}
return less_unsigned(b1, b2);
}
// FIXME: isCompatibleWith(uuid)
virtual bool is_byte_order_equal() const override {
return true;
}
virtual size_t hash(bytes_view v) override {
return std::hash<bytes_view>()(v);
}
virtual bytes from_string(sstring_view s) override {
throw std::runtime_error("not implemented");
}
virtual sstring to_string(const bytes& b) override {
throw std::runtime_error("not implemented");
}
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() override {
return cql3::native_cql3_type::uuid;
}
};
std::ostream& operator<<(std::ostream& os, const bytes& b) {
return os << to_hex(b);
}
thread_local shared_ptr<abstract_type> int32_type(make_shared<int32_type_impl>());
thread_local shared_ptr<abstract_type> long_type(make_shared<long_type_impl>());
thread_local shared_ptr<abstract_type> ascii_type(make_shared<string_type_impl>("ascii", cql3::native_cql3_type::ascii));
thread_local shared_ptr<abstract_type> bytes_type(make_shared<bytes_type_impl>());
thread_local shared_ptr<abstract_type> utf8_type(make_shared<string_type_impl>("utf8", cql3::native_cql3_type::text));
thread_local shared_ptr<abstract_type> boolean_type(make_shared<boolean_type_impl>());
thread_local shared_ptr<abstract_type> date_type(make_shared<date_type_impl>());
thread_local shared_ptr<abstract_type> timeuuid_type(make_shared<timeuuid_type_impl>());
thread_local shared_ptr<abstract_type> timestamp_type(make_shared<timestamp_type_impl>());
thread_local shared_ptr<abstract_type> uuid_type(make_shared<uuid_type_impl>());