/* * Copyright (C) 2014 Cloudius Systems, Ltd. */ #ifndef DATABASE_HH_ #define DATABASE_HH_ #include "core/sstring.hh" #include "core/shared_ptr.hh" #include "net/byteorder.hh" #include "utils/UUID.hh" #include "db_clock.hh" #include #include #include #include #include #include #include #include #include #include #include #include "core/future.hh" // FIXME: should be int8_t using bytes = basic_sstring; using bytes_opt = std::experimental::optional; sstring to_hex(const bytes& b); sstring to_hex(const bytes_opt& b); using object_opt = std::experimental::optional; class marshal_exception : public std::exception { sstring _why; public: marshal_exception() : _why("marshalling error") {} marshal_exception(sstring why) : _why(sstring("marshaling error: ") + why) {} virtual const char* why() const { return _why.c_str(); } }; struct runtime_exception : public std::exception { sstring _why; public: runtime_exception(sstring why) : _why(sstring("runtime error: ") + why) {} virtual const char* why() const { return _why.c_str(); } }; class abstract_type { sstring _name; public: abstract_type(sstring name) : _name(name) {} virtual ~abstract_type() {} virtual void serialize(const boost::any& value, std::ostream& out) = 0; virtual object_opt deserialize(std::istream& in) = 0; virtual bool less(const bytes& v1, const bytes& v2) = 0; virtual int32_t compare(const bytes& v1, const bytes& v2) { if (less(v1, v2)) { return -1; } else if (less(v2, v1)) { return 1; } else { return 0; } } object_opt deserialize(const bytes& v) { // FIXME: optimize std::istringstream iss(v); return deserialize(iss); } virtual void validate(const bytes& v) { // FIXME } virtual void validate_collection_member(const bytes& v, const bytes& collection_name) { validate(v); } virtual object_opt compose(const bytes& v) { return deserialize(v); } bytes decompose(const boost::any& value) { // FIXME: optimize std::ostringstream oss; serialize(value, oss); auto s = oss.str(); return bytes(s.data(), s.size()); } sstring name() const { return _name; } protected: template > bool default_less(const bytes& b1, const bytes& b2, Compare compare = Compare()); }; using data_type = shared_ptr; inline size_t hash_value(const shared_ptr& x) { return std::hash()(x.get()); } template shared_ptr data_type_for(); class key_compare { shared_ptr _type; public: key_compare(shared_ptr type) : _type(type) {} bool operator()(const bytes& v1, const bytes& v2) const { return _type->less(v1, v2); } }; struct row; struct paritition; struct column_family; struct row { std::vector cells; }; struct partition { explicit partition(column_family& cf); row static_columns; // row key within partition -> row std::map rows; }; // FIXME: add missing types extern thread_local shared_ptr int32_type; extern thread_local shared_ptr long_type; extern thread_local shared_ptr ascii_type; extern thread_local shared_ptr bytes_type; extern thread_local shared_ptr utf8_type; extern thread_local shared_ptr boolean_type; extern thread_local shared_ptr timeuuid_type; extern thread_local shared_ptr timestamp_type; extern thread_local shared_ptr uuid_type; template <> inline shared_ptr data_type_for() { return int32_type; } template <> inline shared_ptr data_type_for() { return long_type; } template <> inline shared_ptr data_type_for() { return utf8_type; } struct column_definition { sstring name; shared_ptr type; struct name_compare { bool operator()(const column_definition& cd1, const column_definition& cd2) const { return std::lexicographical_compare( cd1.name.begin(), cd1.name.end(), cd2.name.begin(), cd2.name.end(), [] (char c1, char c2) { return uint8_t(c1) < uint8_t(c1); }); } }; }; struct column_family { column_family(shared_ptr partition_key_type, shared_ptr clustering_key_type); // primary key = paritition key + clustering_key shared_ptr partition_key_type; shared_ptr clustering_key_type; std::vector partition_key; std::vector clustering_key; std::vector column_defs; // sorted by name partition& find_or_create_partition(const bytes& key); row& find_or_create_row(const bytes& partition_key, const bytes& clustering_key); partition* find_partition(const bytes& key); row* find_row(const bytes& partition_key, const bytes& clustering_key); // partition key -> partition std::map partitions; }; class keyspace { public: std::unordered_map column_families; static future populate(sstring datadir); }; class database { public: std::unordered_map keyspaces; static future populate(sstring datadir); }; namespace std { template <> struct hash> : boost::hash> { }; } inline bytes to_bytes(const char* x) { return bytes(reinterpret_cast(x), std::strlen(x)); } inline bytes to_bytes(const std::string& x) { return bytes(reinterpret_cast(x.data()), x.size()); } inline bytes to_bytes(const sstring& x) { return bytes(reinterpret_cast(x.c_str()), x.size()); } inline bytes to_bytes(const utils::UUID& uuid) { struct { uint64_t msb; uint64_t lsb; } tmp = { net::hton(uint64_t(uuid.get_most_significant_bits())), net::hton(uint64_t(uuid.get_least_significant_bits())) }; return bytes(reinterpret_cast(&tmp), 16); } // This follows java.util.Comparator // FIXME: Choose a better place than database.hh template struct comparator { virtual ~comparator() {} virtual bool operator()(const T& v1, const T& v2) const = 0; }; inline bool less_unsigned(const bytes& v1, const bytes& v2) { return std::lexicographical_compare(v1.begin(), v1.end(), v2.begin(), v2.end(), [](int8_t v1, int8_t v2) { return uint8_t(v1) < uint8_t(v2); }); } inline int32_t compare_unsigned(const bytes& v1, const bytes& v2) { if (less_unsigned(v1, v2)) { return -1; } else if (less_unsigned(v2, v1)) { return 1; } else { return 0; } } #endif /* DATABASE_HH_ */