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:
parent
029a3ff09b
commit
b374ae1dbb
CMakeLists.txt
cmake
include
data_structures/concurrent
database
dbms
mvcc
query
snapshot
storage
common.hppedge.hppedge_accessor.hppedge_record.hpp
edge_type
edge_x_vertex.hppedges.hppindexes
impl
index_base.hppindex_definition.hppindex_holder.hppindex_record.hppindex_update.hppindexes.hppkeys
iterator
label
model
record_accessor.hpptype_group_edge.hpptype_group_vertex.hpptyped_value.hpptyped_value_store.hpptyped_value_utils.hvertex.hppvertex_accessor.hppvertex_record.hppvertices.hpputils
poc
src
database
memgraph_http.cppstorage
tests/integration
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
};
|
||||
|
17
include/database/creation_exception.hpp
Normal file
17
include/database/creation_exception.hpp
Normal 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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
};
|
@ -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"
|
||||
|
112
include/database/graph_db.hpp
Normal file
112
include/database/graph_db.hpp
Normal 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;
|
||||
};
|
||||
|
24
include/database/graph_db_accessor.hpp
Normal file
24
include/database/graph_db_accessor.hpp
Normal 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:
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "database/db.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "threading/thread.hpp"
|
||||
|
||||
class Thread;
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "database/db.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "logging/default.hpp"
|
||||
#include "threading/thread.hpp"
|
||||
|
||||
|
@ -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"
|
@ -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_;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
@ -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>;
|
@ -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;
|
||||
};
|
@ -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); });
|
||||
}
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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};
|
||||
};
|
@ -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;
|
||||
};
|
@ -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};
|
||||
};
|
@ -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};
|
||||
};
|
@ -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);
|
@ -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;
|
||||
};
|
@ -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:
|
||||
};
|
@ -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;
|
||||
};
|
@ -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>>;
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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));
|
||||
}
|
@ -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>;
|
@ -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_;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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_;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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};
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "storage/model/properties/properties.hpp"
|
||||
|
||||
template <class TG>
|
||||
class PropertyModel
|
||||
{
|
||||
public:
|
||||
Properties<TG> props;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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_;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
@ -6,7 +6,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
#include "storage/model/typed_value_store.hpp"
|
||||
#include "storage/typed_value_store.hpp"
|
||||
|
||||
|
||||
/**
|
@ -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_;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)) {}
|
||||
};
|
@ -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;
|
||||
};
|
22
include/utils/pass_key.hpp
Normal file
22
include/utils/pass_key.hpp
Normal 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() {}
|
||||
};
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "database/db.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "database/db_accessor.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
@ -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_; }
|
@ -1,4 +1,4 @@
|
||||
#include "database/db.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "database/db_accessor.hpp"
|
||||
|
||||
DbAccessor::DbAccessor(Db &db)
|
||||
|
@ -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
77
src/database/graph_db.cpp
Normal 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);
|
||||
}
|
||||
`
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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(); }
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -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>;
|
@ -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>;
|
@ -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>;
|
@ -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>;
|
@ -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>;
|
@ -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}};
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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(); }
|
@ -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_;
|
||||
}
|
@ -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();
|
||||
}
|
@ -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>;
|
@ -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"
|
@ -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(), ",") + "]";
|
||||
}
|
||||
|
||||
}
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
@ -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(), ",") + "}";
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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 + "\"";
|
||||
}
|
||||
|
||||
}
|
@ -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>;
|
@ -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
|
@ -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_)
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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"
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user