Deleted storage/model/properties, started refactoring

This commit is contained in:
Florijan Stamenkovic 2017-02-02 09:03:48 +01:00
parent b329225322
commit e508482ab9
42 changed files with 400 additions and 2182 deletions

View File

@ -18,77 +18,76 @@ class Indexes;
/**
* Main class which represents Database concept in code.
*/
class Db
{
class Db {
public:
using sptr = std::shared_ptr<Db>;
using sptr = std::shared_ptr<Db>;
/**
* This constructor will create a database with the name "default"
*
* NOTE: explicit is here to prevent compiler from evaluating const char *
* into a bool.
*
* @param import_snapshot will in constructor import latest snapshot
* into the db.
*/
explicit Db(bool import_snapshot = true);
/**
* This constructor will create a database with the name "default"
*
* NOTE: explicit is here to prevent compiler from evaluating const char *
* into a bool.
*
* @param import_snapshot will in constructor import latest snapshot
* into the db.
*/
explicit Db(bool import_snapshot = true);
/**
* Construct database with a custom name.
*
* @param name database name
* @param import_snapshot will in constructor import latest snapshot
* into the db.
*/
Db(const char *name, bool import_snapshot = true);
/**
* Construct database with a custom name.
*
* @param name database name
* @param import_snapshot will in constructor import latest snapshot
* into the db.
*/
Db(const char *name, bool import_snapshot = true);
/**
* Construct database with a custom name.
*
* @param name database name
* @param import_snapshot will in constructor import latest snapshot
* into the db.
*/
Db(const std::string &name, bool import_snapshot = true);
/**
* Construct database with a custom name.
*
* @param name database name
* @param import_snapshot will in constructor import latest snapshot
* into the db.
*/
Db(const std::string &name, bool import_snapshot = true);
/**
* Database object can't be copied.
*/
Db(const Db &db) = delete;
/**
* Database object can't be copied.
*/
Db(const Db &db) = delete;
private:
/** database name */
const std::string name_;
/** database name */
const std::string name_;
public:
/** transaction engine related to this database */
tx::Engine tx_engine;
/** transaction engine related to this database */
tx::Engine tx_engine;
/** graph related to this database */
Graph graph;
/** graph related to this database */
Graph graph;
/** garbage collector related to this database*/
Garbage garbage = {tx_engine};
/** garbage collector related to this database*/
Garbage garbage = {tx_engine};
/**
* snapshot engine related to this database
*
* \b IMPORTANT: has to be initialized after name
* */
SnapshotEngine snap_engine = {*this};
/**
* snapshot engine related to this database
*
* \b IMPORTANT: has to be initialized after name
* */
SnapshotEngine snap_engine = {*this};
/**
* Creates Indexes for this database.
*/
Indexes indexes();
// TODO: Indexes should be created only once somwhere Like Db or layer
// between Db and Dbms.
/**
* Creates Indexes for this database.
*/
Indexes indexes();
// TODO: Indexes should be created only once somwhere Like Db or layer
// between Db and Dbms.
/**
* Returns a name of the database.
*
* @return database name
*/
std::string const &name() const;
/**
* Returns a name of the database.
*
* @return database name
*/
std::string const &name() const;
};

View File

@ -2,17 +2,17 @@
#include "database/db.hpp"
#include "database/db_transaction.hpp"
#include "storage/model/properties/property_family.hpp"
#include "utils/border.hpp"
#include "utils/iterator/iterator.hpp"
#include "utils/option.hpp"
#include "storage/model/typed_value_store.hpp"
namespace tx
{
class Transaction;
namespace tx {
class Transaction;
}
class Label;
class EdgeType;
using EdgePropertyFamily = PropertyFamily<TypeGroupEdge>;
@ -44,119 +44,119 @@ using VertexPropertyFamily = PropertyFamily<TypeGroupVertex>;
* which
* returns by default filled EdgeAccessor.
*/
class DbAccessor
{
class DbAccessor {
public:
DbAccessor(Db &db);
DbAccessor(Db &db, tx::Transaction &t);
DbAccessor(Db &db);
DbAccessor(const DbAccessor& other) = delete;
DbAccessor(DbAccessor&& other) = delete;
DbAccessor(Db &db, tx::Transaction &t);
//*******************VERTEX METHODS
// Returns iterator of VertexAccessor for all vertices.
// TODO: Implement class specaily for this return
// NOTE: This implementation must be here to be able to infere return type.
auto vertex_access()
{
return iter::make_map(
iter::make_iter(this->db_transaction.db.graph.vertices.access()),
[&](auto e) -> auto {
return VertexAccessor(&(e->second), db_transaction);
});
}
DbAccessor(const DbAccessor &other) = delete;
// Optionaly return vertex with given internal Id.
Option<const VertexAccessor> vertex_find(const Id &id);
DbAccessor(DbAccessor &&other) = delete;
// Creates new Vertex and returns filled VertexAccessor.
VertexAccessor vertex_insert();
//*******************VERTEX METHODS
// Returns iterator of VertexAccessor for all vertices.
// TODO: Implement class specaily for this return
// NOTE: This implementation must be here to be able to infere return type.
auto vertex_access() {
return iter::make_map(
iter::make_iter(this->db_transaction.db.graph.vertices.access()),
[&](auto e) -> auto {
return VertexAccessor(&(e->second), db_transaction);
});
}
// ******************* EDGE METHODS
// Returns iterator of EdgeAccessor for all edges.
// TODO: Implement class specaily for this return
// NOTE: This implementation must be here to be able to infere return type.
auto edge_access()
{
return iter::make_map(
iter::make_iter(this->db_transaction.db.graph.edges.access()),
[&](auto e) -> auto {
return EdgeAccessor(&(e->second), db_transaction);
});
}
// Optionaly return vertex with given internal Id.
Option<const VertexAccessor> vertex_find(const Id &id);
// Optionally return Edge with given internal Id.
Option<const EdgeAccessor> edge_find(const Id &id);
// Creates new Vertex and returns filled VertexAccessor.
VertexAccessor vertex_insert();
// Creates new Edge and returns filled EdgeAccessor.
// Slighlty faster than const version.
EdgeAccessor edge_insert(VertexAccessor &from, VertexAccessor &to);
// ******************* EDGE METHODS
// Returns iterator of EdgeAccessor for all edges.
// TODO: Implement class specaily for this return
// NOTE: This implementation must be here to be able to infere return type.
auto edge_access() {
return iter::make_map(
iter::make_iter(this->db_transaction.db.graph.edges.access()),
[&](auto e) -> auto {
return EdgeAccessor(&(e->second), db_transaction);
});
}
// Creates new Edge and returns filled EdgeAccessor.
EdgeAccessor edge_insert(VertexAccessor const &from,
VertexAccessor const &to);
// Optionally return Edge with given internal Id.
Option<const EdgeAccessor> edge_find(const Id &id);
// ******************* LABEL METHODS
// Finds or crated label with given name.
const Label &label_find_or_create(const char *name);
// Creates new Edge and returns filled EdgeAccessor.
// Slighlty faster than const version.
EdgeAccessor edge_insert(VertexAccessor &from, VertexAccessor &to);
// True if label with name exists.
bool label_contains(const char *name);
// Creates new Edge and returns filled EdgeAccessor.
EdgeAccessor edge_insert(VertexAccessor const &from,
VertexAccessor const &to);
// ******************** TYPE METHODS
// Finds or creates edge_type with given name.
const EdgeType &type_find_or_create(const char *name);
// ******************* LABEL METHODS
// Finds or crated label with given name.
const Label &label_find_or_create(const char *name);
// True if edge_type with given name exists.
bool type_contains(const char *name);
// True if label with name exists.
bool label_contains(const char *name);
// ******************** PROPERTY METHODS
// ******************** TYPE METHODS
// Finds or creates edge_type with given name.
const EdgeType &type_find_or_create(const char *name);
VertexPropertyFamily &vertex_property_family_get(const std::string &name);
// True if edge_type with given name exists.
bool type_contains(const char *name);
EdgePropertyFamily &edge_property_family_get(const std::string &name);
// ******************** PROPERTY METHODS
// ******************** PROPERTY HELPER METHODS
VertexPropertyFamily::PropertyType::PropertyFamilyKey
vertex_property_key(const std::string &name, Type type);
VertexPropertyFamily &vertex_property_family_get(const std::string &name);
EdgePropertyFamily::PropertyType::PropertyFamilyKey
edge_property_key(const std::string &name, Type type);
EdgePropertyFamily &edge_property_family_get(const std::string &name);
template <class T>
VertexPropertyFamily::PropertyType::PropertyTypeKey<T>
vertex_property_key(const std::string &name)
{
return vertex_property_family_get(name)
.get(T::type)
.template type_key<T>();
}
// ******************** PROPERTY HELPER METHODS
VertexPropertyFamily::PropertyType::PropertyFamilyKey
vertex_property_key(const std::string &name, Type type);
template <class T>
EdgePropertyFamily::PropertyType::PropertyTypeKey<T>
edge_property_key(const std::string &name)
{
return edge_property_family_get(name)
.get(T::type)
.template type_key<T>();
}
EdgePropertyFamily::PropertyType::PropertyFamilyKey
edge_property_key(const std::string &name, Type type);
bool update_indexes();
// ******************** TRANSACTION METHODS
template<class T>
VertexPropertyFamily::PropertyType::PropertyTypeKey <T>
vertex_property_key(const std::string &name) {
return vertex_property_family_get(name)
.get(T::type)
.template type_key<T>();
}
// True if commit was successful, or false if transaction was aborted.
bool commit();
template<class T>
EdgePropertyFamily::PropertyType::PropertyTypeKey <T>
edge_property_key(const std::string &name) {
return edge_property_family_get(name)
.get(T::type)
.template type_key<T>();
}
// Aborts transaction.
void abort();
bool update_indexes();
// ******************** TRANSACTION METHODS
// True if commit was successful, or false if transaction was aborted.
bool commit();
// Aborts transaction.
void abort();
private:
// TODO: make this friend generic for all indexes.
template <class T, class K>
friend class NonUniqueUnorderedIndex;
template <class T, class K>
friend class UniqueOrderedIndex;
// TODO: make this friend generic for all indexes.
template<class T, class K>
friend
class NonUniqueUnorderedIndex;
DbTransaction db_transaction;
template<class T, class K>
friend
class UniqueOrderedIndex;
DbTransaction db_transaction;
};

View File

@ -1,111 +1,104 @@
#pragma once
#include <cassert>
#include "database/db_accessor.hpp"
#include "storage/model/properties/property_family.hpp"
#include "storage/vertex_accessor.hpp"
#include "storage/model/typed_value.hpp"
#include "storage/model/typed_value_store.hpp"
// Holder for element data which he can then insert as a vertex or edge into the
// database depending on the available data and called add_* method.
class ElementSkeleton
{
class ElementSkeleton {
public:
ElementSkeleton(DbAccessor &db) : db(db){};
ElementSkeleton(DbAccessor &db) : db(db) {};
void add_property(StoredProperty<TypeGroupVertex> &&prop)
{
properties_v.push_back(std::move(prop));
void add_property(StoredProperty<TypeGroupVertex> &&prop) {
properties_v.push_back(std::move(prop));
}
void add_property(StoredProperty<TypeGroupEdge> &&prop) {
properties_e.push_back(std::move(prop));
}
void set_element_id(size_t id) {
el_id = make_option<size_t>(std::move(id));
}
void add_label(Label const &label) { labels.push_back(&label); }
void set_type(EdgeType const &type) { this->type = make_option(&type); }
void set_from(VertexAccessor &&va) {
from_va = make_option<VertexAccessor>(std::move(va));
}
void set_to(VertexAccessor &&va) {
to_va = make_option<VertexAccessor>(std::move(va));
}
VertexAccessor add_vertex() {
assert(properties_e.empty());
auto va = db.vertex_insert();
for (auto l : labels) {
// std::cout << *l << std::endl;
va.add_label(*l);
}
void add_property(StoredProperty<TypeGroupEdge> &&prop)
{
properties_e.push_back(std::move(prop));
for (auto prop : properties_v) {
va.set(std::move(prop));
}
void set_element_id(size_t id)
{
el_id = make_option<size_t>(std::move(id));
return va;
}
// Return error msg if unsuccessful
Option<std::string> add_edge() {
if (!from_va.is_present()) {
return make_option(std::string("From field must be seted"));
}
if (!to_va.is_present()) {
return make_option(std::string("To field must be seted"));
}
if (!type.is_present()) {
return make_option(std::string("Type field must be seted"));
}
assert(properties_v.empty());
auto ve = db.edge_insert(from_va.get(), to_va.get());
ve.edge_type(*type.get());
for (auto prop : properties_e) {
ve.set(std::move(prop));
}
void add_label(Label const &label) { labels.push_back(&label); }
return make_option<std::string>();
}
void set_type(EdgeType const &type) { this->type = make_option(&type); }
void clear() {
el_id = make_option<size_t>();
to_va = make_option<VertexAccessor>();
from_va = make_option<VertexAccessor>();
type = make_option<EdgeType const *>();
labels.clear();
properties_v.clear();
properties_e.clear();
}
void set_from(VertexAccessor &&va)
{
from_va = make_option<VertexAccessor>(std::move(va));
}
void set_to(VertexAccessor &&va)
{
to_va = make_option<VertexAccessor>(std::move(va));
}
VertexAccessor add_vertex()
{
assert(properties_e.empty());
auto va = db.vertex_insert();
for (auto l : labels) {
// std::cout << *l << std::endl;
va.add_label(*l);
}
for (auto prop : properties_v) {
va.set(std::move(prop));
}
return va;
}
// Return error msg if unsuccessful
Option<std::string> add_edge()
{
if (!from_va.is_present()) {
return make_option(std::string("From field must be seted"));
}
if (!to_va.is_present()) {
return make_option(std::string("To field must be seted"));
}
if (!type.is_present()) {
return make_option(std::string("Type field must be seted"));
}
assert(properties_v.empty());
auto ve = db.edge_insert(from_va.get(), to_va.get());
ve.edge_type(*type.get());
for (auto prop : properties_e) {
ve.set(std::move(prop));
}
return make_option<std::string>();
}
void clear()
{
el_id = make_option<size_t>();
to_va = make_option<VertexAccessor>();
from_va = make_option<VertexAccessor>();
type = make_option<EdgeType const *>();
labels.clear();
properties_v.clear();
properties_e.clear();
}
// Returns import local id.
Option<size_t> element_id() { return el_id; }
// Returns import local id.
Option<size_t> element_id() { return el_id; }
private:
DbAccessor &db;
DbAccessor &db;
Option<size_t> el_id;
Option<VertexAccessor> to_va;
Option<VertexAccessor> from_va;
Option<EdgeType const *> type;
std::vector<Label const *> labels;
std::vector<StoredProperty<TypeGroupEdge>> properties_e;
std::vector<StoredProperty<TypeGroupVertex>> properties_v;
Option<size_t> el_id;
Option<VertexAccessor> to_va;
Option<VertexAccessor> from_va;
Option<EdgeType const *> type;
std::vector<Label const *> labels;
TypedValueStore properties_e;
TypedValueStore properties_v;
};

View File

@ -1,57 +0,0 @@
#pragma once
#include "database/db_accessor.hpp"
#include "import/fillings/common.hpp"
#include "import/fillings/filler.hpp"
#include "utils/array_store.hpp"
// Parses Array of elements type T.
// TG - Type group
// T - type of element in array.
// A - property type in database for holding arrays.
template <class TG, class T, class A>
class ArrayFiller : public Filler
{
public:
ArrayFiller(
BaseImporter &db,
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key,
T (*f)(const char *))
: bim(db), key(key), f(f)
{
}
// Fills skeleton with data from str. Returns error description if
// error occurs.
Option<std::string> fill(ElementSkeleton &data, char *str) final
{
sub_str.clear();
std::vector<T> vec;
bim.extract(str, bim.parts_array_mark, sub_str);
for (auto s : sub_str) {
if (s[0] != '\0') {
vec.push_back(f(s));
}
}
if (vec.size() > 0) {
data.add_property(StoredProperty<TG>(A(std::move(vec)), key));
}
return make_option<std::string>();
}
private:
BaseImporter &bim;
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
vector<char *> sub_str;
T (*f)(const char *);
};
template <class TG, class T, class A>
auto make_array_filler(
BaseImporter &db,
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key,
T (*f)(const char *))
{
return new ArrayFiller<TG, T, A>(db, key, f);
}

View File

@ -1,34 +0,0 @@
#pragma once
#include "import/fillings/common.hpp"
#include "import/fillings/filler.hpp"
#include "storage/model/properties/all.hpp"
#include "storage/model/properties/flags.hpp"
#include "storage/model/properties/property_family.hpp"
// Parses double.
// TG - Type group
template <class TG>
class DoubleFiller : public Filler
{
public:
DoubleFiller(
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
: key(key)
{
}
// Fills skeleton with data from str. Returns error description if
// error occurs.
Option<std::string> fill(ElementSkeleton &data, char *str) final
{
if (str[0] != '\0') {
data.add_property(StoredProperty<TG>(Double(to_double(str)), key));
}
return make_option<std::string>();
}
private:
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
};

View File

@ -1,35 +0,0 @@
#pragma once
#include "import/fillings/common.hpp"
#include "import/fillings/filler.hpp"
#include "storage/model/properties/all.hpp"
#include "storage/model/properties/flags.hpp"
#include "storage/model/properties/property_family.hpp"
// Parses int32.
// TG - Type group
template <class TG>
class Int32Filler : public Filler
{
public:
Int32Filler(
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
: key(key)
{
}
// Fills skeleton with data from str. Returns error description if
// error occurs.
Option<std::string> fill(ElementSkeleton &data, char *str) final
{
if (str[0] != '\0') {
data.add_property(StoredProperty<TG>(Int32(to_int32(str)), key));
}
return make_option<std::string>();
}
private:
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
};

View File

@ -7,46 +7,43 @@
#include "mvcc/serialization_error.hpp"
#include "storage/locking/record_lock.hpp"
namespace mvcc
{
namespace mvcc {
template <class T>
class VersionList
{
template<class T>
class VersionList {
friend class Accessor;
public:
public:
using uptr = std::unique_ptr<VersionList<T>>;
using item_t = T;
VersionList(Id id) : id(id) {}
VersionList(const VersionList &) = delete;
/* @brief Move constructs the version list
* Note: use only at the beginning of the "other's" lifecycle since this
* constructor doesn't move the RecordLock, but only the head pointer
*/
VersionList(VersionList &&other) : id(other.id)
{
this->head = other.head.load();
other.head = nullptr;
VersionList(VersionList &&other) : id(other.id) {
this->head = other.head.load();
other.head = nullptr;
}
~VersionList() { delete head.load(); }
friend std::ostream &operator<<(std::ostream &stream,
const VersionList<T> &vlist)
{
stream << "VersionList" << std::endl;
const VersionList<T> &vlist) {
stream << "VersionList" << std::endl;
auto record = vlist.head.load();
auto record = vlist.head.load();
while (record != nullptr) {
stream << "-- " << *record << std::endl;
record = record->next();
}
while (record != nullptr) {
stream << "-- " << *record << std::endl;
record = record->next();
}
return stream;
return stream;
}
auto gc_lock_acquire() { return std::unique_lock<RecordLock>(lock); }
@ -59,156 +56,148 @@ public:
// possibilty that someone is reading it at this moment but he cant change
// it or get anything from it.
// TODO: Validate this method
bool gc_deleted(const Id &id)
{
auto r = head.load(std::memory_order_seq_cst);
T *bef = nullptr;
bool gc_deleted(const Id &id) {
auto r = head.load(std::memory_order_seq_cst);
T *bef = nullptr;
// nullptr
// |
// [v1] ...
// |
// [v2] <------+
// | |
// [v3] <------+
// | | Jump backwards until you find a first old deleted
// [VerList] ----+ version, or you reach the end of the list
//
while (r != nullptr && !r->is_deleted_before(id)) {
bef = r;
r = r->next(std::memory_order_seq_cst);
// nullptr
// |
// [v1] ...
// |
// [v2] <------+
// | |
// [v3] <------+
// | | Jump backwards until you find a first old deleted
// [VerList] ----+ version, or you reach the end of the list
//
while (r != nullptr && !r->is_deleted_before(id)) {
bef = r;
r = r->next(std::memory_order_seq_cst);
}
if (bef == nullptr) {
// if r==nullptr he is needed and it is expecting insert.
// if r!=nullptr vertex has been explicitly deleted. It can't be
// updated because for update, visible record is needed and at this
// point whe know that there is no visible record for any
// transaction. Also it cant be inserted because head isn't nullptr.
// Remove also requires visible record. Find wont return any record
// because none is visible.
return r != nullptr;
} else {
if (r != nullptr) {
// Bef is possible visible to some transaction but r is not and
// the implementation of this version list guarantees that
// record r and older records aren't accessed.
bef->next(nullptr, std::memory_order_seq_cst);
delete r; // THIS IS ISSUE IF MULTIPLE THREADS TRY TO DO THIS
}
if (bef == nullptr) {
// if r==nullptr he is needed and it is expecting insert.
// if r!=nullptr vertex has been explicitly deleted. It can't be
// updated because for update, visible record is needed and at this
// point whe know that there is no visible record for any
// transaction. Also it cant be inserted because head isn't nullptr.
// Remove also requires visible record. Find wont return any record
// because none is visible.
return r != nullptr;
} else {
if (r != nullptr) {
// Bef is possible visible to some transaction but r is not and
// the implementation of this version list guarantees that
// record r and older records aren't accessed.
bef->next(nullptr, std::memory_order_seq_cst);
delete r; // THIS IS ISSUE IF MULTIPLE THREADS TRY TO DO THIS
}
return false;
}
return false;
}
}
void vacuum() {}
T *find(const tx::TransactionRead &t) const
{
auto r = head.load(std::memory_order_seq_cst);
T *find(const tx::TransactionRead &t) const {
auto r = head.load(std::memory_order_seq_cst);
// nullptr
// |
// [v1] ...
// |
// [v2] <------+
// | |
// [v3] <------+
// | | Jump backwards until you find a first visible
// [VerList] ----+ version, or you reach the end of the list
//
while (r != nullptr && !r->visible(t))
r = r->next(std::memory_order_seq_cst);
// nullptr
// |
// [v1] ...
// |
// [v2] <------+
// | |
// [v3] <------+
// | | Jump backwards until you find a first visible
// [VerList] ----+ version, or you reach the end of the list
//
while (r != nullptr && !r->visible(t))
r = r->next(std::memory_order_seq_cst);
return r;
return r;
}
T *insert(tx::Transaction &t)
{
assert(head == nullptr);
T *insert(tx::Transaction &t) {
assert(head == nullptr);
// create a first version of the record
// TODO replace 'new' with something better
auto v1 = new T();
// create a first version of the record
// TODO replace 'new' with something better
auto v1 = new T();
// mark the record as created by the transaction t
v1->mark_created(t);
// mark the record as created by the transaction t
v1->mark_created(t);
head.store(v1, std::memory_order_seq_cst);
head.store(v1, std::memory_order_seq_cst);
return v1;
return v1;
}
T *update(tx::Transaction &t)
{
assert(head != nullptr);
auto record = find(t);
T *update(tx::Transaction &t) {
assert(head != nullptr);
auto record = find(t);
// check if we found any visible records
if (!record) return nullptr;
// check if we found any visible records
if (!record) return nullptr;
return update(record, t);
return update(record, t);
}
T *update(T *record, tx::Transaction &t)
{
assert(record != nullptr);
lock_and_validate(record, t);
T *update(T *record, tx::Transaction &t) {
assert(record != nullptr);
lock_and_validate(record, t);
// It could be done with unique_ptr but while this could mean memory
// leak on exception, unique_ptr could mean use after free. Memory
// leak is less dangerous.
auto updated = new T();
updated->data = record->data;
// It could be done with unique_ptr but while this could mean memory
// leak on exception, unique_ptr could mean use after free. Memory
// leak is less dangerous.
auto updated = new T();
updated->data = record->data;
updated->mark_created(t);
record->mark_deleted(t);
updated->mark_created(t);
record->mark_deleted(t);
updated->next(record, std::memory_order_seq_cst);
head.store(updated, std::memory_order_seq_cst);
updated->next(record, std::memory_order_seq_cst);
head.store(updated, std::memory_order_seq_cst);
return updated;
return updated;
}
bool remove(tx::Transaction &t)
{
assert(head != nullptr);
auto record = find(t);
bool remove(tx::Transaction &t) {
assert(head != nullptr);
auto record = find(t);
if (!record) return false;
if (!record) return false;
// TODO: Is this lock and validate necessary
lock_and_validate(record, t);
return remove(record, t), true;
// TODO: Is this lock and validate necessary
lock_and_validate(record, t);
return remove(record, t), true;
}
void remove(T *record, tx::Transaction &t)
{
assert(record != nullptr);
lock_and_validate(record, t);
record->mark_deleted(t);
void remove(T *record, tx::Transaction &t) {
assert(record != nullptr);
lock_and_validate(record, t);
record->mark_deleted(t);
}
const Id id;
private:
void lock_and_validate(T *record, tx::Transaction &t)
{
assert(record != nullptr);
private:
void lock_and_validate(T *record, tx::Transaction &t) {
assert(record != nullptr);
// take a lock on this node
t.take_lock(lock);
// take a lock on this node
t.take_lock(lock);
// if the record hasn't been deleted yet or the deleting transaction
// has aborted, it's ok to modify it
if (!record->tx.exp() || !record->exp_committed(t)) return;
// if the record hasn't been deleted yet or the deleting transaction
// has aborted, it's ok to modify it
if (!record->tx.exp() || !record->exp_committed(t)) return;
// if it committed, then we have a serialization conflict
assert(record->hints.load().exp.is_committed());
throw SerializationError();
// if it committed, then we have a serialization conflict
assert(record->hints.load().exp.is_committed());
throw SerializationError();
}
std::atomic<T *> head{nullptr};
RecordLock lock;
};
};
}

View File

@ -1,10 +0,0 @@
#pragma once
#include "storage/model/properties/array.hpp"
#include "storage/model/properties/bool.hpp"
#include "storage/model/properties/double.hpp"
#include "storage/model/properties/float.hpp"
#include "storage/model/properties/int32.hpp"
#include "storage/model/properties/int64.hpp"
#include "storage/model/properties/null.hpp"
#include "storage/model/properties/string.hpp"

View File

@ -1,77 +0,0 @@
#pragma once
#include <memory>
#include <vector>
#include "storage/model/properties/flags.hpp"
#include "utils/array_store.hpp"
template <class T, Flags flag_t>
class Array
{
public:
const static Type type;
using Arr = ArrayStore<T>;
Array(Arr &&value) : data(std::make_shared<Arr>(std::move(value))) {}
Arr &value() { return *data.get(); }
Arr const &value() const { return *data.get(); }
std::ostream &print(std::ostream &stream) const
{
stream << "[";
for (auto e : value()) {
stream << e << ",";
}
stream << "]";
return stream;
}
friend std::ostream &operator<<(std::ostream &stream, const Array &prop)
{
return prop.print(stream);
}
bool operator==(const Array &other) const { return *this == other.value(); }
bool operator==(const Arr &other) const
{
auto arr = value();
if (arr.size() != other.size()) {
return false;
}
auto n = arr.size();
for (size_t i = 0; i < n; i++) {
if (arr[i] != other[i]) {
return false;
}
}
return true;
}
// NOTE: OTHER METHODS WILL AUTOMATICALLY USE THIS IN CERTAIN SITUATIONS TO
// MOVE ARR OUT OF SHARED_PTR WHICH IS BAD
// operator const Arr &() const { return value(); };
private:
// TODO: PropertyHolder can be 8B smaller if this uses custom shared_ptr
// which has only one ptr here.
std::shared_ptr<Arr> data;
};
using ArrayString = Array<std::string, Flags::ArrayString>;
using ArrayBool = Array<bool, Flags::ArrayBool>;
using ArrayInt32 = Array<int32_t, Flags::ArrayInt32>;
using ArrayInt64 = Array<int64_t, Flags::ArrayInt64>;
using ArrayFloat = Array<float, Flags::ArrayFloat>;
using ArrayDouble = Array<double, Flags::ArrayDouble>;

View File

@ -1,37 +0,0 @@
#pragma once
#include "storage/model/properties/flags.hpp"
class Bool
{
public:
const static Type type;
Bool(bool d) : data(d) {}
bool &value() { return data; }
bool const &value() const { return data; }
std::ostream &print(std::ostream &stream) const
{
return operator<<(stream, *this);
}
friend std::ostream &operator<<(std::ostream &stream, const Bool &prop)
{
return stream << prop.data;
}
bool operator==(const Bool &other) const
{
return other.value() == value();
}
bool operator==(bool v) const { return value() == v; }
explicit operator bool() const { return value(); }
private:
bool data;
};

View File

@ -1,19 +0,0 @@
#pragma once
#include "storage/model/properties/flags.hpp"
#include "storage/model/properties/floating.hpp"
struct Double : public Floating<Double>
{
public:
const static Type type;
Double(double d) : data(d) {}
double &value() { return data; }
double const &value() const { return data; }
private:
double data;
};

View File

@ -1,151 +0,0 @@
#pragma once
#include <cassert>
#include <ostream>
#include <string>
#include <vector>
#include "utils/total_ordering.hpp"
#include "utils/underlying_cast.hpp"
// TODO: Revise this
// NOTE: Why not just count all the types?
enum class Flags : unsigned
{
// Type | Mask
// -----------+----------------------------------------
// Null | 0000 0000 0000 0000 0000 0000 0000 0000
// -----------+----------------------------------------
// Bool | 0000 0000 0000 0000 0000 0000 0000 0001
// + True | 0000 0000 0000 0000 0000 0000 0000 0011
// + False | 0000 0000 0000 0000 0000 0000 0000 0101
// -----------+----------------------------------------
// String | 0000 0000 0000 0000 0000 0000 0000 1000
// -----------+----------------------------------------
// Number | 0000 0000 0000 0000 0000 0000 0001 0000
// + Integral | 0000 0000 0000 0000 0000 0000 0011 0000
// + Int32 | 0000 0000 0000 0000 0000 0000 0111 0000
// + Int64 | 0000 0000 0000 0000 0000 0000 1011 0000
// + Floating | 0000 0000 0000 0000 0000 0001 0001 0000
// + Float | 0000 0000 0000 0000 0000 0011 0001 0000
// + Double | 0000 0000 0000 0000 0000 0101 0001 0000
// -----------+----------------------------------------
// Array | 0000 0000 0000 0000 0001 0000 0000 0000
// -----------+----------------------------------------
Null = 0x0,
Bool = 0x1,
// TODO remove this two values
True = 0x2 | Bool,
False = 0x4 | Bool,
String = 0x8,
Number = 0x10,
Integral = 0x20 | Number,
Int32 = 0x40 | Integral,
Int64 = 0x80 | Integral,
Floating = 0x100 | Number,
Float = 0x200 | Floating,
Double = 0x400 | Floating,
Array = 0x1000,
ArrayBool = (Bool << 13) | Array,
ArrayString = (String << 13) | Array,
ArrayInt32 = (Int32 << 13) | Array,
ArrayInt64 = (Int64 << 13) | Array,
ArrayFloat = (Float << 13) | Array,
ArrayDouble = (Double << 13) | Array,
type_mask = 0xFFFFFF
};
// Mask to turn flags into type. It passes all bits except 0x2 and 0x4 which
// correspond
// to True and False.
const unsigned flags_equal_mask = 0xFF3FF9;
class Type : public TotalOrdering<Type>
{
public:
constexpr Type(Flags f) : value(underlying_cast(f) & flags_equal_mask)
{
Flags o = Flags(value);
assert(o == Flags::Null || o == Flags::Bool || o == Flags::String ||
o == Flags::Int32 || o == Flags::Int64 || o == Flags::Float ||
o == Flags::Double || o == Flags::ArrayBool ||
o == Flags::ArrayString || o == Flags::ArrayInt32 ||
o == Flags::ArrayInt64 || o == Flags::ArrayFloat ||
o == Flags::ArrayDouble);
}
const std::string to_str() const
{
switch (flags()) {
case Flags::Null:
return "null";
case Flags::Bool:
return "bool";
case Flags::String:
return "str";
case Flags::Int32:
return "int32";
case Flags::Int64:
return "int64";
case Flags::Float:
return "float";
case Flags::Double:
return "double";
case Flags::ArrayBool:
return "array_bool";
case Flags::ArrayString:
return "array_string";
case Flags::ArrayInt64:
return "array_int64";
case Flags::ArrayInt32:
return "array_int32";
case Flags::ArrayFloat:
return "array_float";
case Flags::ArrayDouble:
return "array_double";
default:
assert(false);
return "err_unknown_type_" + std::to_string(value);
}
}
Flags flags() const { return Flags(value); }
Type get_type() const { return *this; }
bool is_array() const
{
return (value & underlying_cast(Flags::Array)) != 0;
}
template <class T>
bool is() const
{
return *this == T::type;
}
bool operator==(Flags other) const { return *this == Type(other); }
bool operator!=(Flags other) const { return *this != Type(other); }
friend bool operator<(const Type &lhs, const Type &rhs)
{
return lhs.value < rhs.value;
}
friend bool operator==(const Type &lhs, const Type &rhs)
{
return lhs.value == rhs.value;
}
private:
const unsigned value; // TODO: turn this to flags
};

View File

@ -1,23 +0,0 @@
#pragma once
#include "storage/model/properties/double.hpp"
#include "storage/model/properties/flags.hpp"
#include "storage/model/properties/floating.hpp"
class Float : public Floating<Float>
{
public:
const static Type type;
Float(float d) : data(d) {}
operator Double() const { return Double(value()); }
float &value() { return data; }
float const &value() const { return data; }
private:
float data;
};

View File

@ -1,9 +0,0 @@
#pragma once
#include "storage/model/properties/number.hpp"
template <class Derived>
struct Floating : public Number<Derived>
{
using Number<Derived>::Number;
};

View File

@ -1,22 +0,0 @@
#pragma once
#include "storage/model/properties/flags.hpp"
#include "storage/model/properties/int64.hpp"
#include "storage/model/properties/integral.hpp"
class Int32 : public Integral<Int32>
{
public:
const static Type type;
Int32(int32_t d) : data(d) {}
operator Int64() const { return Int64(value()); }
int32_t &value() { return data; }
int32_t const &value() const { return data; }
private:
int32_t data;
};

View File

@ -1,18 +0,0 @@
#pragma once
#include "storage/model/properties/flags.hpp"
#include "storage/model/properties/integral.hpp"
class Int64 : public Integral<Int64>
{
public:
const static Type type;
Int64(int64_t d) : data(d) {}
int64_t &value() { return data; }
int64_t const &value() const { return data; }
private:
int64_t data;
};

View File

@ -1,18 +0,0 @@
#pragma once
#include "storage/model/properties/floating.hpp"
#include "storage/model/properties/number.hpp"
#include "storage/model/properties/utils/modulo.hpp"
template <class Derived>
struct Integral : public Number<Derived>, public Modulo<Derived>
{
using Number<Derived>::Number;
template <class T, typename = std::enable_if_t<
std::is_base_of<Floating<T>, T>::value>>
operator T() const
{
return T(this->derived().value);
}
};

View File

@ -1,72 +0,0 @@
#pragma once
#include "storage/model/properties/properties.hpp"
#include "storage/type_group_edge.hpp"
#include "storage/type_group_vertex.hpp"
template <class Buffer>
struct JsonWriter
{
public:
JsonWriter(Buffer &buffer) : buffer(buffer) { buffer << '{'; };
void handle(const StoredProperty<TypeGroupEdge> &prop)
{
handle<TypeGroupEdge>(prop);
}
void handle(const StoredProperty<TypeGroupVertex> &prop)
{
handle<TypeGroupVertex>(prop);
}
template <class TG>
void handle(const StoredProperty<TG> &prop)
{
if (!first) buffer << ',';
if (first) first = false;
buffer << '"' << prop.key.family_name() << "\":";
prop.accept(*this);
}
void handle(const Null &v) { buffer << "NULL"; }
void handle(const Bool &b) { buffer << (b ? "true" : "false"); }
void handle(const String &s) { buffer << '"' << s.value() << '"'; }
void handle(const Int32 &int32) { buffer << std::to_string(int32.value()); }
void handle(const Int64 &int64) { buffer << std::to_string(int64.value()); }
void handle(const Float &f) { buffer << std::to_string(f.value()); }
void handle(const Double &d) { buffer << std::to_string(d.value()); }
// Not yet implemented
void handle(const ArrayBool &) { assert(false); }
// Not yet implemented
void handle(const ArrayInt32 &) { assert(false); }
// Not yet implemented
void handle(const ArrayInt64 &) { assert(false); }
// Not yet implemented
void handle(const ArrayFloat &) { assert(false); }
// Not yet implemented
void handle(const ArrayDouble &) { assert(false); }
// Not yet implemented
void handle(const ArrayString &) { assert(false); }
void finish() { buffer << '}'; }
private:
bool first{true};
Buffer &buffer;
};

View File

@ -1,23 +0,0 @@
#pragma once
#include <ostream>
#include <string>
#include "storage/model/properties/flags.hpp"
#include "utils/void.hpp"
class Null
{
public:
const static Type type;
Void &value() { return _void; }
Void const &value() const { return _void; }
std::ostream &print(std::ostream &stream) const;
friend std::ostream &operator<<(std::ostream &stream, const Null &prop);
bool operator==(const Null &) const;
explicit operator bool();
};

View File

@ -1,33 +0,0 @@
#pragma once
#include "storage/model/properties/utils/math_operations.hpp"
#include "storage/model/properties/utils/unary_negation.hpp"
#include "utils/total_ordering.hpp"
template <class Derived>
class Number : public TotalOrdering<Derived>,
public MathOperations<Derived>,
public UnaryNegation<Derived>
{
public:
std::ostream &print(std::ostream &stream) const
{
return operator<<(stream, this->derived());
}
friend std::ostream &operator<<(std::ostream &s, const Derived &number)
{
return s << number.value();
}
friend bool operator==(const Derived &lhs, const Derived &rhs)
{
return lhs.value() == rhs.value();
}
friend bool operator<(const Derived &lhs, const Derived &rhs)
{
return lhs.value() == rhs.value();
}
};

View File

@ -1,99 +0,0 @@
#pragma once
#include <unordered_set>
#include "utils/option.hpp"
#include "utils/option_ptr.hpp"
#include "storage/model/properties/property_family.hpp"
#include "storage/model/properties/stored_property.hpp"
// TG - type group (TypeGroupEntity)
// TODO: think about a better place
template <class TG, class T>
using type_key_t =
typename PropertyFamily<TG>::PropertyType::template PropertyTypeKey<T>;
// Collection of stored properties.
// NOTE: Currently underlying strucutre is a vector which is fine for smaller
// number of properties.
template <class TG>
class Properties
{
public:
using property_key =
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey;
template <class T>
using type_key_t =
typename PropertyFamily<TG>::PropertyType::template PropertyTypeKey<T>;
auto begin() const { return props.begin(); }
auto cbegin() const { return props.cbegin(); }
auto end() const { return props.end(); }
auto cend() const { return props.cend(); }
size_t size() const { return props.size(); }
const bool contains(property_key &key) const;
const StoredProperty<TG> &at(PropertyFamily<TG> &key) const;
const StoredProperty<TG> &at(property_key &key) const;
template <class T>
OptionPtr<const T> at(type_key_t<T> &key) const
{
for (auto &prop : props) {
if (prop.key == key) {
if (prop.template is<T>()) {
return OptionPtr<const T>(&(prop.template as<T>()));
}
break;
}
}
return OptionPtr<const T>();
}
void set(StoredProperty<TG> &&value);
void clear(property_key &key);
void clear(PropertyFamily<TG> &key);
template <class Handler>
void accept(Handler &handler) const
{
for (auto &kv : props)
kv.accept(handler);
handler.finish();
}
template <class Handler>
void handle(Handler &handler) const
{
for (auto &kv : props)
handler.handle(kv);
handler.finish();
}
template <class Handler>
void for_all(Handler handler) const
{
for (auto &kv : props)
handler(kv);
}
private:
using props_t = std::vector<StoredProperty<TG>>;
// TODO: more bytes can be saved if this is array with exact size as number
// of elements.
// TODO: even more bytes can be saved if this is one ptr to structure which
// holds len followed by len sized array.
props_t props;
};

View File

@ -1,47 +0,0 @@
#pragma once
#include <cassert>
#include <memory>
#include <ostream>
#include <string>
#include <vector>
#include "storage/model/properties/flags.hpp"
#include "storage/model/properties/property_holder.hpp"
class Null;
// Property Class designated for creation outside the database.
class Property : public PropertyHolder<Type>
{
public:
using PropertyHolder<Type>::PropertyHolder;
static Property handle(Void &&v);
static Property handle(bool &&prop);
static Property handle(float &&prop);
static Property handle(double &&prop);
static Property handle(int32_t &&prop);
static Property handle(int64_t &&prop);
static Property handle(std::string &&value);
static Property handle(ArrayStore<bool> &&);
static Property handle(ArrayStore<int32_t> &&);
static Property handle(ArrayStore<int64_t> &&);
static Property handle(ArrayStore<float> &&);
static Property handle(ArrayStore<double> &&);
static Property handle(ArrayStore<std::string> &&);
};
using properties_t = std::vector<Property>;

View File

@ -1,246 +0,0 @@
#pragma once
#include <memory>
#include "data_structures/concurrent/concurrent_map.hpp"
#include "storage/indexes/index_holder.hpp"
#include "storage/model/properties/flags.hpp"
#include "storage/type_group_edge.hpp"
#include "storage/type_group_vertex.hpp"
#include "utils/option.hpp"
#include "utils/total_ordering.hpp"
#include "utils/underlying_cast.hpp"
// #include "storage/indexes/index_base.hpp"
// Family of properties with the same name but different types.
// Ordered on name.
// TG - group of types Edge/Vertex
template <class TG>
class PropertyFamily : public TotalOrdering<PropertyFamily<TG>>
{
friend class PropertyType;
friend class PropertyFamilyKey;
friend class PropertyTypeKey;
public:
// Type of property defined with his family and his type.
// Ordered on PropertyFamily and Type.
class PropertyType : public TotalOrdering<PropertyType>
{
friend class PropertyFamilyKey;
friend class PropertyTypeKey;
friend class PropertyFamily;
public:
// Ordered on POINTERS to PropertyFamily
class PropertyFamilyKey
: public TotalOrdering<PropertyFamilyKey>,
public TotalOrdering<PropertyFamilyKey, PropertyFamily>,
public TotalOrdering<PropertyFamily, PropertyFamilyKey>
{
friend class PropertyType;
friend class PropertyTypeKey;
PropertyFamilyKey(const PropertyType &type) : type(&type) {}
public:
friend bool operator==(const PropertyFamilyKey &lhs,
const PropertyFamilyKey &rhs)
{
return &(lhs.type->family) == &(rhs.type->family);
}
friend bool operator<(const PropertyFamilyKey &lhs,
const PropertyFamilyKey &rhs)
{
return &(lhs.type->family) < &(rhs.type->family);
}
friend bool operator==(const PropertyFamilyKey &lhs,
const PropertyFamily &rhs)
{
return &(lhs.type->family) == &(rhs);
}
friend bool operator<(const PropertyFamilyKey &lhs,
const PropertyFamily &rhs)
{
return &(lhs.type->family) < &(rhs);
}
friend bool operator==(const PropertyFamily &lhs,
const PropertyFamilyKey &rhs)
{
return &(lhs) == &(rhs.type->family);
}
friend bool operator<(const PropertyFamily &lhs,
const PropertyFamilyKey &rhs)
{
return &(lhs) < &(rhs.type->family);
}
Type get_type() const { return type->type; }
Type prop_type() const { return type->type; }
std::string const &family_name() const
{
return type->family.name();
}
const PropertyFamily &get_family() const { return type->family; }
const std::string to_str() const
{
return std::string(family_name());
}
private:
const PropertyType *type;
};
// Ordered on POINTERS to PropertyType.
// When compared with PropertyFamilyKey behaves as PropertyFamilyKey.
template <class T>
class PropertyTypeKey
: public TotalOrdering<PropertyTypeKey<T>>,
public TotalOrdering<PropertyFamilyKey, PropertyTypeKey<T>>,
public TotalOrdering<PropertyTypeKey<T>, PropertyFamilyKey>
{
friend class PropertyType;
PropertyTypeKey(const PropertyType &type) : type(type) {}
public:
PropertyFamilyKey family_key() const
{
return PropertyFamilyKey(type);
}
Type const &prop_type() const { return type.type; }
friend bool operator==(const PropertyTypeKey &lhs,
const PropertyTypeKey &rhs)
{
return &(lhs.type) == &(rhs.type);
}
friend bool operator<(const PropertyTypeKey &lhs,
const PropertyTypeKey &rhs)
{
return &(lhs.type) < &(rhs.type);
}
friend bool operator==(const PropertyFamilyKey &lhs,
const PropertyTypeKey &rhs)
{
return lhs == rhs.family_key();
}
friend bool operator<(const PropertyFamilyKey &lhs,
const PropertyTypeKey &rhs)
{
return lhs < rhs.family_key();
}
friend bool operator==(const PropertyTypeKey &lhs,
const PropertyFamilyKey &rhs)
{
return lhs.family_key() == rhs;
}
friend bool operator<(const PropertyTypeKey &lhs,
const PropertyFamilyKey &rhs)
{
return lhs.family_key() < rhs;
}
private:
const PropertyType &type;
};
private:
PropertyType(PropertyFamily &family, Type type);
PropertyType(PropertyFamily &other) = delete;
PropertyType(PropertyFamily &&other) = delete;
public:
template <class T>
bool is() const
{
return type == T::type;
}
bool is(Type &t) const;
// Returns key ordered on POINTERS to PropertyType.
// When compared with PropertyFamilyKey behaves as PropertyFamilyKey.
template <class T>
PropertyTypeKey<T> type_key()
{
assert(this->is<T>());
return PropertyTypeKey<T>(*this);
}
// Returns key ordered on POINTERS to PropertyFamily
PropertyFamilyKey family_key();
friend bool operator<(const PropertyType &lhs, const PropertyType &rhs)
{
return lhs.family < rhs.family ||
(lhs.family == rhs.family && lhs.type < rhs.type);
}
friend bool operator==(const PropertyType &lhs, const PropertyType &rhs)
{
return lhs.family == rhs.family && lhs.type == rhs.type;
}
private:
const PropertyFamily &family;
const Type type;
};
PropertyFamily(std::string const &name_v);
PropertyFamily(std::string &&name_v);
PropertyFamily(PropertyFamily &other) = delete;
PropertyFamily(PropertyFamily &&other) = delete;
std::string const &name() const;
// Returns type if it exists otherwise creates it.
PropertyType &get(Type type);
// Return pointer for NULL type. Extremly fast.
PropertyType &getNull() const { return *null_type; }
friend bool operator<(const PropertyFamily &lhs, const PropertyFamily &rhs);
friend bool operator==(const PropertyFamily &lhs,
const PropertyFamily &rhs);
// Place for index of TG::elements which have property from this family.
IndexHolder<TG, std::nullptr_t> index;
private:
const std::string name_v;
// This is exclusivly for getNull method.
PropertyType *null_type{nullptr};
// TODO: Because types wont be removed this could be done with more efficent
// data structure.
ConcurrentMap<Type, std::unique_ptr<PropertyType>> types;
};
using VertexPropertyKey =
PropertyFamily<TypeGroupVertex>::PropertyType::PropertyFamilyKey;
using EdgePropertyKey =
PropertyFamily<TypeGroupEdge>::PropertyType::PropertyFamilyKey;
template <class T>
using VertexPropertyType =
PropertyFamily<TypeGroupVertex>::PropertyType::PropertyTypeKey<T>;
template <class T>
using EdgePropertyType =
PropertyFamily<TypeGroupEdge>::PropertyType::PropertyTypeKey<T>;

View File

@ -1,291 +0,0 @@
#pragma once
#include "storage/model/properties/all.hpp"
// Generates constructor by value which accepts type_name object and stores them
// in union_name field.
#define GENERATE_CONSTRUCTOR_FOR_DATA(type_name, union_name) \
PropertyHolder(type_name &&data, T k) \
: union_name(std::move(data)), key(k) \
{ \
assert(type_name::type == key.get_type()); \
}
// Genrates case claus for Flags::type_name to construct type_name object in
// place of union_name field by a move from other
#define GENERATE_CASE_CLAUSE_FOR_CONSTRUCTOR_MOVE(type_name, union_name) \
case Flags::type_name: { \
new (&(this->union_name)) type_name(std::move(other.union_name)); \
break; \
}
// Genrates case claus for Flags::type_name to construct type_name object in
// place of union_name field by a copy from other
#define GENERATE_CASE_CLAUSE_FOR_CONSTRUCTOR_COPY(type_name, union_name) \
case Flags::type_name: { \
new (&(this->union_name)) type_name(other.union_name); \
break; \
}
// Genrates case claus for Flags::type_name to destruct type_name object in
// place of union_name field
#define GENERATE_CASE_CLAUSE_FOR_DESTRUCTOR(type_name, union_name) \
case Flags::type_name: { \
this->union_name.~type_name(); \
break; \
}
// Genrates case claus for Flags::type_name to handle type_name object from
// field of union_name
#define GENERATE_CASE_CLAUSE_FOR_HANDLER(type_name, union_name) \
case Flags::type_name: { \
h.handle(this->union_name); \
break; \
}
// Genrates case claus for Flags::type_name to handle primitives of type_name
// object from field of union_name
#define GENERATE_CASE_CLAUSE_FOR_HANDLER_PRIMITIVE(type_name, union_name) \
case Flags::type_name: { \
h.handle(this->union_name.value()); \
break; \
}
// Genrates case claus for Flags::type_name to print type_name object from
// field of union_name
#define GENERATE_CASE_CLAUSE_FOR_PRINT(type_name, union_name) \
case Flags::type_name: { \
return this->union_name.print(stream); \
}
// Genrates case claus for Flags::type_name to comapre type_name object from
// field of union_name with same named and field from other holder.
#define GENERATE_CASE_CLAUSE_FOR_COMPARISON(type_name, union_name) \
case Flags::type_name: { \
return this->union_name == other.union_name; \
}
// Generates field in a union with a given type and name
#define GENERATE_UNION_FIELD(type_name, union_name) type_name union_name
// Generates signatures define_generator(type_name, union_name );
// for every pair type,property
#define GENERATE_FOR_ALL_PROPERTIES(define_generator) \
define_generator(Null, null_v); \
define_generator(Bool, bool_v); \
define_generator(Int32, int32_v); \
define_generator(Int64, int64_v); \
define_generator(Float, float_V); \
define_generator(Double, double_v); \
define_generator(String, string_v); \
define_generator(ArrayBool, array_bool); \
define_generator(ArrayInt32, array_int32); \
define_generator(ArrayInt64, array_int64); \
define_generator(ArrayFloat, array_float); \
define_generator(ArrayDouble, array_double); \
define_generator(ArrayString, array_string);
// Holds property and has some means of determining its type.
// T must have method get_type() const which returns Type.
template <class T>
class PropertyHolder
{
// He is his own best friend.
template <class O>
friend class PropertyHolder;
public:
PropertyHolder() = delete;
GENERATE_FOR_ALL_PROPERTIES(GENERATE_CONSTRUCTOR_FOR_DATA);
PropertyHolder(PropertyHolder const &other) : key(other.key)
{
switch (other.key.get_type().flags()) {
GENERATE_FOR_ALL_PROPERTIES(
GENERATE_CASE_CLAUSE_FOR_CONSTRUCTOR_COPY);
default:
assert(false);
}
assert(key.get_type().flags() == Flags::Int64 || this->int64_v != 0);
}
PropertyHolder(PropertyHolder &&other) : key(other.key)
{
switch (other.key.get_type().flags()) {
GENERATE_FOR_ALL_PROPERTIES(
GENERATE_CASE_CLAUSE_FOR_CONSTRUCTOR_MOVE);
default:
assert(false);
}
}
template <class O>
PropertyHolder(PropertyHolder<O> &&other, T const &key) : key(key)
{
assert(other.key.get_type() == key.get_type());
switch (key.get_type().flags()) {
GENERATE_FOR_ALL_PROPERTIES(
GENERATE_CASE_CLAUSE_FOR_CONSTRUCTOR_MOVE);
default:
assert(false);
}
assert(key.get_type().flags() == Flags::Int64 || this->int64_v != 0);
}
~PropertyHolder()
{
switch (key.get_type().flags()) {
GENERATE_FOR_ALL_PROPERTIES(GENERATE_CASE_CLAUSE_FOR_DESTRUCTOR);
default:
assert(false);
}
}
PropertyHolder &operator=(PropertyHolder const &other)
{
this->~PropertyHolder();
new (this) PropertyHolder(other);
assert(key.get_type().flags() == Flags::Int64 || this->int64_v != 0);
return *this;
}
PropertyHolder &operator=(PropertyHolder &&other)
{
this->~PropertyHolder();
new (this) PropertyHolder(std::move(other));
assert(key.get_type().flags() == Flags::Int64 || this->int64_v != 0);
return *this;
}
// Calls appropiate handler with a database property.
// (String,Int64,ArrayBool,...)
template <class Handler>
void accept(Handler &h) const
{
switch (key.get_type().flags()) {
GENERATE_FOR_ALL_PROPERTIES(GENERATE_CASE_CLAUSE_FOR_HANDLER);
default:
assert(false);
}
}
// Calls appropiate handler with a primitive.(std::string,bool,int64_t,...)
template <class Handler>
void accept_primitive(Handler &h) const
{
switch (key.get_type().flags()) {
GENERATE_FOR_ALL_PROPERTIES(
GENERATE_CASE_CLAUSE_FOR_HANDLER_PRIMITIVE);
default:
assert(false);
}
}
std::ostream &print(std::ostream &stream) const
{
switch (key.get_type().flags()) {
GENERATE_FOR_ALL_PROPERTIES(GENERATE_CASE_CLAUSE_FOR_PRINT);
default:
// TODO: custom error
throw std::runtime_error("PropertyHolder::print -> unknown flag");
}
}
friend std::ostream &operator<<(std::ostream &stream,
const PropertyHolder &prop)
{
return prop.print(stream);
}
bool operator==(const PropertyHolder &other) const
{
if (key == other.key) {
switch (key.get_type().flags()) {
GENERATE_FOR_ALL_PROPERTIES(GENERATE_CASE_CLAUSE_FOR_COMPARISON);
default:
assert(false);
return false;
}
} else {
return false;
}
}
template <class O>
bool operator==(const PropertyHolder<O> &other) const
{
if (key.get_type() == other.key.get_type()) {
switch (key.get_type().flags()) {
GENERATE_FOR_ALL_PROPERTIES(GENERATE_CASE_CLAUSE_FOR_COMPARISON);
default:
assert(false);
return false;
}
} else {
return false;
}
}
template <class O, Flags f = O::type.flags()>
bool operator==(const O &other) const
{
if (key.get_type() == O::type) {
return other == as<O>();
} else {
return false;
}
}
bool operator!=(const PropertyHolder &other) const
{
return !(*this == other);
}
// True if NULL
bool is_empty() const { return is<Null>(); }
// True if contains T property
template <class D>
bool is() const
{
return D::type == key.get_type();
}
// T MUST be type with which this holder was constructed.
template <class D>
D &as()
{
assert(is<D>());
return *reinterpret_cast<D *>(&array_string);
}
// T MUST be type with which this PropertyData was constructed.
// Specialized after this class
template <class D>
D const &as() const
{
assert(is<D>());
return *reinterpret_cast<D const *>(&array_string);
}
// Knows type
const T key;
private:
// Stored data.
union
{
GENERATE_FOR_ALL_PROPERTIES(GENERATE_UNION_FIELD);
};
};
#undef GENERATE_CONSTRUCTOR_FOR_DATA
#undef GENERATE_CASE_CLAUSE_FOR_CONSTRUCTOR_MOVE
#undef GENERATE_CASE_CLAUSE_FOR_CONSTRUCTOR_COPY
#undef GENERATE_CASE_CLAUSE_FOR_DESTRUCTOR
#undef GENERATE_CASE_CLAUSE_FOR_HANDLER
#undef GENERATE_CASE_CLAUSE_FOR_PRINT
#undef GENERATE_CASE_CLAUSE_FOR_COMPARISON
#undef GENERATE_UNION_FIELD
#undef GENERATE_FOR_ALL_PROPERTIES

View File

@ -1,28 +0,0 @@
#pragma once
#include "storage/model/properties/flags.hpp"
#include "storage/model/properties/property_family.hpp"
#include "storage/model/properties/property_holder.hpp"
template <class TG>
using property_key =
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey;
// Property Class designated for creation inside the database. Meant for
// storage.
template <class TG>
class StoredProperty : public PropertyHolder<property_key<TG>>
{
// null property family
const static class PropertyFamily<TG> null_family;
public:
// NOTE: Needed for properties to return reference on stored property when
// they don't cointain searched property.
const static class StoredProperty<TG> null;
using PropertyHolder<property_key<TG>>::PropertyHolder;
template <class P>
StoredProperty(PropertyFamily<TG> &family, P &&property);
};

View File

@ -1,37 +0,0 @@
#pragma once
#include <memory>
#include <ostream>
#include <string>
#include "storage/model/properties/flags.hpp"
class String
{
public:
const static Type type;
String(std::string const &d) : data(std::make_shared<std::string>(d)) {}
String(std::string &&d) : data(std::make_shared<std::string>(std::move(d)))
{
}
std::string &value() { return *data.get(); }
std::string const &value() const { return *data.get(); }
std::ostream &print(std::ostream &stream) const;
friend std::ostream &operator<<(std::ostream &stream, const String &prop);
bool operator==(const String &other) const;
bool operator==(const std::string &other) const;
// NOTE: OTHER METHODS WILL AUTOMATICALLY USE THIS IN CERTAIN SITUATIONS
// TO MOVE STD::STRING OUT OF SHARED_PTR WHICH IS BAD.
// operator const std::string &() const;
private:
std::shared_ptr<std::string> data;
};

View File

@ -1,25 +0,0 @@
#pragma once
template <class Derived>
struct MathOperations
{
friend Derived operator+(const Derived& lhs, const Derived& rhs)
{
return Derived(lhs.value + rhs.value);
}
friend Derived operator-(const Derived& lhs, const Derived& rhs)
{
return Derived(lhs.value - rhs.value);
}
friend Derived operator*(const Derived& lhs, const Derived& rhs)
{
return Derived(lhs.value * rhs.value);
}
friend Derived operator/(const Derived& lhs, const Derived& rhs)
{
return Derived(lhs.value / rhs.value);
}
};

View File

@ -1,10 +0,0 @@
#pragma once
template <class Derived>
struct Modulo
{
friend Derived operator%(const Derived& lhs, const Derived& rhs)
{
return Derived(lhs.value % rhs.value);
}
};

View File

@ -1,12 +0,0 @@
#pragma once
#include "utils/crtp.hpp"
template <class Derived>
struct UnaryNegation : public Crtp<Derived>
{
Derived operator-() const
{
return Derived(-this->derived().value);
}
};

View File

@ -1,125 +1,108 @@
#include "database/db.hpp"
#include "database/db_accessor.hpp"
#include "utils/iterator/iterator.hpp"
DbAccessor::DbAccessor(Db &db)
: db_transaction(std::move(DbTransaction(db, db.tx_engine.begin())))
{
: db_transaction(std::move(DbTransaction(db, db.tx_engine.begin()))) {
}
DbAccessor::DbAccessor(Db &db, tx::Transaction &t)
: db_transaction(std::move(DbTransaction(db, t)))
{
: db_transaction(std::move(DbTransaction(db, t))) {
}
// VERTEX METHODS
Option<const VertexAccessor> DbAccessor::vertex_find(const Id &id)
{
return this->db_transaction.db.graph.vertices.find(db_transaction, id);
Option<const VertexAccessor> DbAccessor::vertex_find(const Id &id) {
return this->db_transaction.db.graph.vertices.find(db_transaction, id);
}
VertexAccessor DbAccessor::vertex_insert()
{
return this->db_transaction.db.graph.vertices.insert(db_transaction);
VertexAccessor DbAccessor::vertex_insert() {
return this->db_transaction.db.graph.vertices.insert(db_transaction);
}
// EDGE METHODS
Option<const EdgeAccessor> DbAccessor::edge_find(const Id &id)
{
return db_transaction.db.graph.edges.find(db_transaction, id);
Option<const EdgeAccessor> DbAccessor::edge_find(const Id &id) {
return db_transaction.db.graph.edges.find(db_transaction, id);
}
EdgeAccessor DbAccessor::edge_insert(VertexAccessor &from, VertexAccessor &to)
{
auto edge_accessor = db_transaction.db.graph.edges.insert(
db_transaction, from.vlist, to.vlist);
EdgeAccessor DbAccessor::edge_insert(VertexAccessor &from, VertexAccessor &to) {
auto edge_accessor = db_transaction.db.graph.edges.insert(
db_transaction, from.vlist, to.vlist);
// Connect edge with from,to vertices.
from->data.out.add(edge_accessor.vlist);
to->data.in.add(edge_accessor.vlist);
// Connect edge with from,to vertices.
from->data.out.add(edge_accessor.vlist);
to->data.in.add(edge_accessor.vlist);
return edge_accessor;
return edge_accessor;
}
EdgeAccessor DbAccessor::edge_insert(VertexAccessor const &from,
VertexAccessor const &to)
{
auto edge_accessor = db_transaction.db.graph.edges.insert(
db_transaction, from.vlist, to.vlist);
VertexAccessor const &to) {
auto edge_accessor = db_transaction.db.graph.edges.insert(
db_transaction, from.vlist, to.vlist);
// Connect edge with updated from,to vertices.
from.update()->data.out.add(edge_accessor.vlist);
to.update()->data.in.add(edge_accessor.vlist);
// Connect edge with updated from,to vertices.
from.update()->data.out.add(edge_accessor.vlist);
to.update()->data.in.add(edge_accessor.vlist);
return edge_accessor;
return edge_accessor;
}
// LABEL METHODS
const Label &DbAccessor::label_find_or_create(const char *name)
{
return db_transaction.db.graph.label_store.find_or_create(name);
const Label &DbAccessor::label_find_or_create(const char *name) {
return db_transaction.db.graph.label_store.find_or_create(name);
}
bool DbAccessor::label_contains(const char *name)
{
return db_transaction.db.graph.label_store.contains(name);
bool DbAccessor::label_contains(const char *name) {
return db_transaction.db.graph.label_store.contains(name);
}
// TYPE METHODS
const EdgeType &DbAccessor::type_find_or_create(const char *name)
{
return db_transaction.db.graph.edge_type_store.find_or_create(name);
const EdgeType &DbAccessor::type_find_or_create(const char *name) {
return db_transaction.db.graph.edge_type_store.find_or_create(name);
}
bool DbAccessor::type_contains(const char *name)
{
return db_transaction.db.graph.edge_type_store.contains(name);
bool DbAccessor::type_contains(const char *name) {
return db_transaction.db.graph.edge_type_store.contains(name);
}
// PROPERTY METHODS
VertexPropertyFamily &
DbAccessor::vertex_property_family_get(const std::string &name)
{
return db_transaction.db.graph.vertices.property_family_find_or_create(
name);
DbAccessor::vertex_property_family_get(const std::string &name) {
return db_transaction.db.graph.vertices.property_family_find_or_create(
name);
}
EdgePropertyFamily &
DbAccessor::edge_property_family_get(const std::string &name)
{
return db_transaction.db.graph.edges.property_family_find_or_create(name);
DbAccessor::edge_property_family_get(const std::string &name) {
return db_transaction.db.graph.edges.property_family_find_or_create(name);
}
// PROPERTY HELPER METHODS
VertexPropertyFamily::PropertyType::PropertyFamilyKey
DbAccessor::vertex_property_key(const std::string &name, Type type)
{
return vertex_property_family_get(name).get(type).family_key();
DbAccessor::vertex_property_key(const std::string &name, Type type) {
return vertex_property_family_get(name).get(type).family_key();
}
EdgePropertyFamily::PropertyType::PropertyFamilyKey
DbAccessor::edge_property_key(const std::string &name, Type type)
{
return edge_property_family_get(name).get(type).family_key();
DbAccessor::edge_property_key(const std::string &name, Type type) {
return edge_property_family_get(name).get(type).family_key();
}
bool DbAccessor::update_indexes()
{
return db_transaction.update_indexes();
bool DbAccessor::update_indexes() {
return db_transaction.update_indexes();
}
// TRANSACTION METHODS
bool DbAccessor::commit()
{
if (db_transaction.update_indexes()) {
db_transaction.trans.commit();
return true;
} else {
// Index update wasn't successfull so whe are aborting transaction.
db_transaction.trans.abort();
return false;
}
bool DbAccessor::commit() {
if (db_transaction.update_indexes()) {
db_transaction.trans.commit();
return true;
} else {
// Index update wasn't successfull so whe are aborting transaction.
db_transaction.trans.abort();
return false;
}
}
void DbAccessor::abort() { db_transaction.trans.abort(); }

View File

@ -1,16 +0,0 @@
#include "storage/model/properties/array.hpp"
template <class T, Flags flag_t>
const Type Array<T, flag_t>::type = Type(flag_t);
template class Array<std::string, Flags::ArrayString>;
template class Array<bool, Flags::ArrayBool>;
template class Array<int32_t, Flags::ArrayInt32>;
template class Array<int64_t, Flags::ArrayInt64>;
template class Array<float, Flags::ArrayFloat>;
template class Array<double, Flags::ArrayDouble>;

View File

@ -1,3 +0,0 @@
#include "storage/model/properties/bool.hpp"
const Type Bool::type = Type(Flags::Bool);

View File

@ -1,3 +0,0 @@
#include "storage/model/properties/double.hpp"
const Type Double::type = Type(Flags::Double);

View File

@ -1,3 +0,0 @@
#include "storage/model/properties/float.hpp"
const Type Float::type = Type(Flags::Float);

View File

@ -1,3 +0,0 @@
#include "storage/model/properties/int32.hpp"
const Type Int32::type = Type(Flags::Int32);

View File

@ -1,3 +0,0 @@
#include "storage/model/properties/int64.hpp"
const Type Int64::type = Type(Flags::Int64);

View File

@ -1,17 +0,0 @@
#include "storage/model/properties/null.hpp"
const Type Null::type = Type(Flags::Null);
bool Null::operator==(const Null &) const { return true; }
Null::operator bool() { return false; }
std::ostream &operator<<(std::ostream &stream, const Null &)
{
return stream << "NULL";
}
std::ostream &Null::print(std::ostream &stream) const
{
return operator<<(stream, *this);
}

View File

@ -1,86 +0,0 @@
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/null.hpp"
#include "storage/model/properties/property_family.hpp"
#include "utils/option.hpp"
#include "storage/type_group_edge.hpp"
#include "storage/type_group_vertex.hpp"
template <class TG>
const bool Properties<TG>::contains(property_key &key) const
{
for (auto &prop : props)
{
if (prop.key == key)
{
return true;
}
}
return false;
}
template <class TG>
const StoredProperty<TG> &Properties<TG>::at(PropertyFamily<TG> &fam) const
{
// It doesn't matter whit which type
// compare is done, thats why getNull
// method is here to give fast access
// to such key.
auto f_key = fam.getNull().family_key();
return at(f_key);
}
template <class TG>
const StoredProperty<TG> &Properties<TG>::at(property_key &key) const
{
for (auto &prop : props) {
if (prop.key == key) {
return prop;
}
}
return StoredProperty<TG>::null;
}
template <class TG>
void Properties<TG>::set(StoredProperty<TG> &&value)
{
for (auto &prop : props) {
if (prop.key == value.key) {
// It is necessary to change key because the types from before and
// now could be different.
StoredProperty<TG> &sp = const_cast<StoredProperty<TG> &>(prop);
sp = std::move(value);
return;
}
}
props.push_back(std::move(value));
}
template <class TG>
void Properties<TG>::clear(property_key &key)
{
auto end = props.end();
for (auto it = props.begin(); it != end; it++) {
if (it->key == key) {
props.erase(it);
return;
}
}
}
template <class TG>
void Properties<TG>::clear(PropertyFamily<TG> &fam)
{
// It doesn't matter whit which type
// find is called, thats why getNull
// method is here to give fast access
// to such key.
auto f_key = fam.getNull().family_key();
clear(f_key);
}
template class Properties<TypeGroupEdge>;
template class Properties<TypeGroupVertex>;

View File

@ -1,68 +0,0 @@
#include "storage/model/properties/property.hpp"
#include "storage/model/properties/all.hpp"
Property Property::handle(Void &&v)
{
return Property(Null(), Type(Flags::Null));
}
Property Property::handle(bool &&prop)
{
return Property(Bool(prop), Type(Flags::Bool));
}
Property Property::handle(float &&prop)
{
return Property(Float(prop), Type(Flags::Float));
}
Property Property::handle(double &&prop)
{
return Property(Double(prop), Type(Flags::Double));
}
Property Property::handle(int32_t &&prop)
{
return Property(Int32(prop), Type(Flags::Int32));
}
Property Property::handle(int64_t &&prop)
{
return Property(Int64(prop), Type(Flags::Int64));
}
Property Property::handle(std::string &&value)
{
return Property(String(std::move(value)), Type(Flags::String));
}
Property Property::handle(ArrayStore<bool> &&a)
{
return Property(ArrayBool(std::move(a)), Type(Flags::ArrayBool));
}
Property Property::handle(ArrayStore<int32_t> &&a)
{
return Property(ArrayInt32(std::move(a)), Type(Flags::ArrayInt32));
}
Property Property::handle(ArrayStore<int64_t> &&a)
{
return Property(ArrayInt64(std::move(a)), Type(Flags::ArrayInt64));
}
Property Property::handle(ArrayStore<float> &&a)
{
return Property(ArrayFloat(std::move(a)), Type(Flags::ArrayFloat));
}
Property Property::handle(ArrayStore<double> &&a)
{
return Property(ArrayDouble(std::move(a)), Type(Flags::ArrayDouble));
}
Property Property::handle(ArrayStore<std::string> &&a)
{
return Property(ArrayString(std::move(a)), Type(Flags::ArrayString));
}

View File

@ -1,62 +0,0 @@
#include "storage/model/properties/property_family.hpp"
#include "storage/type_group_edge.hpp"
#include "storage/type_group_vertex.hpp"
template <class T>
PropertyFamily<T>::PropertyFamily(std::string const &name_v)
: name_v(std::forward<const std::string>(name_v))
{
null_type = &get(Flags::Null);
}
template <class T>
PropertyFamily<T>::PropertyFamily(std::string &&name_v)
: name_v(std::move(name_v))
{
null_type = &get(Flags::Null);
}
template <class T>
std::string const &PropertyFamily<T>::name() const
{
return name_v;
}
// Returns type if it exists otherwise creates it.
template <class T>
typename PropertyFamily<T>::PropertyType &PropertyFamily<T>::get(Type type)
{
auto acc = types.access();
auto it = acc.find(type);
if (it == acc.end()) {
auto value =
std::unique_ptr<PropertyType>(new PropertyType(*this, type));
auto res = acc.insert(type, std::move(value));
it = res.first;
}
return *(it->second);
}
template <class T>
PropertyFamily<T>::PropertyType::PropertyType(PropertyFamily &family, Type type)
: family(family), type(std::move(type))
{
}
template <class T>
bool PropertyFamily<T>::PropertyType::is(Type &t) const
{
return type == t;
}
// Returns key ordered on POINTERS to PropertyFamily
template <class T>
typename PropertyFamily<T>::PropertyType::PropertyFamilyKey
PropertyFamily<T>::PropertyType::family_key()
{
return PropertyFamilyKey(*this);
}
template class PropertyFamily<TypeGroupEdge>;
template class PropertyFamily<TypeGroupVertex>;

View File

@ -1,26 +0,0 @@
#include "storage/model/properties/property.hpp"
#include "storage/model/properties/stored_property.hpp"
template <class TG>
const PropertyFamily<TG> StoredProperty<TG>::null_family("NULL");
template <class TG>
const StoredProperty<TG> StoredProperty<TG>::null = {
Null(), StoredProperty<TG>::null_family.getNull().family_key()};
template <class TG>
template <class P>
StoredProperty<TG>::StoredProperty(PropertyFamily<TG> &family, P &&property)
: StoredProperty(std::move(property),
family.get(property.key.get_type()).family_key())
{
}
template class StoredProperty<TypeGroupVertex>;
template class StoredProperty<TypeGroupEdge>;
template StoredProperty<TypeGroupVertex>::StoredProperty(
PropertyFamily<TypeGroupVertex> &family, Property &&property);
template StoredProperty<TypeGroupEdge>::StoredProperty(
PropertyFamily<TypeGroupEdge> &family, Property &&property);

View File

@ -1,23 +0,0 @@
#include "storage/model/properties/string.hpp"
const Type String::type = Type(Flags::String);
bool String::operator==(const String &other) const
{
return value() == other.value();
}
bool String::operator==(const std::string &other) const
{
return value() == other;
}
std::ostream &operator<<(std::ostream &stream, const String &prop)
{
return stream << prop.value();
}
std::ostream &String::print(std::ostream &stream) const
{
return operator<<(stream, *this);
}