storage and database major refactor in progress, also switching from properties to typed-value system. a lot of overdesigned functionalities cut down, new implementations just started. VERY UNSTABLE STATE

This commit is contained in:
Florijan Stamenkovic 2017-02-04 09:01:15 +01:00
parent 029a3ff09b
commit b374ae1dbb
99 changed files with 491 additions and 3332 deletions
CMakeLists.txt
cmake
include
poc
src
tests/integration
_hardcoded_query
queries.cpp

View File

@ -303,33 +303,8 @@ set(memgraph_src_files
${src_dir}/snapshot/snapshot_decoder.cpp
${src_dir}/storage/vertices.cpp
${src_dir}/storage/edges.cpp
${src_dir}/storage/label/label.cpp
${src_dir}/storage/label/label_collection.cpp
${src_dir}/storage/label/label_store.cpp
${src_dir}/storage/label/labels_writer.cpp
${src_dir}/storage/edge_type/edge_type.cpp
${src_dir}/storage/edge_type/edge_type_store.cpp
${src_dir}/storage/model/typed_value.cpp
${src_dir}/storage/model/typed_value_store.cpp
${src_dir}/storage/model/properties/null.cpp
${src_dir}/storage/model/properties/bool.cpp
${src_dir}/storage/model/properties/int32.cpp
${src_dir}/storage/model/properties/int64.cpp
${src_dir}/storage/model/properties/float.cpp
${src_dir}/storage/model/properties/double.cpp
${src_dir}/storage/model/properties/string.cpp
${src_dir}/storage/model/properties/array.cpp
${src_dir}/storage/model/properties/property.cpp
${src_dir}/storage/model/properties/properties.cpp
${src_dir}/storage/model/properties/stored_property.cpp
${src_dir}/storage/model/properties/property_family.cpp
${src_dir}/storage/indexes/indexes.cpp
${src_dir}/storage/indexes/index_base.cpp
${src_dir}/storage/indexes/index_record.cpp
${src_dir}/storage/indexes/index_update.cpp
${src_dir}/storage/indexes/index_holder.cpp
${src_dir}/storage/indexes/impl/unique_ordered_index.cpp
${src_dir}/storage/indexes/impl/nonunique_unordered_index.cpp
${src_dir}/storage/typed_value.cpp
${src_dir}/storage/typed_value_store.cpp
${src_dir}/storage/locking/record_lock.cpp
${src_dir}/storage/garbage/garbage.cpp
${src_dir}/storage/vertex_accessor.cpp

View File

@ -6,29 +6,16 @@ FILE(COPY ${include_dir}/database/db.hpp DESTINATION ${build_include_dir}/databa
FILE(COPY ${include_dir}/database/db_transaction.hpp DESTINATION ${build_include_dir}/database)
FILE(COPY ${include_dir}/database/db_accessor.hpp DESTINATION ${build_include_dir}/database)
FILE(COPY ${include_dir}/storage/common.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/graph.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/edge.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/edge_record.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/vertex_record.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/edge_accessor.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/edges.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/vertices.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/vertex.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/vertex_accessor.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/record_accessor.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/locking/record_lock.hpp DESTINATION ${build_include_dir}/storage/locking)
FILE(COPY ${include_dir}/storage/locking/lock_status.hpp DESTINATION ${build_include_dir}/storage/locking)
FILE(COPY ${include_dir}/storage/edge_type/edge_type_store.hpp DESTINATION ${build_include_dir}/storage/edge_type)
FILE(COPY ${include_dir}/storage/edge_type/edge_type.hpp DESTINATION ${build_include_dir}/storage/edge_type)
FILE(COPY ${include_dir}/storage/label/label_store.hpp DESTINATION ${build_include_dir}/storage/label)
FILE(COPY ${include_dir}/storage/label/labels_writer.hpp DESTINATION ${build_include_dir}/storage/label)
FILE(COPY ${include_dir}/storage/model/edge_map.hpp DESTINATION ${build_include_dir}/storage/model)
FILE(COPY ${include_dir}/storage/model/properties/flags.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/stored_property.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/property_holder.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/type_group_edge.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/type_group_vertex.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/edge_x_vertex.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/query/util.hpp DESTINATION ${build_include_dir}/query)
@ -71,42 +58,9 @@ FILE(COPY ${include_dir}/transactions/engine.hpp DESTINATION ${build_include_dir
FILE(COPY ${include_dir}/transactions/transaction_store.hpp DESTINATION ${build_include_dir}/transactions)
FILE(COPY ${include_dir}/transactions/transaction_read.hpp DESTINATION ${build_include_dir}/transactions)
FILE(COPY ${include_dir}/storage/model/properties/properties.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/property.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/json_writer.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/all.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/bool.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/null.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/float.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/double.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/int32.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/int64.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/string.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/array.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/floating.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/number.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/integral.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/property_family.hpp DESTINATION ${build_include_dir}/storage/model/properties)
FILE(COPY ${include_dir}/storage/model/properties/utils/math_operations.hpp DESTINATION ${build_include_dir}/storage/model/properties/utils)
FILE(COPY ${include_dir}/storage/model/properties/utils/unary_negation.hpp DESTINATION ${build_include_dir}/storage/model/properties/utils)
FILE(COPY ${include_dir}/storage/model/properties/utils/modulo.hpp DESTINATION ${build_include_dir}/storage/model/properties/utils)
FILE(COPY ${include_dir}/storage/model/edge_model.hpp DESTINATION ${build_include_dir}/storage/model)
FILE(COPY ${include_dir}/storage/model/property_model.hpp DESTINATION ${build_include_dir}/storage/model)
FILE(COPY ${include_dir}/storage/model/vertex_model.hpp DESTINATION ${build_include_dir}/storage/model)
FILE(COPY ${include_dir}/storage/model/edge_list.hpp DESTINATION ${build_include_dir}/storage/model)
FILE(COPY ${include_dir}/storage/label/label.hpp DESTINATION ${build_include_dir}/storage/label)
FILE(COPY ${include_dir}/storage/label/label_collection.hpp DESTINATION ${build_include_dir}/storage/label)
FILE(COPY ${include_dir}/storage/label/label_store.hpp DESTINATION ${build_include_dir}/storage/label)
FILE(COPY ${include_dir}/storage/indexes/index_record.hpp DESTINATION ${build_include_dir}/storage/indexes)
FILE(COPY ${include_dir}/storage/indexes/index_base.hpp DESTINATION ${build_include_dir}/storage/indexes)
FILE(COPY ${include_dir}/storage/indexes/impl/nonunique_unordered_index.hpp DESTINATION ${build_include_dir}/storage/indexes/impl)
FILE(COPY ${include_dir}/storage/indexes/index_holder.hpp DESTINATION ${build_include_dir}/storage/indexes)
FILE(COPY ${include_dir}/storage/indexes/index_definition.hpp DESTINATION ${build_include_dir}/storage/indexes)
FILE(COPY ${include_dir}/storage/indexes/index_update.hpp DESTINATION ${build_include_dir}/storage/indexes)
FILE(COPY ${include_dir}/storage/typed_value.hpp DESTINATION ${build_include_dir}/storage/model)
FILE(COPY ${include_dir}/storage/typed_value_store.hpp DESTINATION ${build_include_dir}/storage/model)
FILE(COPY ${include_dir}/storage/typed_value_utils.hpp DESTINATION ${build_include_dir}/storage/model)
FILE(COPY ${include_dir}/storage/garbage/delete_sensitive.hpp DESTINATION ${build_include_dir}/storage/garbage)
FILE(COPY ${include_dir}/storage/garbage/garbage.hpp DESTINATION ${build_include_dir}/storage/garbage)

View File

@ -5,73 +5,65 @@
// Multi thread safe set based on skiplist.
// T - type of data.
template <class T>
class ConcurrentSet
{
typedef SkipList<T> list;
typedef typename SkipList<T>::Iterator list_it;
typedef typename SkipList<T>::ConstIterator list_it_con;
template<class T>
class ConcurrentSet {
typedef SkipList<T> list;
typedef typename SkipList<T>::Iterator list_it;
typedef typename SkipList<T>::ConstIterator list_it_con;
public:
ConcurrentSet() {}
ConcurrentSet() {}
class Accessor : public AccessorBase<T>
{
friend class ConcurrentSet;
class Accessor : public AccessorBase<T> {
friend class ConcurrentSet;
using AccessorBase<T>::AccessorBase;
using AccessorBase<T>::AccessorBase;
private:
using AccessorBase<T>::accessor;
private:
using AccessorBase<T>::accessor;
public:
std::pair<list_it, bool> insert(const T &item)
{
return accessor.insert(item);
}
public:
std::pair<list_it, bool> insert(const T &item) {
return accessor.insert(item);
}
std::pair<list_it, bool> insert(T &&item)
{
return accessor.insert(std::move(item));
}
std::pair<list_it, bool> insert(T &&item) {
return accessor.insert(std::move(item));
}
list_it_con find(const T &item) const { return accessor.find(item); }
list_it_con find(const T &item) const { return accessor.find(item); }
list_it find(const T &item) { return accessor.find(item); }
list_it find(const T &item) { return accessor.find(item); }
// Returns iterator to item or first larger if it doesn't exist.
template <class K>
list_it_con find_or_larger(const K &item) const
{
return accessor.find_or_larger(item);
}
// Returns iterator to item or first larger if it doesn't exist.
template<class K>
list_it_con find_or_larger(const K &item) const {
return accessor.find_or_larger(item);
}
// Returns iterator to item or first larger if it doesn't exist.
template <class K>
list_it find_or_larger(const K &item)
{
return accessor.find_or_larger(item);
}
// Returns iterator to item or first larger if it doesn't exist.
template<class K>
list_it find_or_larger(const K &item) {
return accessor.find_or_larger(item);
}
// Returns iterator to item or first larger if it doesn't exist.
template <class K>
list_it_con cfind_or_larger(const K &item)
{
return accessor.template find_or_larger<list_it_con, K>(item);
}
// Returns iterator to item or first larger if it doesn't exist.
template<class K>
list_it_con cfind_or_larger(const K &item) {
return accessor.template find_or_larger<list_it_con, K>(item);
}
bool contains(const T &item) const
{
return this->find(item) != this->end();
}
bool contains(const T &item) const {
return this->find(item) != this->end();
}
bool remove(const T &item) { return accessor.remove(item); }
};
bool remove(const T &item) { return accessor.remove(item); }
};
Accessor access() { return Accessor(&skiplist); }
Accessor access() { return Accessor(&skiplist); }
const Accessor access() const { return Accessor(&skiplist); }
const Accessor access() const { return Accessor(&skiplist); }
private:
list skiplist;
list skiplist;
};

View File

@ -0,0 +1,17 @@
//
// Copyright 2017 Memgraph
// Created by Florijan Stamenkovic on 03.02.17.
//
#pragma once
#include "utils/exceptions/basic_exception.hpp"
class CreationException : public BasicException {
public:
using BasicException::BasicException;
};

View File

@ -1,93 +0,0 @@
#pragma once
#include "storage/type_group_edge.hpp"
#include "storage/type_group_vertex.hpp"
#include "snapshot/snapshot_engine.hpp"
#include "storage/garbage/garbage.hpp"
#include "storage/graph.hpp"
#include "transactions/engine.hpp"
class Indexes;
// TODO: Maybe split this in another layer between Db and Dbms. Where the new
// layer would hold SnapshotEngine and his kind of concept objects. Some
// guidelines would be: retain objects which are necessary to implement querys
// in Db, the rest can be moved to the new layer.
/**
* Main class which represents Database concept in code.
*/
class Db {
public:
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);
/**
* 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);
/**
* Database object can't be copied.
*/
Db(const Db &db) = delete;
private:
/** database name */
const std::string name_;
public:
/** transaction engine related to this database */
tx::Engine tx_engine;
/** graph related to this database */
Graph graph;
/** 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};
/**
* 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;
};

View File

@ -1,6 +1,6 @@
#pragma once
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "database/db_transaction.hpp"
#include "utils/border.hpp"
#include "utils/iterator/iterator.hpp"

View File

@ -0,0 +1,112 @@
#pragma once
#include "data_structures/concurrent/skiplist.hpp"
#include "database/db_transaction.hpp"
#include "snapshot/snapshot_engine.hpp"
#include "storage/garbage/garbage.hpp"
#include "transactions/engine.hpp"
#include "mvcc/version_list.hpp"
#include "utils/pass_key.hpp"
// forward declaring Edge and Vertex because they use
// GraphDb::Label etc., and therefore include this header
class Vertex;
class VertexAccessor;
class Edge;
class EdgeAccessor;
// TODO: Maybe split this in another layer between Db and Dbms. Where the new
// layer would hold SnapshotEngine and his kind of concept objects. Some
// guidelines would be: retain objects which are necessary to implement querys
// in Db, the rest can be moved to the new layer.
/**
* Main class which represents Database concept in code.
*/
class GraphDb {
public:
using sptr = std::shared_ptr<GraphDb>;
// definitions for what data types are used for a Label, Property, EdgeType
using Label = uint32_t;
using EdgeType = uint32_t;
using Property = uint32_t;
/**
* 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 GraphDb(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.
*/
GraphDb(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.
*/
GraphDb(const std::string &name, bool import_snapshot = true);
/**
* Database object can't be copied.
*/
GraphDb(const GraphDb &db) = delete;
/**
* Creates a new Vertex and returns an accessor to it.
*
* @param db_trans The transaction that is creating a vertex.
* @return See above.
*/
VertexAccesor insert_vertex(DbTransaction& db_trans);
/**
* Creates a new Edge and returns an accessor to it.
*
* @param db_trans The transaction that is creating an Edge.
* @param from The 'from' vertex.
* @param to The 'to' vertex'
* @param type Edge type.
* @return An accessor to the edge.
*/
EdgeAccessor insert_edge(DbTransaction& db_trans, VertexAccessor& from,
VertexAccessor& to, EdgeType type);
/** transaction engine related to this database */
tx::Engine tx_engine;
/** garbage collector related to this database*/
// TODO bring back garbage collection
// Garbage garbage = {tx_engine};
// TODO bring back shapshot engine
// SnapshotEngine snap_engine = {*this};
// database name
const std::string name_;
private:
// main storage for the graph
SkipList<mvcc::VersionList<Edge>*> edges_;
SkipList<mvcc::VersionList<Vertex>*> vertices_;
// utility stuff
const PassKey<GraphDb> pass_key;
};

View File

@ -0,0 +1,24 @@
//
// Copyright 2017 Memgraph
// Created by Florijan Stamenkovic on 03.02.17.
//
#pragma
#include "graph_db.hpp"
#include "transactions/transaction.hpp"
class GraphDbAccessor {
public:
tx::Transaction transaction_;
private:
};

View File

@ -1,6 +1,6 @@
#pragma once
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "threading/thread.hpp"
class Thread;

View File

@ -2,7 +2,7 @@
#include "config/config.hpp"
#include "data_structures/concurrent/concurrent_map.hpp"
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "dbms/cleaner.hpp"
#include "snapshot/snapshoter.hpp"

View File

@ -17,7 +17,7 @@ namespace mvcc {
using uptr = std::unique_ptr<VersionList<T>>;
using item_t = T;
VersionList(Id id) : id(id) {}
VersionList() = default;
VersionList(const VersionList &) = delete;
@ -179,8 +179,6 @@ namespace mvcc {
record->mark_deleted(t);
}
const Id id;
private:
void lock_and_validate(T *record, tx::Transaction &t) {
assert(record != nullptr);

View File

@ -2,7 +2,7 @@
#include <experimental/filesystem>
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "logging/default.hpp"
#include "query/exception/query_engine.hpp"
#include "query/plan/program.hpp"

View File

@ -1,7 +1,7 @@
#pragma once
#include "communication/communication.hpp"
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "database/db_accessor.hpp"
#include "query/strip/stripped.hpp"

View File

@ -2,7 +2,7 @@
#include <string>
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "query/exception/query_engine.hpp"
#include "query/exception/plan_execution.hpp"
#include "query/plan/program.hpp"

View File

@ -2,7 +2,7 @@
#include <unordered_map>
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "logging/default.hpp"
#include "threading/thread.hpp"

View File

@ -1,6 +0,0 @@
#pragma once
#include "data_structures/concurrent/concurrent_map.hpp"
#include "mvcc/version_list.hpp"
#include "transactions/transaction.hpp"
#include "utils/counters/atomic_counter.hpp"

View File

@ -1,38 +1,17 @@
#pragma once
#include "database/graph_db.hpp"
#include "mvcc/record.hpp"
#include "storage/model/edge_model.hpp"
#include "utils/string_buffer.hpp"
#include "storage/model/properties/json_writer.hpp"
#include "utils/handle_write.hpp"
#include "mvcc/version_list.hpp"
#include "storage/typed_value_store.hpp"
class Edge : public mvcc::Record<Edge>
{
using buffer_t = utils::StringBuffer;
using props_writer_t = JsonWriter<buffer_t>;
// forward declare Vertex because there is a circular usage Edge <-> Vertex
class Vertex;
class Edge : public mvcc::Record<Edge> {
public:
class Accessor;
Edge() = default;
Edge(const EdgeModel &data) : data(data) {}
Edge(EdgeModel &&data) : data(std::move(data)) {}
Edge(const Edge &) = delete;
Edge(Edge &&) = delete;
Edge &operator=(const Edge &) = delete;
Edge &operator=(Edge &&) = delete;
EdgeModel data;
template <typename Stream>
void stream_repr(Stream &stream) const
{
auto props = handle_write<buffer_t, props_writer_t>(data.props);
stream << "Edge(cre = " << tx.cre() << ", "
<< "exp = " << tx.exp() << ", "
<< "props = " << props.str() << ")";
}
mvcc::VersionList<Vertex>* from_;
mvcc::VersionList<Vertex>* to_;
GraphDb::EdgeType edge_type_;
TypedValueStore properties_;
};

View File

@ -1,55 +1,24 @@
#pragma once
#include "storage/edge.hpp"
#include "storage/edge_record.hpp"
#include "storage/record_accessor.hpp"
#include "storage/vertex_accessor.hpp"
#include "utils/assert.hpp"
#include "utils/reference_wrapper.hpp"
#include "database/graph_db.hpp"
class EdgeType;
using edge_type_ref_t = ReferenceWrapper<const EdgeType>;
class Edges;
// There exists circular dependecy with VertexAccessor.
class EdgeAccessor : public RecordAccessor<TypeGroupEdge, EdgeAccessor>
{
friend VertexAccessor;
class VertexAccessor;
class EdgeAccessor : public RecordAccessor<Edge, EdgeAccessor> {
public:
using RecordAccessor::RecordAccessor;
using RecordAccessor::RecordAccessor;
using record_t = Edge;
using record_list_t = EdgeRecord;
void set_edge_type(GraphDb::EdgeType edge_type);
// Removes self and disconects vertices from it.
void remove() const;
EdgeType edge_type() const;
void edge_type(EdgeType const &edge_type);
VertexAccessor from() const;
const EdgeType &edge_type() const;
VertexAccessor to() const;
// EdgeAccessor doesnt need to be filled
VertexAccessor from() const;
// EdgeAccessor doesnt need to be filled
VertexAccessor to() const;
template <typename Stream>
void stream_repr(Stream& stream) const
{
auto from_va = from();
auto to_va = to();
from_va.fill();
to_va.fill();
from_va.stream_repr(stream);
stream << '-';
this->record->stream_repr(stream);
stream << "->";
to_va.stream_repr(stream);
stream << '\n';
}
void remove() const;
};

View File

@ -1,35 +0,0 @@
#pragma once
#include "mvcc/version_list.hpp"
#include "storage/edge.hpp"
class VertexRecord;
class EdgeRecord : public mvcc::VersionList<Edge>
{
public:
EdgeRecord(Id id, VertexRecord *from, VertexRecord *to)
: from_v(from), to_v(to), VersionList(id)
{
}
EdgeRecord(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
*/
EdgeRecord(EdgeRecord &&other)
: from_v(other.from_v), to_v(other.to_v), VersionList(std::move(other))
{
}
VertexRecord *&get_key() { return this->from_v; }
auto from() const { return this->from_v; }
auto to() const { return this->to_v; }
protected:
VertexRecord *from_v;
VertexRecord *to_v;
};

View File

@ -1,50 +0,0 @@
#pragma once
#include <ostream>
#include <stdint.h>
#include "storage/edge.hpp"
#include "storage/edge_accessor.hpp"
#include "storage/indexes/impl/nonunique_unordered_index.hpp"
#include "storage/type_group_edge.hpp"
#include "utils/char_str.hpp"
#include "utils/reference_wrapper.hpp"
#include "utils/total_ordering.hpp"
using EdgeTypeIndexRecord = IndexRecord<TypeGroupEdge, std::nullptr_t>;
class EdgeType : public TotalOrdering<EdgeType>
{
public:
using type_index_t = NonUniqueUnorderedIndex<TypeGroupEdge, std::nullptr_t>;
EdgeType() = delete;
EdgeType(const std::string &id);
EdgeType(const char *id);
EdgeType(std::string &&id);
EdgeType(const EdgeType &) = delete;
EdgeType(EdgeType &&other) = default;
friend bool operator<(const EdgeType &lhs, const EdgeType &rhs);
friend bool operator==(const EdgeType &lhs, const EdgeType &rhs);
friend std::ostream &operator<<(std::ostream &stream, const EdgeType &type);
operator const std::string &() const;
std::string const &str() const { return id; }
CharStr char_str() { return CharStr(&id[0]); }
// Index of esges which have this type.
type_index_t &index() const;
private:
std::string id;
std::unique_ptr<type_index_t> index_v;
};
using edge_type_ref_t = ReferenceWrapper<const EdgeType>;

View File

@ -1,32 +0,0 @@
#pragma once
#include <stdexcept>
#include "data_structures/concurrent/concurrent_map.hpp"
#include "storage/edge_type/edge_type.hpp"
#include "utils/char_str.hpp"
class EdgeTypeStore
{
public:
using store_t = ConcurrentMap<CharStr, std::unique_ptr<EdgeType>>;
store_t::Accessor access();
const EdgeType &find_or_create(const char *name);
bool contains(const char *name); // TODO: const
// TODO: implement find method
// return { EdgeType, is_found }
// TODO: find by reference if it is possible (should be faster)
// figure out the fastest way to store and find types
// do the same for labels
// TODO: EdgeTypeStore and LabelStore are almost the same
// templetize the two of them
private:
store_t edge_types;
};

View File

@ -1,20 +0,0 @@
#pragma once
// There exists circular dependecy with EdgeAccessor. This file serves to break
// that circularity.
#include "storage/edge_accessor.hpp"
#include "storage/vertex_accessor.hpp"
auto VertexAccessor::out() const
{
DbTransaction &t = this->db;
return iter::make_map(iter::make_iter_ref(record->data.out),
[&](auto e) -> auto { return EdgeAccessor(*e, t); });
}
auto VertexAccessor::in() const
{
DbTransaction &t = this->db;
return iter::make_map(iter::make_iter_ref(record->data.in),
[&](auto e) -> auto { return EdgeAccessor(e, t); });
}

View File

@ -1,47 +0,0 @@
#pragma once
#include <string>
#include "data_structures/concurrent/concurrent_map.hpp"
#include "utils/counters/atomic_counter.hpp"
#include "utils/option.hpp"
#include "storage/edge_record.hpp"
#include "storage/model/properties/property_family.hpp"
class EdgeAccessor;
class DbTransaction;
using EdgePropertyFamily = PropertyFamily<TypeGroupEdge>;
template <class K>
using EdgeIndexBase = IndexBase<TypeGroupEdge, K>;
class Edges
{
using prop_familys_t = ConcurrentMap<std::string, EdgePropertyFamily *>;
using store_t = ConcurrentMap<uint64_t, EdgeRecord>;
public:
store_t::Accessor access();
Option<const EdgeAccessor> find(DbTransaction &t, const Id &id);
// Creates new Edge and returns filled EdgeAccessor.
EdgeAccessor insert(DbTransaction &t, VertexRecord *from, VertexRecord *to);
prop_familys_t::Accessor property_family_access();
EdgePropertyFamily &property_family_find_or_create(const std::string &name);
private:
// TODO: Because familys wont be removed this could be done with more
// efficent
// data structure.
prop_familys_t prop_familys;
// NOTE: this must be before prop_familys field to be destroyed before them.
// Because there are property_family references in vertices.
store_t edges;
AtomicCounter<uint64_t> counter;
};

View File

@ -1,42 +0,0 @@
#pragma once
#include "storage/indexes/index_base.hpp"
// #include "storage/indexes/index_record.hpp"
#include "data_structures/concurrent/concurrent_list.hpp"
template <class TG, class K>
class NonUniqueUnorderedIndex : public IndexBase<TG, K>
{
public:
using store_t = ConcurrentList<IndexRecord<TG, K>>;
// typedef T value_type;
// typedef K key_type;
// Created with the database
NonUniqueUnorderedIndex(IndexLocation &&loc);
NonUniqueUnorderedIndex(IndexLocation &&loc, tx::Transaction const &t);
// Insert's value.
// nonunique => always succeds.
bool insert(IndexRecord<TG, K> &&value) final;
// Returns iterator which returns valid records in range.
// ordered==None => doesn't guarantee any order of submitting records.
iter::Virtual<const typename TG::accessor_t>
for_range(DbAccessor &t, Border<K> from = Border<K>(),
Border<K> to = Border<K>()) final;
// Same as for_range just whit known returned iterator.
auto for_range_exact(DbAccessor &t, Border<K> from = Border<K>(),
Border<K> to = Border<K>());
// Removes for all transactions obsolete Records.
// Cleaner has to call this method when he decideds that it is time for
// cleaning. Id must be id of oldest active transaction.
void clean(const Id &id) final;
private:
store_t list;
};

View File

@ -1,42 +0,0 @@
#pragma once
#include "storage/indexes/index_base.hpp"
#include "data_structures/concurrent/concurrent_set.hpp"
// TODO: T shoud be TG (TypeGroup)
template <class T, class K>
class UniqueOrderedIndex : public IndexBase<T, K>
{
public:
// typedef T value_type;
// typedef K key_type;
// Created with the database
UniqueOrderedIndex(IndexLocation loc, Order order);
UniqueOrderedIndex(IndexLocation loc, Order order,
tx::Transaction const &t);
// Insert's value.
// nonunique => always succeds.
bool insert(IndexRecord<T, K> &&value) final;
// Returns iterator which returns valid records in range.
// ordered==None => doesn't guarantee any order of submitting records.
iter::Virtual<const typename T::accessor_t>
for_range(DbAccessor &t, Border<K> from = Border<K>(),
Border<K> to = Border<K>()) final;
// Same as for_range just whith known returned iterator.
auto for_range_exact(DbAccessor &t, Border<K> from = Border<K>(),
Border<K> to = Border<K>());
// Removes for all transactions obsolete Records.
// Cleaner has to call this method when he decideds that it is time for
// cleaning. Id must be id of oldest active transaction.
void clean(const Id &id) final;
private:
ConcurrentSet<IndexRecord<T, K>> set;
};

View File

@ -1,84 +0,0 @@
#pragma once
#include <atomic>
#include <functional>
#include <memory>
#include "mvcc/id.hpp"
// #include "storage/indexes/index_record.hpp"
#include "logging/loggable.hpp"
#include "storage/garbage/delete_sensitive.hpp"
#include "storage/indexes/index_definition.hpp"
#include "utils/border.hpp"
#include "utils/iterator/virtual_iter.hpp"
template <class TG, class K>
class IndexRecord;
class DbTransaction;
class DbAccessor;
namespace tx
{
class Transaction;
}
// Interface for all indexes.
// TG type group
// K type of key on which records are ordered
template <class TG, class K>
class IndexBase : public DeleteSensitive, public Loggable
{
public:
// Created with the database
IndexBase(IndexDefinition &&it, std::string &&logger_name = "IndexBase");
IndexBase(IndexDefinition &&it, const tx::Transaction &t,
std::string &&logger_name = "IndexBase");
virtual ~IndexBase(){};
// Insert's value.
// unique => returns false if there is already valid equal value.
// nonunique => always succeds.
virtual bool insert(IndexRecord<TG, K> &&value) = 0;
// Returns iterator which returns valid filled records in range.
// order==noe => doesn't guarantee any order of returned records.
// order==Ascending => guarantees order of returnd records will be from
// smallest to largest.
// order==Descending => guarantees order of returned records will be from
// largest to smallest.
// Range must be from<=to
virtual iter::Virtual<const typename TG::accessor_t>
for_range(DbAccessor &, Border<K> from = Border<K>(),
Border<K> to = Border<K>()) = 0;
// Removes for all transactions obsolete Records.
// Cleaner has to call this method when he decideds that it is time for
// cleaning. Id must be id of oldest active transaction.
virtual void clean(const Id &id) = 0;
// Activates index for readers.
void activate();
// True if index is ready for reading.
bool can_read();
// True if transaction is obliged to insert T into index.
bool is_obliged_to_insert(const tx::Transaction &t);
IndexType type() const { return it.type; }
const IndexDefinition &definition() const { return it; }
protected:
Logger logger;
private:
const IndexDefinition it;
// Id of transaction which created this index.
const Id created;
// Active state
std::atomic_bool active = {false};
};

View File

@ -1,104 +0,0 @@
#pragma once
#include "utils/option.hpp"
#include "utils/order.hpp"
#include "utils/underlying_cast.hpp"
enum DbSide : uint8_t
{
EdgeSide = 0,
VertexSide = 1,
};
struct IndexType
{
public:
// Are the records unique
const bool unique;
// Ordering of the records.
const Order order;
};
// Defines location of index in a sense of what is necessary to be present in
// Edge/Vertex for it to be in index.
struct IndexLocation
{
public:
// Returns code for location.
size_t location_code() const
{
return (property_name.is_present() ? 1 : 0) |
(label_name.is_present() ? 2 : 0) |
(edge_type_name.is_present() ? 4 : 0);
}
IndexLocation clone() const
{
return IndexLocation{side, property_name, label_name, edge_type_name};
}
const DbSide side;
const Option<std::string> property_name;
const Option<std::string> label_name;
const Option<std::string> edge_type_name;
};
// Fully answers:
// Index on what?
// What kind of index?
struct IndexDefinition
{
public:
// Serializes self which can be deserialized.
template <class E>
void serialize(E &encoder) const
{
std::string empty;
encoder.write_integer(underlying_cast(loc.side));
encoder.write_string(loc.property_name.get_or(empty));
encoder.write_string(loc.label_name.get_or(empty));
encoder.write_string(loc.edge_type_name.get_or(empty));
encoder.write_bool(type.unique);
encoder.write_integer(underlying_cast(type.order));
}
// Deserializes self.
template <class D>
static IndexDefinition deserialize(D &decoder)
{
auto side = decoder.integer() == 0 ? EdgeSide : VertexSide;
std::string property_name_s;
decoder.string(property_name_s);
auto property_name =
property_name_s.empty()
? Option<std::string>()
: Option<std::string>(std::move(property_name_s));
std::string label_name_s;
decoder.string(label_name_s);
auto label_name = label_name_s.empty()
? Option<std::string>()
: Option<std::string>(std::move(label_name_s));
std::string edge_type_name_s;
decoder.string(edge_type_name_s);
auto edge_type_name =
edge_type_name_s.empty()
? Option<std::string>()
: Option<std::string>(std::move(edge_type_name_s));
bool unique = decoder.read_bool();
auto order_v = decoder.integer();
auto order =
order_v == 0 ? None : (order_v == 1 ? Ascending : Descending);
return IndexDefinition{
IndexLocation{side, property_name, label_name, edge_type_name},
IndexType{unique, order}};
}
const IndexLocation loc;
const IndexType type;
};

View File

@ -1,49 +0,0 @@
#pragma once
#include <atomic>
#include "storage/indexes/index_base.hpp"
#include "utils/option.hpp"
#include "utils/option_ptr.hpp"
namespace tx
{
class Transaction;
}
// Holds one index which can be changed. Convinient class.
// TG - type group
// K - key of index_records
template <class TG, class K>
class IndexHolder
{
public:
IndexHolder() = default;
IndexHolder(IndexHolder const &) = delete;
IndexHolder(IndexHolder &&) = default;
// Sets index for this property family. returns false if index is already
// present.
bool set_index(std::unique_ptr<IndexBase<TG, K>> inx);
// Returns index for read only if it is present and it's valid for read.
OptionPtr<IndexBase<TG, K>> get_read() const;
// Returns index for write only if it's present and transaction is
// responsibly for updating it.
OptionPtr<IndexBase<TG, K>> get_write(const tx::Transaction &t) const;
// Removes index if it is given index. Caller is now responsable of
// disposing index in a safe way.
Option<std::unique_ptr<IndexBase<TG, K>>>
remove_index(IndexBase<TG, K> *index);
// Caller is now responsable of disposing index in a safe way.
Option<std::unique_ptr<IndexBase<TG, K>>> remove_index();
private:
std::atomic<IndexBase<TG, K> *> index = {nullptr};
};

View File

@ -1,70 +0,0 @@
#pragma once
#include "mvcc/id.hpp"
#include "utils/border.hpp"
#include "utils/total_ordering.hpp"
namespace tx
{
class Transaction;
}
class DbTransaction;
// TG type group
// K key on which record is ordered.
template <class TG, class K>
class IndexRecord : public TotalOrdering<IndexRecord<TG, K>>,
public TotalOrdering<Border<K>, IndexRecord<TG, K>>
{
public:
IndexRecord() = default;
IndexRecord(K key, typename TG::record_t *record,
typename TG::vlist_t *vlist);
friend bool operator<(const IndexRecord &lhs, const IndexRecord &rhs)
{
return (lhs.key < rhs.key ||
(lhs.key == rhs.key && lhs.vlist == rhs.vlist &&
lhs.record < rhs.record)) ^
lhs.descending;
}
friend bool operator==(const IndexRecord &lhs, const IndexRecord &rhs)
{
return lhs.key == rhs.key &&
(lhs.vlist != rhs.vlist || lhs.record == rhs.record);
}
friend bool operator<(const Border<K> &lhs, const IndexRecord &rhs)
{
return lhs < rhs.key;
}
friend bool operator==(const Border<K> &lhs, const IndexRecord &rhs)
{
return lhs == rhs.key;
}
// Will change ordering of record to descending.
void set_descending();
// true if record is nullptr.
bool empty() const;
// True if this index record i valid for given Transaction.
bool is_valid(tx::Transaction &t) const;
// True if it can be removed.
bool to_clean(const Id &oldest_active) const;
// This method is valid only if is_valid is true.
const auto access(DbTransaction &db) const;
const K key;
private:
bool descending = false; // TODO: this can be passed as template argument.
typename TG::record_t *const record{nullptr};
typename TG::vlist_t *const vlist{nullptr};
};

View File

@ -1,45 +0,0 @@
#pragma once
#include "storage/indexes/index_record.hpp"
#include "storage/type_group_edge.hpp"
#include "storage/type_group_vertex.hpp"
// Record for updating indexes of edge
struct IndexUpdateEdge
{
EdgeRecord *vlist;
Edge *record;
};
// Record for updatin indexes of vertex
struct IndexUpdateVertex
{
VertexRecord *vlist;
Vertex *record;
};
// based of IndexUpdate objects IndexRecords are created
// at the end of transaction (inside commit called on DbAccessor)
struct IndexUpdate
{
enum
{
EDGE,
VERTEX
} tag;
union
{
IndexUpdateEdge e;
IndexUpdateVertex v;
};
};
template <class T, class V>
IndexUpdate make_index_update(V *vlist, T *record);
template <>
IndexUpdate make_index_update(EdgeRecord *vlist, Edge *record);
template <>
IndexUpdate make_index_update(VertexRecord *vlist, Vertex *record);

View File

@ -1,308 +0,0 @@
#pragma once
#include "database/db.hpp"
#include "storage/garbage/garbage.hpp"
#include "storage/graph.hpp"
#include "storage/indexes/impl/nonunique_unordered_index.hpp"
#include "storage/indexes/impl/unique_ordered_index.hpp"
#include "storage/indexes/index_definition.hpp"
#include "transactions/engine.hpp"
#include "utils/exceptions/non_exaustive_switch.hpp"
#include "utils/exceptions/not_yet_implemented.hpp"
// Operation on indexes in the This should be the only place which knows how
// to get all indexes in database.
// TODO: This class should be updated accordingly when adding new place for
// index.
class Indexes
{
public:
Indexes(Db &d) : db(d) {}
// Adds index defined in given definition. Returns true if successfull.
bool add_index(IndexDefinition id);
// currently caller has to get index through object that contains
// the index
// TODO: redesign
//
// this was a nice try
// // Returns index from location.
// template <class TG, class K>
// Option<IndexHolder<TG, K>> get_index(IndexLocation loc)
// {
// size_t code = loc.location_code();
//
// switch (code) {
// case 0: // Illegal location
// return Option<IndexHolder<TG, K>>();
//
// case 1:
// switch (loc.side) {
// case EdgeSide: {
// return make_option(
// db.graph.edges
// .property_family_find_or_create(loc.property_name.get())
// .index);
// }
// case VertexSide: {
// return make_option(
// db.graph.vertices
// .property_family_find_or_create(loc.property_name.get())
// .index);
// }
// default:
// throw new NonExhaustiveSwitch("Unkown side: " +
// std::to_string(loc.side));
// };
//
// case 2: // Can't be removed
// return Option<IndexHolder<TG, K>>();
//
// case 3: // Not yet implemented
// throw new NotYetImplemented("Getting index over label and "
// "property isn't yet implemented");
// case 4: // Can't be removed
// return Option<IndexHolder<TG, K>>();
//
// case 5: // Not yet implemented
// throw new NotYetImplemented("Getting index over edge_type and "
// "property isn't yet implemented");
// case 6: // Not yet implemented
// throw new NotYetImplemented("Getting index over edge_type and "
// "label isn't yet implemented");
// case 7: // Not yet implemented
// throw new NotYetImplemented("Getting index over label, edge_type
// "
// "and property isn't yet
// implemented");
// default:
// throw new NonExhaustiveSwitch("Unkown index location code: " +
// std::to_string(code));
// }
// }
// Removes index from given location. Returns true if successfull or if no
// index was present. False if index location is illegal.
bool remove_index(IndexLocation loc)
{
size_t code = loc.location_code();
switch (code) {
case 0: // Illegal location
return false;
case 1:
switch (loc.side) {
case EdgeSide: {
return remove_index(
db.graph.edges
.property_family_find_or_create(loc.property_name.get())
.index);
}
case VertexSide: {
return remove_index(
db.graph.vertices
.property_family_find_or_create(loc.property_name.get())
.index);
}
default:
throw new NonExhaustiveSwitch("Unkown side: " +
std::to_string(loc.side));
};
case 2: // Can't be removed
return false;
case 3: // Not yet implemented
throw new NotYetImplemented("Remove of index over label and "
"property isn't yet implemented");
case 4: // Can't be removed
return false;
case 5: // Not yet implemented
throw new NotYetImplemented("Remove of index over edge_type and "
"property isn't yet implemented");
case 6: // Not yet implemented
throw new NotYetImplemented("Remove of index over edge_type and "
"label isn't yet implemented");
case 7: // Not yet implemented
throw new NotYetImplemented("Remove of index over label, edge_type "
"and property isn't yet implemented");
default:
throw new NonExhaustiveSwitch("Unkown index location code: " +
std::to_string(code));
}
}
// Calls F over all vertex indexes in the database which are readable.
template <class F>
void vertex_indexes(F &&f)
{
for (auto &l : db.graph.label_store.access()) {
f(l.second.get()->index());
}
for_all_property_indexes_read(
db.graph.vertices.property_family_access(), f);
}
// Calls F over all edge indexes in the database which are readable.
template <class F>
void edge_indexes(F &&f)
{
for (auto &l : db.graph.edge_type_store.access()) {
f(l.second.get()->index());
}
for_all_property_indexes_read(db.graph.edges.property_family_access(),
f);
}
// Updates property indexes for given TypeGroup TG and IU index_update
template <class TG, class IU>
bool update_property_indexes(IU &iu, const tx::Transaction &t)
{
for (auto kp : iu.record->data.props) {
// FamilyProperty index
auto opi = kp.key.get_family().index.get_write(t);
if (opi.is_present()) {
if (!opi.get()->insert(IndexRecord<TG, std::nullptr_t>(
std::nullptr_t(), iu.record, iu.vlist))) {
return false;
}
}
// TODO: other property indexes
}
return true;
}
private:
// Calls F for all * property indexes which are readable.
template <class A, class F>
void for_all_property_indexes_read(A &&acc, F &f)
{
for (auto &family : acc) {
auto oi = family.second->index.get_read();
if (oi.is_present()) {
f(*oi.get());
}
}
// TODO: Code for reaching other property indexes which are not yet
// coded into the database.
}
// Creates type of index specified ind index definition.
// TG - type group vertex/edge
// K - key of index
template <class TG, class K>
std::unique_ptr<IndexBase<TG, K>> create_index(IndexDefinition id,
tx::Transaction const &t)
{
// Determine which index is needed
if (id.type.unique) {
switch (id.type.order) {
case None: {
// TODO: Implement this version of index.
throw NotYetImplemented(
"Missing implementation for Unique Unordered Index");
}
case Ascending:
case Descending: {
return std::make_unique<UniqueOrderedIndex<TG, K>>(
id.loc.clone(), id.type.order, t);
}
default:
throw new NonExhaustiveSwitch("Unknown order: " +
std::to_string(id.type.order));
};
} else {
switch (id.type.order) {
case None: {
return std::make_unique<NonUniqueUnorderedIndex<TG, K>>(
id.loc.clone(), t);
}
case Ascending:
case Descending: {
// TODO: Implement this version of index.
throw NotYetImplemented(
"Missing implementation for Nonunique Ordered Index");
}
default:
throw new NonExhaustiveSwitch("Unknown order: " +
std::to_string(id.type.order));
};
}
}
// Fills index with returned elements. Return true if successfully filled.
// Iterator must return std::pair<TG::accessor_t, K>
template <class TG, class K, class I>
bool fill_index(DbTransaction &t, IndexHolder<TG, K> &holder, I &&iter)
{
// Wait for all other active transactions to finish so that this
// transaction can see there changes so that they can be added into
// index.
t.trans.wait_for_active();
auto oindex = holder.get_write(t.trans);
if (oindex.is_present()) {
// Inexed to which whe must insert is present. This wouldn't be the
// case if someone removed it.
auto index = oindex.get();
// Iterate over all elements and add them into index. Fail if
// some insert failed.
bool res = iter.all([&](auto elem) {
// Try to insert record.
if (!index->insert(elem.first.create_index_record(
std::move(elem.second)))) {
// Index is probably unique.
// Index wasn't successfully filled so whe should remove it
// an safely dispose of it.
auto owned_maybe = holder.remove_index(index);
if (owned_maybe.is_present()) {
db.garbage.dispose(db.tx_engine.snapshot(),
owned_maybe.get().release());
}
return false;
}
return true;
});
if (res) {
// Index has been updated accordingly and whe can activate it
// for read.
index->activate();
return true;
}
}
return false;
}
// Removes index from index holder
template <class TG, class K>
bool remove_index(IndexHolder<TG, K> &ih)
{
auto owned_maybe = ih.remove_index();
if (owned_maybe.is_present()) {
// Index was successfully removed so whe are responsible for
// dispoising it safely.
db.garbage.dispose(db.tx_engine.snapshot(),
owned_maybe.get().release());
return true;
}
return false;
}
Db &db;
};

View File

@ -1,20 +0,0 @@
#pragma once
// TODO: DEPRICATED
#include "utils/total_ordering.hpp"
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/property.hpp"
template <class Ordering>
class UniqueIndexKey
{
public:
};
template <class Ordering>
class IndexKey
{
public:
};

View File

@ -1,18 +0,0 @@
#pragma once
// TODO: DEPRICATED
#include "unique_key.hpp"
template <class K, class T, class SortOrder>
class NonUniqueKey
{
public:
NonUniqueKey(const K& key, const T&)
{
}
private:
intptr_t x;
};

View File

@ -1,45 +0,0 @@
#pragma once
// TODO: DEPRICATED
#include "utils/total_ordering.hpp"
#include "storage/indexes/sort_order.hpp"
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/property.hpp"
template <class K, class SortOrder>
class UniqueKey : public TotalOrdering<UniqueKey<K, SortOrder>>
{
public:
using type = UniqueKey<K, SortOrder>;
using key_t = K;
UniqueKey(const K& key) : key(key) {}
friend constexpr bool operator<(const type& lhs, const type& rhs)
{
return sort_order(lhs.key, rhs.key);
}
friend constexpr bool operator==(const type& lhs, const type& rhs)
{
return lhs.key == rhs.key;
}
operator const K&() const { return key; }
private:
static constexpr SortOrder sort_order = SortOrder();
const K& key;
};
template <class K, class SortOrder>
constexpr SortOrder UniqueKey<K, SortOrder>::sort_order;
template <class K>
using UniqueKeyAsc = UniqueKey<K, Ascending<K>>;
template <class K>
using UniqueKeyDesc = UniqueKey<K, Descending<K>>;

View File

@ -1,20 +0,0 @@
#pragma once
#include "utils/iterator/composable.hpp"
// Class for creating easy composable iterators for querying.
//
// This class contains graph specific methods.
//
// Derived - type of derived class
// T - return type
template <class T, Derived>
class GraphComposable : public Composable<T, GraphComposable<T, Derived>>
{
// TODO: various filters
// from filter
// to filter
// match filter
};

View File

@ -1,19 +0,0 @@
#pragma once
#include "utils/iterator/filter.hpp"
#include "storage/iterator/graph_composable.hpp"
template <class T, class I, class OP>
class GraphFilter : public Filter<T, I, OP>,
public GraphComposable<T, GraphFilter<T, I, OP>
{
using Filter::Filter;
};
template <class I, class OP>
auto make_graph_filter(I &&iter, OP &&op)
{
// Compiler cant deduce type T. decltype is here to help with it.
return GraphFilter<decltype(iter.next().take()), I, OP>(std::move(iter),
std::move(op));
}

View File

@ -1,53 +0,0 @@
#pragma once
#include <ostream>
#include <stdint.h>
#include "storage/indexes/impl/nonunique_unordered_index.hpp"
#include "storage/type_group_vertex.hpp"
#include "storage/vertex.hpp"
#include "storage/vertex_accessor.hpp"
#include "utils/char_str.hpp"
#include "utils/reference_wrapper.hpp"
#include "utils/total_ordering.hpp"
using LabelIndexRecord = IndexRecord<TypeGroupVertex, std::nullptr_t>;
class Label : public TotalOrdering<Label>, TotalOrdering<CharStr, Label>
{
public:
using label_index_t =
NonUniqueUnorderedIndex<TypeGroupVertex, std::nullptr_t>;
Label() = delete;
Label(const char *name);
Label(const Label &) = delete;
Label(Label &&other) = default;
friend bool operator<(const Label &lhs, const Label &rhs);
friend bool operator==(const Label &lhs, const Label &rhs);
friend bool operator<(const CharStr &lhs, const Label &rhs);
friend bool operator==(const CharStr &lhs, const Label &rhs);
friend std::ostream &operator<<(std::ostream &stream, const Label &label);
operator const std::string &() const;
std::string const &str() const { return name; }
CharStr char_str() const { return CharStr(name.c_str()); }
// Index of vertices with current label.
label_index_t &index() const;
private:
std::unique_ptr<label_index_t> index_v;
std::string name;
};
using label_ref_t = ReferenceWrapper<const Label>;

View File

@ -1,37 +0,0 @@
#pragma once
#include <vector>
#include "utils/reference_wrapper.hpp"
class Label;
using label_ref_t = ReferenceWrapper<const Label>;
class LabelCollection
{
public:
auto begin() { return labels_.begin(); }
auto begin() const { return labels_.begin(); }
auto cbegin() const { return labels_.begin(); }
auto end() { return labels_.end(); }
auto end() const { return labels_.end(); }
auto cend() const { return labels_.end(); }
bool add(const Label &label);
bool has(const Label &label) const;
size_t count() const;
bool remove(const Label &label);
void clear();
const std::vector<label_ref_t> &operator()() const;
template <class Handler>
void handle(Handler &handler) const
{
for (auto &label : labels_)
handler.handle(label.get());
}
private:
std::vector<label_ref_t> labels_;
};

View File

@ -1,25 +0,0 @@
#pragma once
#include <stdexcept>
#include "data_structures/concurrent/concurrent_set.hpp"
#include "storage/label/label.hpp"
#include "utils/char_str.hpp"
class LabelStore
{
public:
using store_t = ConcurrentMap<CharStr, std::unique_ptr<Label>>;
store_t::Accessor access();
const Label &find_or_create(const char *name);
bool contains(const char *name); // TODO: const
// TODO: implement find method
// return { Label, is_found }
private:
store_t labels;
};

View File

@ -1,23 +0,0 @@
#pragma once
class Label;
template <class Buffer>
class LabelsWriter
{
public:
LabelsWriter(Buffer &buffer) : buffer_(buffer) {}
~LabelsWriter() = default;
LabelsWriter(const LabelsWriter &) = delete;
LabelsWriter(LabelsWriter &&) = delete;
LabelsWriter &operator=(const LabelsWriter &) = delete;
LabelsWriter &operator=(LabelsWriter &&) = delete;
void handle(const Label& label);
private:
Buffer& buffer_;
};

View File

@ -1,34 +0,0 @@
#pragma once
#include <vector>
#include "mvcc/version_list.hpp"
#include "storage/edge_record.hpp"
class EdgeList
{
public:
auto begin() { return edges.begin(); }
auto begin() const { return edges.begin(); }
auto cbegin() const { return edges.begin(); }
auto end() { return edges.end(); }
auto end() const { return edges.end(); }
auto cend() const { return edges.end(); }
void add(EdgeRecord *edge) { edges.emplace_back(edge); }
size_t degree() const { return edges.size(); }
void remove(EdgeRecord *edge)
{
edges.erase(std::remove(edges.begin(), edges.end(), edge), edges.end());
}
void clear() { edges.clear(); }
std::size_t size() { return edges.size(); }
private:
std::vector<EdgeRecord *> edges;
};

View File

@ -1,34 +0,0 @@
#pragma once
#include "data_structures/map/rh_hashmultimap.hpp"
#include "storage/edge_record.hpp"
class EdgeMap
{
public:
auto begin() { return edges.begin(); }
auto begin() const { return edges.begin(); }
auto cbegin() const { return edges.begin(); }
auto end() { return edges.end(); }
auto end() const { return edges.end(); }
auto cend() const { return edges.end(); }
size_t degree() const { return edges.size(); }
void add(EdgeRecord *edge) { edges.add(edge); }
void remove(EdgeRecord *edge)
{
edges.remove(edge); // Currently the return is ignored
}
bool contains(VertexRecord *vr) const { return edges.contains(vr); }
void clear() { edges.clear(); }
std::size_t size() { return edges.size(); }
private:
RhHashMultiMap<VertexRecord *, EdgeRecord> edges;
};

View File

@ -1,17 +0,0 @@
#pragma once
// #include "mvcc/version_list.hpp"
// #include "storage/edge_type/edge_type.hpp"
#include "storage/model/property_model.hpp"
#include "storage/type_group_edge.hpp"
class EdgeType;
class EdgeModel : public PropertyModel<TypeGroupEdge>
{
public:
// TODO: here should be the reference
// but something that is copyable
// because this model is copied all the time (mvcc)
const EdgeType *edge_type{nullptr};
};

View File

@ -1,10 +0,0 @@
#pragma once
#include "storage/model/properties/properties.hpp"
template <class TG>
class PropertyModel
{
public:
Properties<TG> props;
};

View File

@ -1,14 +0,0 @@
#pragma once
#include "storage/label/label_collection.hpp"
#include "storage/model/edge_list.hpp"
#include "storage/model/edge_map.hpp"
#include "storage/model/property_model.hpp"
class VertexModel : public PropertyModel<TypeGroupVertex>
{
public:
EdgeList out;
EdgeMap in;
LabelCollection labels;
};

View File

@ -2,175 +2,89 @@
#include "database/db_transaction.hpp"
#include "mvcc/version_list.hpp"
#include "storage/indexes/index_record.hpp"
#include "storage/indexes/index_update.hpp"
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/property.hpp"
#include "storage/model/properties/property_family.hpp"
#include "storage/model/properties/stored_property.hpp"
#include "transactions/transaction.hpp"
#include "storage/typed_value.hpp"
#include "database/graph_db.hpp"
#include "utils/pass_key.hpp"
template <class TG, class Derived>
class RecordAccessor
{
friend DbAccessor;
using vlist_t = typename TG::vlist_t;
using T = typename TG::record_t;
template <typename TRecord, typename TDerived>
class RecordAccessor {
public:
RecordAccessor(vlist_t *vlist, DbTransaction &db) : vlist(vlist), db(db)
{
assert(vlist != nullptr);
RecordAccessor(mvcc::VersionList<TRecord>* vlist, DbTransaction &db_trans)
: vlist_(vlist), db_trans_(db_trans) {
assert(vlist_ != nullptr);
}
RecordAccessor(TRecord *t, mvcc::VersionList<TRecord> *vlist, DbTransaction &db_trans)
: record_(t), vlist_(vlist), db_trans_(db_trans) {
assert(record_ != nullptr);
assert(vlist_ != nullptr);
}
// TODO: Test this
TDerived update() const {
assert(!empty());
if (record_->is_visible_write(db_trans_.trans)) {
// TODO: VALIDATE THIS BRANCH. THEN ONLY THIS TRANSACTION CAN SEE
// THIS DATA WHICH MEANS THAT IT CAN CHANGE IT.
return TDerived(record_, vlist_, db_trans_);
} else {
auto new_record_ = vlist_->update(db_trans_.trans);
// TODO: Validate that update of record in this accessor is correct.
const_cast<RecordAccessor *>(this)->record_ = new_record;
return TDerived(new_record, vlist_, db_trans_);
}
}
RecordAccessor(T *t, vlist_t *vlist, DbTransaction &db)
: record(t), vlist(vlist), db(db)
{
assert(record != nullptr);
assert(vlist != nullptr);
}
TypedValue at(GraphDb::Property key) const {
return record_->props_.at(key);
}
RecordAccessor(RecordAccessor const &other)
: record(other.record), vlist(other.vlist), db(other.db)
{
}
RecordAccessor(RecordAccessor &&other)
: record(other.record), vlist(other.vlist), db(other.db)
{
}
template <typename TValue>
void set(GraphDb::Property key, TValue value) {
// TODO should update be called here?!?!
record_->props_.set(key, value);
}
bool empty() const { return record == nullptr; }
size_t erase(GraphDb::Property key) const {
return record_->props_.erase(key);
}
// Fills accessor and returns true if there is valid data for current
// transaction false otherwise.
bool fill() const
{
const_cast<RecordAccessor *>(this)->record = vlist->find(db.trans);
return record != nullptr;
}
void Accept(std::function<void(const GraphDb::Property key, const TypedValue& prop)> handler,
std::function<void()> finish = {}) const {
record_->props_.Accept(handler, finish);
}
const Id &id() const { return vlist->id; }
// Assumes same transaction
friend bool operator==(const RecordAccessor &a, const RecordAccessor &b) {
// TODO consider the legitimacy of this comparison
return a.vlist_ == b.vlist_;
}
// True if record visible for current transaction is visible to given
// transaction id.
bool is_visble_to(tx::TransactionRead const &id)
{
return record->visible(id);
}
// Assumes same transaction
friend bool operator!=(const RecordAccessor &a, const RecordAccessor &b) {
// TODO consider the legitimacy of this comparison
return !(a == b);
}
// Returns new IndexRecord with given key.
template <class K>
IndexRecord<TG, K> create_index_record(K &&key)
{
return IndexRecord<TG, K>(std::move(key), record, vlist);
}
/**
* Exposes the version list only to the GraphDb.
*
* @param pass_key Ignored.
* @return The version list of this accessor.
*/
mvcc::VersionList<TRecord>* vlist(Passkey<GraphDb> pass_key) {
return vlist_;
}
// TODO: Test this
Derived update() const
{
assert(!empty());
if (record->is_visible_write(db.trans)) {
// TODO: VALIDATE THIS BRANCH. THEN ONLY THIS TRANSACTION CAN SEE
// THIS DATA WHICH MEANS THAT IT CAN CHANGE IT.
return Derived(record, vlist, db);
} else {
auto new_record = vlist->update(db.trans);
// TODO: Validate that update of record in this accessor is correct.
const_cast<RecordAccessor *>(this)->record = new_record;
// Add record to update index.
db.to_update_index<TG>(vlist, new_record);
return Derived(new_record, vlist, db);
}
}
bool contains(property_key<TG> &key) const
{
return properties().contains(key);
}
const StoredProperty<TG> &at(PropertyFamily<TG> &key) const
{
return properties().at(key);
}
const StoredProperty<TG> &at(property_key<TG> &key) const
{
return properties().at(key);
}
template <class V>
OptionPtr<const V> at(type_key_t<TG, V> &key) const
{
return properties().template at<V>(key);
}
void set(property_key<TG> &key, Property value)
{
properties().set(StoredProperty<TG>(std::move(value), key));
}
void set(StoredProperty<TG> value) { properties().set(std::move(value)); }
void clear(property_key<TG> &key) { properties().clear(key); }
void clear(PropertyFamily<TG> &key) { properties().clear(key); }
template <class Handler>
void accept(Handler &handler) const
{
properties().template accept<Handler>(handler);
}
template <class Handler>
void handle(Handler &handler) const
{
properties().template handle<Handler>(handler);
}
Properties<TG> &properties() const { return record->data.props; }
explicit operator bool() const { return record != nullptr; }
T const *operator->() const { return record; }
T *operator->() { return record; }
RecordAccessor &operator=(const RecordAccessor &other)
{
record = other.record;
vlist_t *&vl = const_cast<vlist_t *&>(vlist);
vl = other.vlist;
return *this;
}
RecordAccessor &operator=(RecordAccessor &&other)
{
record = other.record;
vlist_t *&vl = const_cast<vlist_t *&>(vlist);
vl = other.vlist;
return *this;
}
// Assumes same transaction
friend bool operator==(const RecordAccessor &a, const RecordAccessor &b)
{
return a.vlist == b.vlist;
}
// Assumes same transaction
friend bool operator!=(const RecordAccessor &a, const RecordAccessor &b)
{
return !(a == b);
}
protected:
void remove() const;
T *record{nullptr};
vlist_t *const vlist;
DbTransaction &db;
TRecord* record_{nullptr};
mvcc::VersionList<TRecord>* vlist_;
DbTransaction& db_trans_;
};

View File

@ -1,19 +0,0 @@
#pragma once
class Edge;
class EdgeRecord;
class EdgeAccessor;
// Types for Edge side of database. Firstly there exists need for knowing the
// type of object to be able to efficently use it. Dependant classes can
// templetaze over such type, but this is anoying and error prone if there are
// multiple such types over which it is necessary to templetaze. The idea is to
// unify groups of logicaly tyed types into one type. That way depending classes
// can template over that one type.
class TypeGroupEdge
{
public:
using record_t = Edge;
using vlist_t = EdgeRecord;
using accessor_t = EdgeAccessor;
};

View File

@ -1,19 +0,0 @@
#pragma once
class Vertex;
class VertexRecord;
class VertexAccessor;
// Types for Vertex side of database. Firstly there exists need for knowing the
// type of object to be able to efficently use it. Dependant classes can
// templetaze over such type, but this is anoying and error prone if there are
// multiple such types over which it is necessary to templetaze. The idea is to
// unify groups of logicaly tyed types into one type. That way depending classes
// can template over that one type.
class TypeGroupVertex
{
public:
using record_t = Vertex;
using vlist_t = VertexRecord;
using accessor_t = VertexAccessor;
};

View File

@ -6,7 +6,7 @@
#pragma once
#include <ostream>
#include "storage/model/typed_value_store.hpp"
#include "storage/typed_value_store.hpp"
/**

View File

@ -1,42 +1,18 @@
#pragma once
#include "database/graph_db.hpp"
#include "mvcc/record.hpp"
#include "storage/label/labels_writer.hpp"
#include "storage/model/properties/json_writer.hpp"
#include "storage/model/vertex_model.hpp"
#include "utils/handle_write.hpp"
#include "utils/string_buffer.hpp"
#include "mvcc/version_list.hpp"
#include "storage/typed_value_store.hpp"
class Vertex : public mvcc::Record<Vertex>
{
using buffer_t = utils::StringBuffer;
using props_writer_t = JsonWriter<buffer_t>;
using labels_writer_t = LabelsWriter<buffer_t>;
// forward declare Edge because there is a circular usage Edge <-> Vertex
class Edge;
class Vertex : public mvcc::Record<Vertex> {
public:
class Accessor;
Vertex() = default;
Vertex(const VertexModel &data) : data(data) {}
Vertex(VertexModel &&data) : data(std::move(data)) {}
Vertex(const Vertex &) = delete;
Vertex(Vertex &&) = delete;
Vertex &operator=(const Vertex &) = delete;
Vertex &operator=(Vertex &&) = delete;
VertexModel data;
template <typename Stream>
void stream_repr(Stream &stream) const
{
auto props = handle_write<buffer_t, props_writer_t>(data.props);
auto labels = handle_write<buffer_t, labels_writer_t>(data.labels);
stream << "Vertex(cre = " << tx.cre() << ", "
<< "exp = " << tx.exp() << ", "
<< "props = " << props.str() << ", "
<< "labels = " << labels.str() << ")";
}
std::vector<mvcc::VersionList<Edge> *> out_;
std::vector<mvcc::VersionList<Edge> *> in_;
std::set<GraphDb::Label> labels_;
TypedValueStore properties_;
};

View File

@ -1,64 +1,34 @@
#pragma once
#include "storage/label/label_collection.hpp"
#include <set>
#include "storage/record_accessor.hpp"
#include "storage/vertex.hpp"
#include "utils/iterator/iterator.hpp"
#include "database/graph_db.hpp"
class Vertices;
class EdgeAccessor;
// There exists circular dependecy with EdgeAccessor.
class VertexAccessor : public RecordAccessor<TypeGroupVertex, VertexAccessor>
{
friend EdgeAccessor;
class VertexAccessor : public RecordAccessor<Vertex, VertexAccessor> {
public:
using RecordAccessor::RecordAccessor;
using RecordAccessor::RecordAccessor;
using record_t = Vertex;
using record_list_t = VertexRecord;
size_t out_degree() const;
// Removes self and all edges connected to it.
void remove() const;
size_t in_degree() const;
// Returns number of out edges.
size_t out_degree() const;
bool add_label(GraphDb::Label label);
// Returns number of in edges.
size_t in_degree() const;
size_t remove_label(GraphDb::Label label);
// Returns number of all edges.
size_t degree() const;
bool has_label(GraphDb::Label label) const;
// True if vertex isn't connected to any other vertex.
bool isolated() const;
const std::set<GraphDb::Label>& labels() const;
// False if it already has the label.
bool add_label(const Label &label);
// TODO add in/out functions that return (collection|iterator) over EdgeAccessor
// False if it doesn't have the label.
bool remove_label(const Label &label);
// returns if remove was possible due to connections
bool remove() const;
// Checks if it has the label.
bool has_label(const Label &label) const;
// Returns container with all labels.
const std::vector<label_ref_t> &labels() const;
auto out() const;
auto in() const;
// True if there exists edge between other vertex and this vertex.
bool in_contains(VertexAccessor const &other) const;
template <typename Stream>
void stream_repr(Stream& stream) const
{
if (!this->record)
return;
this->record->stream_repr(stream);
}
void detach_remove() const;
};

View File

@ -1,12 +0,0 @@
#pragma once
#include "mvcc/version_list.hpp"
#include "storage/vertex.hpp"
class VertexRecord : public mvcc::VersionList<Vertex>
{
public:
VertexRecord(Id id) : VersionList(id) {}
VertexRecord(const VersionList &) = delete;
VertexRecord(VersionList &&other) : VersionList(std::move(other)) {}
};

View File

@ -1,52 +0,0 @@
#pragma once
#include <string>
#include "data_structures/concurrent/concurrent_map.hpp"
#include "utils/counters/atomic_counter.hpp"
#include "utils/option.hpp"
#include "storage/model/properties/property_family.hpp"
#include "storage/vertex_record.hpp"
class DbTransaction;
class VertexAccessor;
using VertexPropertyFamily = PropertyFamily<TypeGroupVertex>;
template <class K>
using VertexIndexBase = IndexBase<TypeGroupVertex, K>;
class Vertices
{
public:
using vertices_t = ConcurrentMap<uint64_t, VertexRecord>;
using prop_familys_t =
ConcurrentMap<std::string, std::unique_ptr<VertexPropertyFamily>>;
vertices_t::Accessor access();
Option<const VertexAccessor> find(DbTransaction &t, const Id &id);
// Creates new Vertex and returns filled VertexAccessor.
VertexAccessor insert(DbTransaction &t);
// TODO: how can I know how many elements exist
// without iterating through all of them? MVCC?
VertexPropertyFamily &
property_family_find_or_create(const std::string &name);
prop_familys_t::Accessor property_family_access();
private:
// TODO: Because families wont be removed this could be done with more
// efficent
// data structure.
prop_familys_t prop_familys;
// NOTE: this must be before prop_familys field to be destroyed before them.
// Because there are property_family references in vertices.
vertices_t vertices;
AtomicCounter<uint64_t> counter;
};

View File

@ -0,0 +1,22 @@
//
// Copyright 2017 Memgraph
// Created by Marko Budiselic
//
// SOURCES:
// http://arne-mertz.de/2016/10/passkey-idiom/
// http://stackoverflow.com/questions/3217390/clean-c-granular-friend-equivalent-answer-attorney-client-idiom
#pragma once
template<typename T>
class PassKey {
friend T;
private:
// default constructor has to be manually defined otherwise = default
// would allow aggregate initialization to bypass default constructor
// both, default and copy constructors have to be user-defined
// otherwise are public by default
PassKey() {}
};

View File

@ -1,7 +1,7 @@
#include <cstring>
#include <ctime>
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "import/csv_import.hpp"
#include "logging/default.hpp"
#include "logging/streams/stdout.hpp"

View File

@ -11,7 +11,7 @@
#include "communication/bolt/v1/serialization/bolt_serializer.hpp"
#include "data_structures/map/rh_hashmap.hpp"
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "database/db_accessor.cpp"
#include "database/db_accessor.hpp"
#include "import/csv_import.hpp"

View File

@ -11,7 +11,7 @@
#include "communication/bolt/v1/serialization/bolt_serializer.hpp"
#include "data_structures/map/rh_hashmap.hpp"
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "database/db_accessor.cpp"
#include "database/db_accessor.hpp"
#include "import/csv_import.hpp"

View File

@ -1,4 +1,4 @@
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "import/csv_import.hpp"
#include "logging/default.hpp"
#include "logging/streams/stdout.hpp"

View File

@ -4,7 +4,7 @@
#include <unistd.h>
#include <unordered_map>
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "database/db_accessor.hpp"
#include "communication/bolt/v1/serialization/bolt_serializer.hpp"
#include "import/csv_import.hpp"

View File

@ -1,4 +1,4 @@
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "database/db_accessor.hpp"
#include <chrono>

View File

@ -1,21 +0,0 @@
#include "database/db.hpp"
#include "snapshot/snapshoter.hpp"
#include "storage/indexes/indexes.hpp"
#include "storage/model/properties/property_family.hpp"
Db::Db(bool import_snapshot) : Db("default", import_snapshot) {}
Db::Db(const std::string &name, bool import_snapshot)
: Db(name.c_str(), import_snapshot)
{
}
Db::Db(const char *name, bool import_snapshot) : name_(name)
{
if (import_snapshot) snap_engine.import();
}
Indexes Db::indexes() { return Indexes(*this); }
std::string const &Db::name() const { return name_; }

View File

@ -1,4 +1,4 @@
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "database/db_accessor.hpp"
DbAccessor::DbAccessor(Db &db)

View File

@ -1,6 +1,6 @@
#include "database/db_transaction.hpp"
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "serialization/serialization.hpp"
#include "storage/edge.hpp"
#include "storage/edge_type/edge_type.hpp"

77
src/database/graph_db.cpp Normal file
View File

@ -0,0 +1,77 @@
#include <storage/edge.hpp>
#include "database/creation_exception.hpp"
#include "database/graph_db.hpp"
#include "snapshot/snapshoter.hpp"
#include "storage/vertex.hpp"
#include "storage/vertex_accessor.hpp"
#include "storage/edge.hpp"
#include "storage/edge_accessor.hpp"
GraphDb::GraphDb(bool import_snapshot) : GraphDb("default", import_snapshot) {}
GraphDb::GraphDb(const std::string &name, bool import_snapshot)
: GraphDb(name.c_str(), import_snapshot) {
}
//GraphDb::GraphDb(const char *name, bool import_snapshot) : name_(name) {
// if (import_snapshot) snap_engine.import();
//}
VertexAccessor GraphDb::insert_vertex(DbTransaction &db_trans) {
auto vertex_vlist = new mvcc::VersionList<Vertex>();
vertex_vlist->insert(db_trans.trans);
// TODO make this configurable
for (int i = 0; i < 5; ++i) {
bool success = vertices_.access().insert(vertex_vlist).second;
if (success)
return VertexAccessor(vertex_vlist, db_trans);
// TODO sleep for some amount of time
}
throw CreationException("Unable to create a Vertex after 5 attempts");
}
EdgeAccessor GraphDb::insert_edge(
DbTransaction& db_trans, VertexAccessor& from,
VertexAccessor& to, EdgeType type) {
auto edge_vlist = new mvcc::VersionList<Edge>();
Edge* edge = edge_vlist->insert(db_trans.trans);
// set the given values of the new edge
edge->edge_type_ = type;
// connect the edge to vertices
edge->from_ = from.vlist(pass_key);
edge->to_ = to.vlist(pass_key);
// connect the vertices to edge
from.vlist(pass_key).out_.emplace(edge_vlist);
to.vlist(pass_key).in_.emplace(edge_vlist);
// TODO make this configurable
for (int i = 0; i < 5; ++i) {
bool success = edges_.access().insert(edge_vlist).second;
if (success)
return EdgeAccessor(edge_vlist, db_trans);
// TODO sleep for some amount of time
}
throw CreationException("Unable to create an Edge after 5 attempts");
EdgeRecord edge_record(next, from, to);
auto edge = edge_record.insert(t.trans);
// insert the new vertex record into the vertex store
auto edges_accessor = edges.access();
auto result = edges_accessor.insert(next, std::move(edge_record));
// create new vertex
auto inserted_edge_record = result.first;
t.to_update_index<TypeGroupEdge>(&inserted_edge_record->second, edge);
return EdgeAccessor(edge, &inserted_edge_record->second, t);
}
`

View File

@ -4,7 +4,7 @@
#include "debug/log.hpp"
#include "utils/ioc/container.hpp"
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "api/resources/include.hpp"
#include "speedy/speedy.hpp"

View File

@ -1,45 +1,32 @@
#include "storage/edge_accessor.hpp"
#include "storage/vertex_accessor.hpp"
#include <cassert>
#include "utils/assert.hpp"
#include "storage/vertex_record.hpp"
#include "storage/edge_type/edge_type.hpp"
void EdgeAccessor::remove() const
{
RecordAccessor::remove();
auto from_va = from();
auto from_va_is_full = from_va.fill();
runtime_assert(from_va_is_full, "From Vertex Accessor is empty");
auto to_va = to();
auto to_va_is_full = to_va.fill();
permanent_assert(to_va_is_full, "To Vertex Accessor is empty");
from_va.update().record->data.out.remove(vlist);
to_va.update().record->data.in.remove(vlist);
void EdgeAccessor::set_edge_type(GraphDb::EdgeType edge_type) {
this->record_->edge_type_ = edge_type;
}
void EdgeAccessor::edge_type(const EdgeType &edge_type)
{
this->record->data.edge_type = &edge_type;
GraphDb::EdgeType EdgeAccessor::edge_type() const {
return this->record_->edge_type_;
}
const EdgeType &EdgeAccessor::edge_type() const
{
assert(this->record->data.edge_type != nullptr);
runtime_assert(this->record->data.edge_type != nullptr, "EdgeType is null");
return *this->record->data.edge_type;
VertexAccessor EdgeAccessor::from() const {
return VertexAccessor(this->record_->from_, this->db_trans_);
}
VertexAccessor EdgeAccessor::from() const
{
return VertexAccessor(this->vlist->from(), this->db);
VertexAccessor EdgeAccessor::to() const {
return VertexAccessor(this->record_->to_, this->db_trans_);
}
VertexAccessor EdgeAccessor::to() const
{
return VertexAccessor(this->vlist->to(), this->db);
void EdgeAccessor::remove() const {
// remove this edge's reference from the "from" vertex
auto& vertex_from_out = from().update().record_->out_;
std::remove(vertex_from_out.begin(), vertex_from_out.end(), record_->from_);
// remove this edge's reference from the "to" vertex
auto& vertex_to_in = to().update().record_->in_;
std::remove(vertex_to_in.begin(), vertex_to_in.end(), record_->to_);
// remove this record from the database via MVCC
vlist_->remove(record_, db_trans_.trans);
}

View File

@ -1,28 +0,0 @@
#include "storage/edge_type/edge_type.hpp"
EdgeType::EdgeType(const std::string &id) : EdgeType(std::string(id)) {}
EdgeType::EdgeType(const char *id) : EdgeType(std::string(id)) {}
EdgeType::EdgeType(std::string &&id)
: id(id), index_v(std::make_unique<type_index_t>(IndexLocation{
EdgeSide, Option<std::string>(), Option<std::string>(id)}))
{
}
bool operator<(const EdgeType &lhs, const EdgeType &rhs)
{
return lhs.id < rhs.id;
}
bool operator==(const EdgeType &lhs, const EdgeType &rhs)
{
return lhs.id == rhs.id;
}
std::ostream &operator<<(std::ostream &stream, const EdgeType &type)
{
return stream << type.id;
}
EdgeType::operator const std::string &() const { return id; }
EdgeType::type_index_t &EdgeType::index() const { return *index_v.get(); }

View File

@ -1,24 +0,0 @@
#include "storage/edge_type/edge_type_store.hpp"
EdgeTypeStore::store_t::Accessor EdgeTypeStore::access()
{
return edge_types.access();
}
const EdgeType &EdgeTypeStore::find_or_create(const char *name)
{
auto accessor = edge_types.access();
auto it = accessor.find(CharStr(name));
if (it == accessor.end()) {
auto l = std::make_unique<EdgeType>(name);
auto k = l->char_str();
it = accessor.insert(k, std::move(l)).first;
}
return *(it->second);
}
bool EdgeTypeStore::contains(const char *name) // const
{
auto accessor = edge_types.access();
return accessor.find(CharStr(name)) != accessor.end();
}

View File

@ -1,60 +0,0 @@
#include "storage/edges.hpp"
#include "storage/edge_accessor.hpp"
#include "utils/iterator/iterator.hpp"
Edges::store_t::Accessor Edges::access() { return edges.access(); }
Option<const EdgeAccessor> Edges::find(DbTransaction &t, const Id &id)
{
auto edges_accessor = edges.access();
auto edges_iterator = edges_accessor.find(id);
if (edges_iterator == edges_accessor.end())
return make_option<const EdgeAccessor>();
return make_option_const(EdgeAccessor(&edges_iterator->second, t));
}
EdgeAccessor Edges::insert(DbTransaction &t, VertexRecord *from,
VertexRecord *to)
{
// get next vertex id
auto next = counter.next(std::memory_order_acquire);
// create new vertex record
EdgeRecord edge_record(next, from, to);
auto edge = edge_record.insert(t.trans);
// insert the new vertex record into the vertex store
auto edges_accessor = edges.access();
auto result = edges_accessor.insert(next, std::move(edge_record));
// create new vertex
auto inserted_edge_record = result.first;
t.to_update_index<TypeGroupEdge>(&inserted_edge_record->second, edge);
return EdgeAccessor(edge, &inserted_edge_record->second, t);
}
Edges::prop_familys_t::Accessor Edges::property_family_access()
{
return prop_familys.access();
}
EdgePropertyFamily &
Edges::property_family_find_or_create(const std::string &name)
{
auto acc = prop_familys.access();
auto it = acc.find(name);
if (it == acc.end()) {
EdgePropertyFamily *family = new EdgePropertyFamily(name);
auto res = acc.insert(name, family);
if (!res.second) {
delete family;
}
it = res.first;
}
return *(it->second);
}

View File

@ -1,93 +0,0 @@
#include "storage/indexes/impl/nonunique_unordered_index.hpp"
#include "database/db_accessor.hpp"
#include "database/db_transaction.hpp"
#include "storage/edge_accessor.hpp"
#include "storage/edge_record.hpp"
#include "storage/type_group_edge.hpp"
#include "storage/type_group_vertex.hpp"
#include "storage/vertex_accessor.hpp"
#include "storage/vertex_record.hpp"
#include "utils/iterator/iterator.hpp"
#include "storage/indexes/index_record.cpp"
template <class T, class K>
NonUniqueUnorderedIndex<T, K>::NonUniqueUnorderedIndex(IndexLocation &&loc)
: IndexBase<T, K>(IndexDefinition{loc, IndexType{false, None}},
"NonUniqueUnorderedIndex")
{
}
template <class T, class K>
NonUniqueUnorderedIndex<T, K>::NonUniqueUnorderedIndex(IndexLocation &&loc,
tx::Transaction const &t)
: IndexBase<T, K>(IndexDefinition{loc, IndexType{false, None}}, t,
"NonUniqueUnorderedIndex")
{
}
template <class T, class K>
bool NonUniqueUnorderedIndex<T, K>::insert(IndexRecord<T, K> &&value)
{
list.begin().push(std::move(value));
return true;
}
template <class T, class K>
iter::Virtual<const typename T::accessor_t>
NonUniqueUnorderedIndex<T, K>::for_range(DbAccessor &t, Border<K> from,
Border<K> to)
{
return iter::make_virtual(
for_range_exact(t, std::move(from), std::move(to)));
}
template <class T, class K>
auto NonUniqueUnorderedIndex<T, K>::for_range_exact(DbAccessor &t_v,
Border<K> from_v,
Border<K> to_v)
{
return iter::make_iterator(
[
it = list.cbegin(), end = list.cend(), from = from_v, to = to_v,
// &t_v is passed by reference because otherwise
// DbAccessor would be copied that means that t_v.db_transaction would
// also be copied and that wouldn't be good because
// db_transaction contains index_updates
t = &t_v
]() mutable -> auto {
// NonUniqueUnorderedIndex is stupid so it must iterate through all
// index records to determine which are iniside borders.
while (it != end) {
const IndexRecord<T, K> &r = *it;
if (from < r.key && to > r.key &&
r.is_valid(t->db_transaction.trans)) {
// record r is inside borders and is valid for current
// transaction.
const typename T::accessor_t acc =
r.access(t->db_transaction);
it++;
return make_option(std::move(acc));
}
it++;
}
return Option<const typename T::accessor_t>();
},
list.size());
}
template <class T, class K>
void NonUniqueUnorderedIndex<T, K>::clean(const Id &id)
{
auto end = list.end();
for (auto it = list.begin(); it != end; it++) {
if (it->to_clean(id)) {
it.remove();
}
}
}
template class NonUniqueUnorderedIndex<TypeGroupEdge, std::nullptr_t>;
template class NonUniqueUnorderedIndex<TypeGroupVertex, std::nullptr_t>;

View File

@ -1,115 +0,0 @@
#include "storage/indexes/impl/unique_ordered_index.hpp"
#include "database/db.hpp"
#include "database/db_accessor.hpp"
#include "database/db_transaction.hpp"
#include "storage/edge_accessor.hpp"
#include "storage/edge_record.hpp"
#include "storage/edge_type/edge_type.hpp"
#include "storage/label/label.hpp"
#include "storage/type_group_edge.hpp"
#include "storage/type_group_vertex.hpp"
#include "storage/vertex_accessor.hpp"
#include "storage/vertex_record.hpp"
#include "utils/iterator/iterator.hpp"
#include "storage/indexes/index_record.cpp"
template <class T, class K>
UniqueOrderedIndex<T, K>::UniqueOrderedIndex(IndexLocation loc, Order order)
: IndexBase<T, K>(IndexDefinition{loc, IndexType{true, order}},
"UniqueOrderedIndex")
{
}
template <class T, class K>
UniqueOrderedIndex<T, K>::UniqueOrderedIndex(IndexLocation loc, Order order,
tx::Transaction const &t)
: IndexBase<T, K>(IndexDefinition{loc, IndexType{true, order}},
t, "UniqueOrderedIndex")
{
}
template <class T, class K>
bool UniqueOrderedIndex<T, K>::insert(IndexRecord<T, K> &&value)
{
if (this->type().order == Descending) {
value.set_descending();
}
return set.access().insert(std::move(value)).second;
}
template <class T, class K>
iter::Virtual<const typename T::accessor_t>
UniqueOrderedIndex<T, K>::for_range(DbAccessor &t, Border<K> from, Border<K> to)
{
return iter::make_virtual(
for_range_exact(t, std::move(from), std::move(to)));
}
template <class T, class K>
auto UniqueOrderedIndex<T, K>::for_range_exact(DbAccessor &t_v,
Border<K> from_v, Border<K> to_v)
{
auto acc = set.access();
auto begin = acc.cbegin();
auto end = to_v;
// Sorted order must be checked
if (this->type().order == Ascending && from_v.key.is_present()) {
begin = acc.cfind_or_larger(from_v);
} else if (this->type().order == Descending && to_v.key.is_present()) {
// Order is descending so whe have to start from the end border and
// iterate to the from border.
begin = acc.cfind_or_larger(to_v);
end = from_v;
} else {
assert(this->type().order != None);
}
// TODO: determine size on fact of border size.
auto size = acc.size();
return iter::make_iterator(
[
it = std::move(begin), b_end = std::move(end), t = &t_v,
hold_acc = std::move(acc)
]() mutable->auto {
// UniqueOrderedIndex is smart so he has to iterate only through
// records which are inside borders. He knows that he will start
// with items larger than from_v but he needs to check if it has
// reached end border.
while (b_end >= it->key) {
const IndexRecord<T, K> &r = *it;
if (r.is_valid(t->db_transaction.trans)) {
// record r is inside borders and is valid for current
// transaction.
const typename T::accessor_t acc =
r.access(t->db_transaction);
it++;
return make_option(std::move(acc));
}
it++;
}
return Option<const typename T::accessor_t>();
},
size);
}
template <class T, class K>
void UniqueOrderedIndex<T, K>::clean(const Id &id)
{
auto acc = set.access();
for (auto ir : acc) {
if (ir.to_clean(id)) {
// TODO: Optimization, iterator with remove method.
acc.remove(ir);
}
}
}
template class UniqueOrderedIndex<TypeGroupEdge, std::nullptr_t>;
template class UniqueOrderedIndex<TypeGroupVertex, std::nullptr_t>;

View File

@ -1,39 +0,0 @@
#include "storage/indexes/index_base.hpp"
#include "storage/type_group_edge.hpp"
#include "storage/type_group_vertex.hpp"
#include "transactions/transaction.hpp"
template <class TG, class K>
IndexBase<TG, K>::IndexBase(IndexDefinition &&it, std::string&& logger_name)
: Loggable(std::forward<std::string>(logger_name)), it(it), created(Id(0)), active(true)
{
}
template <class TG, class K>
IndexBase<TG, K>::IndexBase(IndexDefinition &&it, const tx::Transaction &t, std::string&& logger_name)
: Loggable(std::forward<std::string>(logger_name)), it(it), created(t.id)
{
}
template <class TG, class K>
void IndexBase<TG, K>::activate()
{
assert(!can_read());
active.store(true);
}
template <class TG, class K>
bool IndexBase<TG, K>::can_read()
{
return active.load(std::memory_order_acquire);
}
template <class TG, class K>
bool IndexBase<TG, K>::is_obliged_to_insert(const tx::Transaction &t)
{
return t.id >= created;
}
template class IndexBase<TypeGroupEdge, std::nullptr_t>;
template class IndexBase<TypeGroupVertex, std::nullptr_t>;

View File

@ -1,71 +0,0 @@
#include "storage/indexes/index_holder.hpp"
#include "storage/type_group_edge.hpp"
#include "storage/type_group_vertex.hpp"
template <class TG, class K>
IndexBase<TG, K> *npr = (IndexBase<TG, K> *)nullptr;
template <class TG, class K>
bool IndexHolder<TG, K>::set_index(std::unique_ptr<IndexBase<TG, K>> inx)
{
if (index.compare_exchange_strong(npr<TG, K>, inx.get())) {
inx.release();
return true;
} else {
return false;
}
}
template <class TG, class K>
OptionPtr<IndexBase<TG, K>> IndexHolder<TG, K>::get_read() const
{
auto loaded = index.load(std::memory_order_acquire);
if (loaded == nullptr || !loaded->can_read()) {
return OptionPtr<IndexBase<TG, K>>();
} else {
return make_option_ptr(loaded);
}
}
template <class TG, class K>
OptionPtr<IndexBase<TG, K>>
IndexHolder<TG, K>::get_write(const tx::Transaction &t) const
{
auto loaded = index.load(std::memory_order_acquire);
if (loaded == nullptr || !loaded->is_obliged_to_insert(t)) {
return OptionPtr<IndexBase<TG, K>>();
} else {
return make_option_ptr(loaded);
}
}
template <class TG, class K>
Option<std::unique_ptr<IndexBase<TG, K>>>
IndexHolder<TG, K>::remove_index(IndexBase<TG, K> *expected)
{
if (index.compare_exchange_strong(expected, nullptr)) {
return make_option(std::unique_ptr<IndexBase<TG, K>>(expected));
} else {
return make_option(std::unique_ptr<IndexBase<TG, K>>());
}
}
template <class TG, class K>
Option<std::unique_ptr<IndexBase<TG, K>>> IndexHolder<TG, K>::remove_index()
{
auto removed = index.exchange(nullptr);
if (removed == nullptr) {
return make_option<std::unique_ptr<IndexBase<TG, K>>>();
} else {
return make_option(std::unique_ptr<IndexBase<TG, K>>(removed));
}
}
template class IndexHolder<TypeGroupEdge, std::nullptr_t>;
template class IndexHolder<TypeGroupVertex, std::nullptr_t>;

View File

@ -1,62 +0,0 @@
#include "storage/indexes/index_record.hpp"
#include "storage/type_group_edge.hpp"
#include "storage/type_group_vertex.hpp"
#include "transactions/transaction.hpp"
template <class TG, class K>
IndexRecord<TG, K>::IndexRecord(K key, typename TG::record_t *record,
typename TG::vlist_t *vlist)
: key(std::move(key)), record(record), vlist(vlist)
{
assert(record != nullptr);
assert(vlist != nullptr);
}
template <class TG, class K>
void IndexRecord<TG, K>::set_descending()
{
descending = true;
}
template <class TG, class K>
bool IndexRecord<TG, K>::empty() const
{
return record == nullptr;
}
template <class TG, class K>
bool IndexRecord<TG, K>::is_valid(tx::Transaction &t) const
{
assert(!empty());
// TODO: this has to be tested extensively
// before here was only (record == newest_record)
// but it doesn't work if single transaction updates something from
// this index and then tries to access to the same element again through
// the same index
auto newest_record = vlist->find(t);
if (!newest_record)
return false;
return (record == newest_record) || (newest_record->tx.cre() == t.id);
}
template <class TG, class K>
bool IndexRecord<TG, K>::to_clean(const Id &oldest_active) const
{
assert(!empty());
return record->is_deleted_before(oldest_active);
}
template <class TG, class K>
const auto IndexRecord<TG, K>::access(DbTransaction &db) const
{
return typename TG::accessor_t(record, vlist, db);
}
#include "storage/edge_accessor.hpp"
#include "storage/edge_record.hpp"
#include "storage/vertex_accessor.hpp"
#include "storage/vertex_record.hpp"
template class IndexRecord<TypeGroupVertex, std::nullptr_t>;
template class IndexRecord<TypeGroupEdge, std::nullptr_t>;

View File

@ -1,14 +0,0 @@
#include "storage/indexes/index_update.hpp"
template <>
IndexUpdate make_index_update(EdgeRecord *vlist, Edge *record)
{
return IndexUpdate{IndexUpdate::EDGE, .e = IndexUpdateEdge{vlist, record}};
}
template <>
IndexUpdate make_index_update(VertexRecord *vlist, Vertex *record)
{
return IndexUpdate{IndexUpdate::VERTEX,
.v = IndexUpdateVertex{vlist, record}};
}

View File

@ -1,140 +0,0 @@
#include "storage/indexes/indexes.hpp"
#include "database/db_accessor.hpp"
bool Indexes::add_index(IndexDefinition id)
{
auto logger = logging::log->logger("Add index");
logger.info("Starting");
// Closure which needs to be runned to finish creating index.
std::function<bool(DbTransaction &)> finish = [](auto &t) { return false; };
// Creates transaction and during it's creation adds index into it's
// place. Also creates finish closure which will add necessary elements
// into index.
DbTransaction t(db, db.tx_engine.begin([&](auto &t) mutable {
size_t code = id.loc.location_code();
switch (code) {
// Index over nothing
case 0: // Illegal location
break;
// Index over property
case 1: {
switch (id.loc.side) {
case EdgeSide: {
auto &holder = db.graph.edges
.property_family_find_or_create(
id.loc.property_name.get())
.index;
if (holder.set_index(
create_index<TypeGroupEdge, std::nullptr_t>(id, t))) {
// Set closure which will fill index.
finish = [&](auto &t) mutable {
DbAccessor acc(t.db, t.trans);
auto &key = acc.edge_property_family_get(
id.loc.property_name.get());
return fill_index(
t, holder,
acc.edge_access().fill().has_property(key).map(
[&](auto ra) {
return std::make_pair(std::move(ra),
std::nullptr_t());
}));
};
}
break;
}
case VertexSide: { // TODO: Duplicate code as above, only difference
// is vertices/vertex
auto &holder = db.graph.vertices
.property_family_find_or_create(
id.loc.property_name.get())
.index;
if (holder.set_index(
create_index<TypeGroupVertex, std::nullptr_t>(id, t))) {
// Set closure which will fill index.
finish = [&](auto &t) mutable {
DbAccessor acc(t.db, t.trans);
auto &key = acc.vertex_property_family_get(
id.loc.property_name.get());
return fill_index(
t, holder,
acc.vertex_access().fill().has_property(key).map(
[&](auto ra) {
return std::make_pair(std::move(ra),
std::nullptr_t());
}));
};
}
break;
}
default:
logger.error("Unkown side: " + std::to_string(id.loc.side));
};
break;
}
// Index over label
case 2: { // Always added
finish = [](auto &t) { return true; };
return;
}
// Index over property and label
case 3: { // Not yet implemented
logger.error("Remove of index over label and "
"property isn't yet implemented");
break;
}
// Index over edge_type
case 4: { // Always added
finish = [](auto &t) { return true; };
break;
}
// Index over property and edge_type
case 5: { // Not yet implemented
logger.error("Remove of index over edge_type and "
"property isn't yet implemented");
break;
}
// Index over edge_type and label
case 6: { // Not yet implemented
logger.error("Remove of index over edge_type and "
"label isn't yet implemented");
break;
}
// Index over property, edge_type and label
case 7: { // Not yet implemented
logger.error("Remove of index over label, edge_type "
"and property isn't yet implemented");
break;
}
default:
logger.error("Unkown index location code: " + std::to_string(code));
}
}));
if (finish(t)) {
t.trans.commit();
logger.info("Success");
return true;
} else {
t.trans.abort();
logger.info("Failed");
return false;
}
}

View File

@ -1,39 +0,0 @@
// #include "storage/indexes/impl/nonunique_unordered_index.hpp"
#include "storage/label/label.hpp"
Label::Label(const char *name)
: name(std::string(name)),
index_v(std::make_unique<label_index_t>(
IndexLocation{VertexSide, Option<std::string>(),
Option<std::string>(std::string(name))}))
{
}
bool operator<(const Label &lhs, const Label &rhs)
{
return lhs.name < rhs.name;
}
bool operator==(const Label &lhs, const Label &rhs)
{
return lhs.name == rhs.name;
}
bool operator<(const CharStr &lhs, const Label &rhs)
{
return lhs < rhs.char_str();
}
bool operator==(const CharStr &lhs, const Label &rhs)
{
return lhs == rhs.char_str();
}
std::ostream &operator<<(std::ostream &stream, const Label &label)
{
return stream << label.name;
}
Label::operator const std::string &() const { return name; }
Label::label_index_t &Label::index() const { return *index_v.get(); }

View File

@ -1,45 +0,0 @@
#include "storage/label/label_collection.hpp"
#include "storage/label/label.hpp"
bool LabelCollection::add(const Label &label)
{
if (has(label)) {
return false;
} else {
labels_.push_back(label_ref_t(label));
return true;
}
}
bool LabelCollection::has(const Label &label) const
{
for (auto l : labels_) {
if (l == label) {
return true;
}
}
return false;
}
size_t LabelCollection::count() const { return labels_.size(); }
bool LabelCollection::remove(const Label &label)
{
auto end = labels_.end();
for (auto it = labels_.begin(); it != end; it++) {
if (*it == label) {
labels_.erase(it);
return true;
}
}
return false;
}
void LabelCollection::clear() { labels_.clear(); }
const std::vector<label_ref_t> &LabelCollection::operator()() const
{
return labels_;
}

View File

@ -1,21 +0,0 @@
#include "storage/label/label_store.hpp"
LabelStore::store_t::Accessor LabelStore::access() { return labels.access(); }
const Label &LabelStore::find_or_create(const char *name)
{
auto accessor = labels.access();
auto it = accessor.find(CharStr(name));
if (it == accessor.end()) {
auto l = std::make_unique<Label>(name);
auto k = l->char_str();
it = accessor.insert(k, std::move(l)).first;
}
return *(it->second);
}
bool LabelStore::contains(const char *name) // const
{
auto accessor = labels.access();
return accessor.find(CharStr(name)) != accessor.end();
}

View File

@ -1,13 +0,0 @@
#include "storage/label/labels_writer.hpp"
#include "storage/label/label.hpp"
#include "utils/string_buffer.hpp"
template <typename Buffer>
void LabelsWriter<Buffer>::handle(const Label& label)
{
buffer_ << ':' << label.str();
}
// NOTE! template instantiations
template class LabelsWriter<utils::StringBuffer>;

View File

@ -1,11 +0,0 @@
#pragma once
#include "array.hpp"
#include "bool.hpp"
#include "integral.hpp"
#include "json.hpp"
#include "null.hpp"
#include "object.hpp"
#include "primitive.hpp"
#include "real.hpp"
#include "string.hpp"

View File

@ -1,81 +0,0 @@
#pragma once
#include <cassert>
#include <memory>
#include <vector>
#include "utilities/string/intercalate.hpp"
#include "json.hpp"
namespace json
{
class Array final : public Json
{
public:
Array() {}
template <typename It>
Array(It first, It last)
: elements(first, last) {}
Array(std::initializer_list<spJson> elements)
: elements(elements) {}
virtual bool is_array() const;
size_t size() const;
Array& push(const std::shared_ptr<Json>& element);
const spJson& operator[](size_t i) const;
spJson operator[](size_t i);
virtual operator std::string() const;
private:
std::vector<spJson> elements;
};
bool Array::is_array() const
{
return true;
}
size_t Array::size() const
{
return elements.size();
}
Array& Array::push(const spJson& element)
{
assert(element);
elements.push_back(element);
return *this;
}
const spJson& Array::operator[](size_t i) const
{
return elements[i];
}
spJson Array::operator[](size_t i)
{
return elements[i];
}
Array::operator std::string() const
{
std::vector<std::string> xs;
std::transform(elements.begin(), elements.end(), std::back_inserter(xs),
[](const spJson& element) {
return static_cast<std::string>(*element);
});
return "[" + utils::intercalate(xs.begin(), xs.end(), ",") + "]";
}
}

View File

@ -1,30 +0,0 @@
#pragma once
#include "primitive.hpp"
namespace json {
class Bool final : public Primitive<bool>
{
public:
Bool() {}
Bool(bool value)
: Primitive<bool>(value) {}
virtual bool is_boolean() const;
virtual operator std::string() const;
};
bool Bool::is_boolean() const
{
return true;
}
Bool::operator std::string() const
{
return value == true ? "true" : "false";
}
}

View File

@ -1,30 +0,0 @@
#pragma once
#include "primitive.hpp"
namespace json {
class Integral final : public Primitive<int64_t>
{
public:
Integral() {}
Integral(int64_t value)
: Primitive<int64_t>(value) {}
virtual bool is_integral() const;
virtual operator std::string() const;
};
bool Integral::is_integral() const
{
return true;
}
Integral::operator std::string() const
{
return std::to_string(value);
}
}

View File

@ -1,44 +0,0 @@
#pragma once
#include <initializer_list>
#include <string>
#include <memory>
namespace json {
class Json;
typedef std::shared_ptr<Json> spJson;
class Json
{
public:
Json() {}
virtual ~Json() {}
virtual bool is_object() const { return false; }
virtual bool is_array() const { return false; }
virtual bool is_real() const { return false; }
virtual bool is_integral() const { return false; }
virtual bool is_boolean() const { return false; }
virtual bool is_null() const { return false; }
template <typename T> T& as();
template <typename T> const T& as() const;
virtual operator std::string() const = 0;
};
template <typename T>
T& Json::as()
{
return *dynamic_cast<T*>(this);
}
template <typename T>
const T& Json::as() const
{
return *dynamic_cast<T*>(this);
}
}

View File

@ -1,27 +0,0 @@
#pragma once
#include "json.hpp"
namespace json {
class Null final : public Json
{
public:
Null() {}
virtual bool is_null() const;
virtual operator std::string() const;
};
bool Null::is_null() const
{
return true;
}
Null::operator std::string() const
{
return "null";
}
}

View File

@ -1,103 +0,0 @@
#pragma once
#include <iostream>
#include <functional>
#include <sstream>
#include <cassert>
#include <vector>
#include <map>
#include "utilities/string/intercalate.hpp"
#include "json.hpp"
namespace json {
typedef std::pair<const std::string, spJson> const_kv_pair_t;
typedef std::pair<std::string, spJson> kv_pair_t;
class Object;
typedef std::shared_ptr<Object> spObject;
class Object : public Json
{
public:
Object() {}
Object(std::initializer_list<const_kv_pair_t> elements)
: props(elements) {}
virtual bool is_object() const;
const spJson& at(const std::string& key) const;
spJson at(const std::string& key);
const spJson& operator[](const std::string& key) const;
spJson operator[](const std::string& key);
Object& put(const std::string& key, spJson value);
Object& operator<<(const kv_pair_t& kv_pair);
virtual operator std::string() const;
protected:
std::map<std::string, spJson> props;
};
bool Object::is_object() const
{
return true;
}
const spJson& Object::at(const std::string& key) const
{
return props.at(key);
}
spJson Object::at(const std::string& key)
{
return props.at(key);
}
const spJson& Object::operator[](const std::string& key) const
{
return this->at(key);
}
spJson Object::operator[](const std::string& key)
{
return this->at(key);
}
Object& Object::put(const std::string& key, spJson value)
{
assert(value);
props[key] = value;
return *this;
}
Object& Object::operator<<(const kv_pair_t& kv_pair)
{
return this->put(std::get<0>(kv_pair), std::get<1>(kv_pair));
}
Object::operator std::string() const
{
if(props.empty())
return "{}";
std::vector<std::string> xs;
std::transform(props.begin(), props.end(), std::back_inserter(xs),
[](const kv_pair_t& kvp) {
return "\"" + kvp.first + "\":" + static_cast<std::string>(*kvp.second);
});
return "{" + utils::intercalate(xs.begin(), xs.end(), ",") + "}";
}
}

View File

@ -1,26 +0,0 @@
#pragma once
#include "json.hpp"
namespace json {
template <class T>
class Primitive : public Json
{
public:
Primitive() {}
Primitive(const T& value)
: value(value) {}
T get() const { return value; }
void set(T value) { this->value = value; }
operator T() const { return this->get(); }
protected:
T value;
};
}

View File

@ -1,30 +0,0 @@
#pragma once
#include "primitive.hpp"
namespace json {
class Real final : public Primitive<float>
{
public:
Real() {}
Real(float value)
: Primitive<float>(value) {}
virtual bool is_real() const;
virtual operator std::string() const;
};
bool Real::is_real() const
{
return true;
}
Real::operator std::string() const
{
return std::to_string(value);
}
}

View File

@ -1,31 +0,0 @@
#pragma once
#include "primitive.hpp"
namespace json
{
class String final : public Primitive<std::string>
{
public:
String() {}
String(const std::string& value)
: Primitive<std::string>(value) {}
virtual bool is_string() const;
virtual operator std::string() const;
};
bool String::is_string() const
{
return true;
}
String::operator std::string() const
{
return "\"" + value + "\"";
}
}

View File

@ -1,24 +0,0 @@
#include "storage/record_accessor.hpp"
#include "storage/edge_accessor.hpp"
#include "storage/edge_record.hpp"
#include "storage/vertex_accessor.hpp"
#include "storage/vertex_record.hpp"
// template <class T, class Derived>
// template <class V>
// auto RecordAccessor<T, Derived>::at(type_key_t<T, V> &key) const
// {
// return properties().template at<V>(key);
// }
template <class T, class Derived>
void RecordAccessor<T, Derived>::remove() const
{
assert(!empty());
vlist->remove(record, db.trans);
}
template class RecordAccessor<TypeGroupEdge, EdgeAccessor>;
template class RecordAccessor<TypeGroupVertex, VertexAccessor>;

View File

@ -3,7 +3,7 @@
#include <cmath>
#include <fmt/format.h>
#include "storage/model/typed_value.hpp"
#include "storage/typed_value.hpp"
#include "utils/assert.hpp"
// Value extraction template instantiations

View File

@ -1,6 +1,6 @@
#include <algorithm>
#include "storage/model/typed_value_store.hpp"
#include "storage/typed_value_store.hpp"
const TypedValue& TypedValueStore::at(const TKey &key) const {
for (const auto& kv : props_)

View File

@ -1,81 +1,50 @@
#include "storage/edge_accessor.hpp"
#include "storage/vertex_accessor.hpp"
#include "database/db.hpp"
#include "storage/vertex_record.hpp"
#include "storage/vertices.hpp"
#include "utils/iterator/iterator.hpp"
bool VertexAccessor::isolated() const
{
return out_degree() == 0 && in_degree() == 0;
size_t VertexAccessor::out_degree() const {
return this->record_->out_.size();
}
size_t VertexAccessor::out_degree() const
{
return this->record->data.out.degree();
size_t VertexAccessor::in_degree() const {
return this->record_->in_.size();
}
size_t VertexAccessor::in_degree() const
{
return this->record->data.in.degree();
bool VertexAccessor::add_label(GraphDb::Label label) {
return this->record_->labels_.emplace(label).second;
}
size_t VertexAccessor::degree() const { return in_degree() + out_degree(); }
bool VertexAccessor::add_label(const Label &label)
{
// update vertex
return this->record->data.labels.add(label);
size_t VertexAccessor::remove_label(GraphDb::Label label) {
return this->record_->labels_.erase(label);
}
bool VertexAccessor::remove_label(const Label &label)
{
// update vertex
return this->record->data.labels.remove(label);
bool VertexAccessor::has_label(GraphDb::Label label) const {
auto &label_set = this->record_->labels_;
return label_set.find(label) != label_set.end();
}
bool VertexAccessor::has_label(const Label &label) const
{
return this->record->data.labels.has(label);
const std::set<GraphDb::Label> &VertexAccessor::labels() const {
return this->record_->labels_;
}
const std::vector<label_ref_t> &VertexAccessor::labels() const
{
return this->record->data.labels();
bool VertexAccessor::remove() const {
// TODO consider if this works well with MVCC
if (out_degree() > 0 || in_degree() > 0)
return false;
vlist_->remove(record_, db_trans_.trans);
return true;
}
bool VertexAccessor::in_contains(VertexAccessor const &other) const
{
return record->data.in.contains(other.vlist);
void VertexAccessor::detach_remove() const {
// removing edges via accessors is both safe
// and it should remove all the pointers in the relevant
// vertices (including this one)
for (auto edge_vlist : record_->out_)
EdgeAccessor(edge_vlist, db_trans_).remove();
for (auto edge_vlist : record_->in_)
EdgeAccessor(edge_vlist, db_trans_).remove();
vlist_->remove(record_, db_trans_.trans);
}
void VertexAccessor::remove() const
{
RecordAccessor::remove();
// Detach all out edges.
for (auto evr : record->data.out) {
auto ea = EdgeAccessor(evr, db);
// Delete edge
ea.vlist->remove(db.trans);
// Remove edge from it's to vertex.
auto to_v = ea.to();
to_v.fill();
to_v.update().record->data.in.remove(ea.vlist);
}
// Detach all in edges.
for (auto evr : record->data.in) {
auto ea = EdgeAccessor(evr, db);
// Delete edge
ea.vlist->remove(db.trans);
// Remove edge from it's from vertex.
auto from_v = ea.from();
from_v.fill();
from_v.update().record->data.out.remove(ea.vlist);
}
}

View File

@ -1,56 +0,0 @@
#include "storage/vertices.hpp"
#include "storage/vertex_accessor.hpp"
#include "utils/iterator/iterator.hpp"
Vertices::vertices_t::Accessor Vertices::access() { return vertices.access(); }
Option<const VertexAccessor> Vertices::find(DbTransaction &t, const Id &id)
{
auto vertices_accessor = vertices.access();
auto vertices_iterator = vertices_accessor.find(id);
if (vertices_iterator == vertices_accessor.end())
return make_option<const VertexAccessor>();
return make_option_const(VertexAccessor(&vertices_iterator->second, t));
}
VertexAccessor Vertices::insert(DbTransaction &t)
{
// get next vertex id
auto next = counter.next();
// create new vertex record
VertexRecord vertex_record(next);
auto vertex = vertex_record.insert(t.trans);
// insert the new vertex record into the vertex store
auto vertices_accessor = vertices.access();
auto result = vertices_accessor.insert(next, std::move(vertex_record));
// create new vertex
auto inserted_vertex_record = result.first;
t.to_update_index<TypeGroupVertex>(&inserted_vertex_record->second, vertex);
return VertexAccessor(vertex, &inserted_vertex_record->second, t);
}
Vertices::prop_familys_t::Accessor Vertices::property_family_access()
{
return prop_familys.access();
}
VertexPropertyFamily &
Vertices::property_family_find_or_create(const std::string &name)
{
auto acc = prop_familys.access();
auto it = acc.find(name);
if (it == acc.end()) {
auto family = std::unique_ptr<VertexPropertyFamily>(
new VertexPropertyFamily(name));
auto res = acc.insert(name, std::move(family));
it = res.first;
}
return *(it->second);
}

View File

@ -10,8 +10,8 @@
#include "communication/bolt/v1/serialization/bolt_serializer.hpp"
#include "communication/bolt/v1/serialization/record_stream.hpp"
#include "database/db.hpp"
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "database/graph_db.hpp"
#include "database/db_accessor.hpp"
#include "database/db_accessor.hpp"
#include "io/network/socket.hpp"

View File

@ -1,5 +1,5 @@
#include "communication/bolt/v1/serialization/bolt_serializer.hpp"
#include "database/db.hpp"
#include "database/graph_db.hpp"
#include "logging/default.hpp"
#include "logging/streams/stdout.hpp"
#include "_hardcoded_query/basic.hpp"