EdgeType indexes added.
Implemented untested UniqueOrderedIndex. Introduced TypeGroupEdge/Vertex into database. Added Index capabilityes to PropertyFamily. Added method for adding index. Added method for removing index.
This commit is contained in:
parent
85dbf1bd86
commit
8a89f6601d
@ -429,8 +429,14 @@ set(memgraph_src_files
|
||||
${src_dir}/storage/model/properties/array.cpp
|
||||
${src_dir}/storage/model/properties/properties.cpp
|
||||
${src_dir}/storage/model/properties/property_family.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/locking/record_lock.cpp
|
||||
${src_dir}/storage/garbage/garbage.cpp
|
||||
${src_dir}/storage/vertex_accessor.cpp
|
||||
${src_dir}/transactions/transaction.cpp
|
||||
${src_dir}/template_engine/engine.cpp
|
||||
@ -442,6 +448,7 @@ set(memgraph_src_files
|
||||
${src_dir}/logging/log.cpp
|
||||
${src_dir}/io/network/tls.cpp
|
||||
${src_dir}/database/db.cpp
|
||||
${src_dir}/database/db_transaction.cpp
|
||||
${src_dir}/database/db_accessor.cpp
|
||||
${src_dir}/storage/edge_accessor.cpp
|
||||
${src_dir}/storage/record_accessor.cpp
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
* }
|
||||
*
|
||||
*/
|
||||
void write(const Vertex::Accessor &vertex)
|
||||
void write(const VertexAccessor &vertex)
|
||||
{
|
||||
// write signatures for the node struct and node data type
|
||||
encoder.write_struct_header(3);
|
||||
@ -72,7 +72,7 @@ public:
|
||||
* }
|
||||
*
|
||||
*/
|
||||
void write(const Edge::Accessor &edge)
|
||||
void write(const EdgeAccessor &edge)
|
||||
{
|
||||
// write signatures for the edge struct and edge data type
|
||||
encoder.write_struct_header(5);
|
||||
|
@ -78,8 +78,8 @@ public:
|
||||
}
|
||||
// -- BOLT SPECIFIC METHODS -----------------------------------------------
|
||||
|
||||
void write(const Vertex::Accessor &vertex) { serializer.write(vertex); }
|
||||
void write(const Edge::Accessor &edge) { serializer.write(edge); }
|
||||
void write(const VertexAccessor &vertex) { serializer.write(vertex); }
|
||||
void write(const EdgeAccessor &edge) { serializer.write(edge); }
|
||||
|
||||
void write(const Property &prop) { serializer.write(prop); }
|
||||
void write(const Bool& prop) { serializer.write(prop); }
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include "utils/crtp.hpp"
|
||||
|
||||
template <class T>
|
||||
|
@ -8,53 +8,66 @@ using std::pair;
|
||||
template <typename K, typename T>
|
||||
class ConcurrentMap
|
||||
{
|
||||
typedef Item<K, T> item_t;
|
||||
typedef SkipList<item_t> list;
|
||||
typedef typename SkipList<item_t>::Iterator list_it;
|
||||
typedef typename SkipList<item_t>::ConstIterator list_it_con;
|
||||
|
||||
public:
|
||||
ConcurrentMap() {}
|
||||
|
||||
class Accessor : public AccessorBase<item_t>
|
||||
{
|
||||
friend class ConcurrentMap;
|
||||
|
||||
using AccessorBase<item_t>::AccessorBase;
|
||||
|
||||
private:
|
||||
using AccessorBase<item_t>::accessor;
|
||||
typedef Item<K, T> item_t;
|
||||
typedef SkipList<item_t> list;
|
||||
typedef typename SkipList<item_t>::Iterator list_it;
|
||||
typedef typename SkipList<item_t>::ConstIterator list_it_con;
|
||||
|
||||
public:
|
||||
std::pair<list_it, bool> insert(const K &key, const T &data)
|
||||
ConcurrentMap() {}
|
||||
|
||||
class Accessor : public AccessorBase<item_t>
|
||||
{
|
||||
return accessor.insert(item_t(key, data));
|
||||
}
|
||||
friend class ConcurrentMap;
|
||||
|
||||
std::pair<list_it, bool> insert(const K &key, T &&data)
|
||||
{
|
||||
return accessor.insert(item_t(key, std::forward<T>(data)));
|
||||
}
|
||||
using AccessorBase<item_t>::AccessorBase;
|
||||
|
||||
std::pair<list_it, bool> insert(K &&key, T &&data)
|
||||
{
|
||||
return accessor.insert(
|
||||
item_t(std::forward<K>(key), std::forward<T>(data)));
|
||||
}
|
||||
private:
|
||||
using AccessorBase<item_t>::accessor;
|
||||
|
||||
list_it_con find(const K &key) const { return accessor.find(key); }
|
||||
public:
|
||||
std::pair<list_it, bool> insert(const K &key, const T &data)
|
||||
{
|
||||
return accessor.insert(item_t(key, data));
|
||||
}
|
||||
|
||||
list_it find(const K &key) { return accessor.find(key); }
|
||||
std::pair<list_it, bool> insert(const K &key, T &&data)
|
||||
{
|
||||
return accessor.insert(item_t(key, std::forward<T>(data)));
|
||||
}
|
||||
|
||||
bool contains(const K &key) const { return this->find(key) != this->end(); }
|
||||
std::pair<list_it, bool> insert(K &&key, T &&data)
|
||||
{
|
||||
return accessor.insert(
|
||||
item_t(std::forward<K>(key), std::forward<T>(data)));
|
||||
}
|
||||
|
||||
bool remove(const K &key) { return accessor.remove(key); }
|
||||
};
|
||||
list_it_con find(const K &key) const { return accessor.find(key); }
|
||||
|
||||
Accessor access() { return Accessor(&skiplist); }
|
||||
list_it find(const K &key) { return accessor.find(key); }
|
||||
|
||||
const Accessor access() const { return Accessor(&skiplist); }
|
||||
list_it_con find_or_larger(const T &item) const
|
||||
{
|
||||
return accessor.find_or_larger(item);
|
||||
}
|
||||
|
||||
private:
|
||||
list skiplist;
|
||||
list_it find_or_larger(const T &item)
|
||||
{
|
||||
return accessor.find_or_larger(item);
|
||||
}
|
||||
|
||||
bool contains(const K &key) const
|
||||
{
|
||||
return this->find(key) != this->end();
|
||||
}
|
||||
|
||||
bool remove(const K &key) { return accessor.remove(key); }
|
||||
};
|
||||
|
||||
Accessor access() { return Accessor(&skiplist); }
|
||||
|
||||
const Accessor access() const { return Accessor(&skiplist); }
|
||||
|
||||
private:
|
||||
list skiplist;
|
||||
};
|
||||
|
@ -53,6 +53,16 @@ public:
|
||||
|
||||
list_it find(const K &key) { return accessor.find(key); }
|
||||
|
||||
list_it_con find_or_larger(const T &item) const
|
||||
{
|
||||
return accessor.find_or_larger(item);
|
||||
}
|
||||
|
||||
list_it find_or_larger(const T &item)
|
||||
{
|
||||
return accessor.find_or_larger(item);
|
||||
}
|
||||
|
||||
bool contains(const K &key) const
|
||||
{
|
||||
return this->find(key) != this->end();
|
||||
|
@ -5,46 +5,59 @@
|
||||
template <class T>
|
||||
class ConcurrentMultiSet
|
||||
{
|
||||
typedef SkipList<T> list;
|
||||
typedef typename SkipList<T>::Iterator list_it;
|
||||
typedef typename SkipList<T>::ConstIterator list_it_con;
|
||||
|
||||
public:
|
||||
ConcurrentMultiSet() {}
|
||||
|
||||
class Accessor : public AccessorBase<T>
|
||||
{
|
||||
friend class ConcurrentMultiSet;
|
||||
|
||||
using AccessorBase<T>::AccessorBase;
|
||||
|
||||
private:
|
||||
using AccessorBase<T>::accessor;
|
||||
typedef SkipList<T> list;
|
||||
typedef typename SkipList<T>::Iterator list_it;
|
||||
typedef typename SkipList<T>::ConstIterator list_it_con;
|
||||
|
||||
public:
|
||||
list_it insert(const T &item) { return accessor.insert_non_unique(item); }
|
||||
ConcurrentMultiSet() {}
|
||||
|
||||
list_it insert(T &&item)
|
||||
class Accessor : public AccessorBase<T>
|
||||
{
|
||||
return accessor.insert_non_unique(std::forward<T>(item));
|
||||
}
|
||||
friend class ConcurrentMultiSet;
|
||||
|
||||
list_it_con find(const T &item) const { return accessor.find(item); }
|
||||
using AccessorBase<T>::AccessorBase;
|
||||
|
||||
list_it find(const T &item) { return accessor.find(item); }
|
||||
private:
|
||||
using AccessorBase<T>::accessor;
|
||||
|
||||
bool contains(const T &item) const
|
||||
{
|
||||
return this->find(item) != this->end();
|
||||
}
|
||||
public:
|
||||
list_it insert(const T &item)
|
||||
{
|
||||
return accessor.insert_non_unique(item);
|
||||
}
|
||||
|
||||
bool remove(const T &item) { return accessor.remove(item); }
|
||||
};
|
||||
list_it insert(T &&item)
|
||||
{
|
||||
return accessor.insert_non_unique(std::forward<T>(item));
|
||||
}
|
||||
|
||||
Accessor access() { return Accessor(&skiplist); }
|
||||
list_it_con find(const T &item) const { return accessor.find(item); }
|
||||
|
||||
const Accessor access() const { return Accessor(&skiplist); }
|
||||
list_it find(const T &item) { return accessor.find(item); }
|
||||
|
||||
private:
|
||||
list skiplist;
|
||||
list_it_con find_or_larger(const T &item) const
|
||||
{
|
||||
return accessor.find_or_larger(item);
|
||||
}
|
||||
|
||||
list_it find_or_larger(const T &item)
|
||||
{
|
||||
return accessor.find_or_larger(item);
|
||||
}
|
||||
|
||||
bool contains(const T &item) const
|
||||
{
|
||||
return this->find(item) != this->end();
|
||||
}
|
||||
|
||||
bool remove(const T &item) { return accessor.remove(item); }
|
||||
};
|
||||
|
||||
Accessor access() { return Accessor(&skiplist); }
|
||||
|
||||
const Accessor access() const { return Accessor(&skiplist); }
|
||||
|
||||
private:
|
||||
list skiplist;
|
||||
};
|
||||
|
@ -37,6 +37,24 @@ public:
|
||||
|
||||
list_it find(const T &item) { return accessor.find(item); }
|
||||
|
||||
template <class K>
|
||||
list_it_con find_or_larger(const K &item) const
|
||||
{
|
||||
return accessor.find_or_larger(item);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
list_it find_or_larger(const K &item)
|
||||
{
|
||||
return accessor.find_or_larger(item);
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -556,6 +556,19 @@ public:
|
||||
return skiplist->find(item);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
ConstIterator find_or_larger(const K &item) const
|
||||
{
|
||||
return static_cast<const SkipList &>(*skiplist).find_or_larger(
|
||||
item);
|
||||
}
|
||||
|
||||
template <class It, class K>
|
||||
It find_or_larger(const K &item)
|
||||
{
|
||||
return skiplist->find_or_larger<It, K>(item);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
bool contains(const K &item) const
|
||||
{
|
||||
@ -637,6 +650,18 @@ private:
|
||||
|
||||
template <class It, class K>
|
||||
It find_node(const K &item)
|
||||
{
|
||||
auto it = find_or_larger<It, K>(item);
|
||||
if (it.node == nullptr || item == *it) {
|
||||
return std::move(it);
|
||||
} else {
|
||||
return It();
|
||||
}
|
||||
}
|
||||
|
||||
// Returns iterator on searched element or the first larger element.
|
||||
template <class It, class K>
|
||||
It find_or_larger(const K &item)
|
||||
{
|
||||
Node *node, *pred = header;
|
||||
int h = static_cast<int>(pred->height) - 1;
|
||||
@ -647,7 +672,7 @@ private:
|
||||
}
|
||||
|
||||
// if we overshoot at every layer, item doesn't exist
|
||||
if (h < 0) return It();
|
||||
if (h < 0) return It(node);
|
||||
|
||||
// the item is farther to the right, continue going right as long
|
||||
// as the key is greater than the current node's key
|
||||
|
@ -1,5 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "storage/type_group_edge.hpp"
|
||||
#include "storage/type_group_vertex.hpp"
|
||||
|
||||
#include "storage/garbage/garbage.hpp"
|
||||
#include "storage/graph.hpp"
|
||||
#include "transactions/engine.hpp"
|
||||
|
||||
@ -14,9 +18,24 @@ public:
|
||||
|
||||
Graph graph;
|
||||
tx::Engine tx_engine;
|
||||
Garbage garbage;
|
||||
|
||||
std::string &name();
|
||||
|
||||
// INDEXES
|
||||
|
||||
// TG - type group
|
||||
// I - type of function I:const tx::Transaction& ->
|
||||
// std::unique_ptr<IndexBase<TypeGroupVertex,std::nullptr_t>>
|
||||
// G - type of collection (verrtex/edge)
|
||||
template <class TG, class I, class G>
|
||||
bool create_index_on_vertex_property_family(const char *name, G &coll,
|
||||
I &create_index);
|
||||
|
||||
// Removes index IndexHolder. True if there was index to remove.
|
||||
template <class TG, class K>
|
||||
bool remove_index(IndexHolder<TG, K> &ih);
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
};
|
||||
|
@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "database/db_transaction.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
#include "utils/border.hpp"
|
||||
// #include "utils/iterator/iterator.hpp"
|
||||
#include "utils/option.hpp"
|
||||
|
||||
namespace tx
|
||||
@ -11,23 +10,29 @@ namespace tx
|
||||
class Transaction;
|
||||
}
|
||||
|
||||
class Label;
|
||||
class EdgeType;
|
||||
|
||||
using EdgePropertyFamily = PropertyFamily<TypeGroupEdge>;
|
||||
using VertexPropertyFamily = PropertyFamily<TypeGroupVertex>;
|
||||
|
||||
/*
|
||||
* DbAccessor
|
||||
* -Guarantees that access to Vertex and Edge is possible only through
|
||||
* Vertex::Accessor and Edge::Accessor.
|
||||
* VertexAccessor and EdgeAccessor.
|
||||
* -Guarantees that changing Vertex and Edge is possible only using
|
||||
* Vertex::Accessor returned by vertex_insert() method and
|
||||
* Edge::Accessor returned by edge_insert() method.
|
||||
* VertexAccessor returned by vertex_insert() method and
|
||||
* EdgeAccessor returned by edge_insert() method.
|
||||
* -Offers CRUD for Vertex and Edge except iterating over all edges.
|
||||
*
|
||||
* Vertex::Accessor
|
||||
* VertexAccessor
|
||||
* By default Vertex::accessor is empty. Caller has to call fill() method
|
||||
* to fetch valid data and check it's return value. fill() method returns
|
||||
* true if there is valid data for current transaction false otherwise.
|
||||
* Only exception to this rule is vertex_insert() method in DbAccessor
|
||||
* which returns by default filled Vertex::Accessor.
|
||||
* which returns by default filled VertexAccessor.
|
||||
*
|
||||
* Edge::Accessor
|
||||
* EdgeAccessor
|
||||
* By default Edge::accessor is empty. Caller has to call fill() method
|
||||
* to
|
||||
* fetch valid data and check it's return value. fill() method returns
|
||||
@ -35,7 +40,7 @@ class Transaction;
|
||||
* if there is valid data for current transaction false otherwise.
|
||||
* Only exception to this rule is edge_insert() method in DbAccessor
|
||||
* which
|
||||
* returns by default filled Edge::Accessor.
|
||||
* returns by default filled EdgeAccessor.
|
||||
*/
|
||||
class DbAccessor
|
||||
{
|
||||
@ -43,22 +48,24 @@ class DbAccessor
|
||||
public:
|
||||
DbAccessor(Db &db);
|
||||
|
||||
DbAccessor(Db &db, tx::Transaction &t);
|
||||
|
||||
//*******************VERTEX METHODS
|
||||
|
||||
auto vertex_access();
|
||||
|
||||
Option<const Vertex::Accessor> vertex_find(const Id &id);
|
||||
Option<const VertexAccessor> vertex_find(const Id &id);
|
||||
|
||||
// Creates new Vertex and returns filled Vertex::Accessor.
|
||||
Vertex::Accessor vertex_insert();
|
||||
// Creates new Vertex and returns filled VertexAccessor.
|
||||
VertexAccessor vertex_insert();
|
||||
|
||||
// ******************* EDGE METHODS
|
||||
|
||||
Option<const Edge::Accessor> edge_find(const Id &id);
|
||||
Option<const EdgeAccessor> edge_find(const Id &id);
|
||||
|
||||
// Creates new Edge and returns filled Edge::Accessor.
|
||||
Edge::Accessor edge_insert(Vertex::Accessor const &from,
|
||||
Vertex::Accessor const &to);
|
||||
// Creates new Edge and returns filled EdgeAccessor.
|
||||
EdgeAccessor edge_insert(VertexAccessor const &from,
|
||||
VertexAccessor const &to);
|
||||
|
||||
// ******************* LABEL METHODS
|
||||
|
||||
@ -74,25 +81,37 @@ public:
|
||||
|
||||
// ******************** PROPERTY METHODS
|
||||
|
||||
PropertyFamily &vertex_property_family_get(const std::string &name);
|
||||
VertexPropertyFamily &vertex_property_family_get(const std::string &name);
|
||||
|
||||
PropertyFamily &edge_property_family_get(const std::string &name);
|
||||
EdgePropertyFamily &edge_property_family_get(const std::string &name);
|
||||
|
||||
// ******************** PROPERTY HELPER METHODS
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey
|
||||
VertexPropertyFamily::PropertyType::PropertyFamilyKey
|
||||
vertex_property_key(const std::string &name, Type type);
|
||||
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey
|
||||
EdgePropertyFamily::PropertyType::PropertyFamilyKey
|
||||
edge_property_key(const std::string &name, Type type);
|
||||
|
||||
template <class T>
|
||||
VertexPropertyFamily::PropertyType::PropertyTypeKey<T>
|
||||
vertex_property_key(const std::string &name);
|
||||
|
||||
template <class T>
|
||||
EdgePropertyFamily::PropertyType::PropertyTypeKey<T>
|
||||
edge_property_key(const std::string &name);
|
||||
|
||||
// ******************** TRANSACTION METHODS
|
||||
|
||||
void commit();
|
||||
// True if commit was successful, or false if transaction was aborted.
|
||||
bool commit();
|
||||
void abort();
|
||||
|
||||
private:
|
||||
// TODO: make this friend generic for all indexes.
|
||||
template <class T, class K>
|
||||
friend class NonUniqueUnorderedIndex;
|
||||
template <class T, class K>
|
||||
friend class UniqueOrderedIndex;
|
||||
|
||||
DbTransaction db_transaction;
|
||||
};
|
||||
|
@ -1,10 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "storage/indexes/index_update.hpp"
|
||||
#include "transactions/transaction.hpp"
|
||||
|
||||
class Db;
|
||||
class DbAccessor;
|
||||
|
||||
using index_updates_t = std::vector<IndexUpdate>;
|
||||
|
||||
// Inner structures local to transaction can hold ref to this structure and use
|
||||
// its methods.
|
||||
// Also serves as a barrier for calling methods defined public but meant for
|
||||
@ -21,6 +24,21 @@ public:
|
||||
// This should provide cleaner hierarchy of operations on database.
|
||||
// For example cleaner.
|
||||
|
||||
// Updates indexes of Vertex/Edges in index_updates. True if indexes are
|
||||
// updated successfully. False means that transaction failed.
|
||||
bool update_indexes();
|
||||
|
||||
// Will update indexes for given element TG::record_t. Actual update happens
|
||||
// with call update_indexes
|
||||
template <class TG>
|
||||
void to_update_index(typename TG::vlist_t *vlist,
|
||||
typename TG::record_t *record)
|
||||
{
|
||||
index_updates.push_back(make_index_update(vlist, record));
|
||||
}
|
||||
|
||||
index_updates_t index_updates;
|
||||
|
||||
tx::Transaction &trans;
|
||||
|
||||
Db &db;
|
||||
|
@ -3,14 +3,14 @@
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
|
||||
#include "transactions/transaction.hpp"
|
||||
#include "transactions/commit_log.hpp"
|
||||
#include "transactions/engine.hpp"
|
||||
#include "transactions/transaction.hpp"
|
||||
|
||||
#include "mvcc/id.hpp"
|
||||
#include "mvcc/cre_exp.hpp"
|
||||
#include "mvcc/version.hpp"
|
||||
#include "mvcc/hints.hpp"
|
||||
#include "mvcc/id.hpp"
|
||||
#include "mvcc/version.hpp"
|
||||
#include "storage/locking/record_lock.hpp"
|
||||
|
||||
// the mvcc implementation used here is very much like postgresql's
|
||||
@ -41,7 +41,7 @@ public:
|
||||
RecordLock lock;
|
||||
|
||||
// check if this record is visible to the transaction t
|
||||
bool visible(const tx::Transaction& t)
|
||||
bool visible(const tx::Transaction &t)
|
||||
{
|
||||
// TODO check if the record was created by a transaction that has been
|
||||
// aborted. one might implement this by checking the hints in mvcc
|
||||
@ -51,87 +51,95 @@ public:
|
||||
// if you think they're not, you're wrong, and you should think about it
|
||||
// again. i know, it happened to me.
|
||||
|
||||
return ((tx.cre() == t.id && // inserted by the current transaction
|
||||
cmd.cre() <= t.cid && // before this command, and
|
||||
(tx.exp() == Id(0) || // the row has not been deleted, or
|
||||
(tx.exp() == t.id && // it was deleted by the current
|
||||
// transaction
|
||||
cmd.exp() >= t.cid))) // but not before this command,
|
||||
|| // or
|
||||
(cre_committed(tx.cre(), t) && // the record was inserted by a
|
||||
// committed transaction, and
|
||||
(tx.exp() == Id(0) || // the record has not been deleted, or
|
||||
(tx.exp() == t.id && // the row is being deleted by this
|
||||
// transaction
|
||||
cmd.exp() >= t.cid) || // but it's not deleted "yet", or
|
||||
(tx.exp() != t.id && // the row was deleted by another
|
||||
// transaction
|
||||
!exp_committed(tx.exp(), t) // that has not been committed
|
||||
))));
|
||||
return ((tx.cre() == t.id && // inserted by the current transaction
|
||||
cmd.cre() <= t.cid && // before this command, and
|
||||
(tx.exp() == Id(0) || // the row has not been deleted, or
|
||||
(tx.exp() == t.id && // it was deleted by the current
|
||||
// transaction
|
||||
cmd.exp() >= t.cid))) // but not before this command,
|
||||
|| // or
|
||||
(cre_committed(tx.cre(), t) && // the record was inserted by a
|
||||
// committed transaction, and
|
||||
(tx.exp() == Id(0) || // the record has not been deleted, or
|
||||
(tx.exp() == t.id && // the row is being deleted by this
|
||||
// transaction
|
||||
cmd.exp() >= t.cid) || // but it's not deleted "yet", or
|
||||
(tx.exp() != t.id && // the row was deleted by another
|
||||
// transaction
|
||||
!exp_committed(tx.exp(), t) // that has not been committed
|
||||
))));
|
||||
}
|
||||
|
||||
void mark_created(const tx::Transaction& t)
|
||||
void mark_created(const tx::Transaction &t)
|
||||
{
|
||||
tx.cre(t.id);
|
||||
cmd.cre(t.cid);
|
||||
}
|
||||
|
||||
void mark_deleted(const tx::Transaction& t)
|
||||
void mark_deleted(const tx::Transaction &t)
|
||||
{
|
||||
tx.exp(t.id);
|
||||
cmd.exp(t.cid);
|
||||
}
|
||||
|
||||
bool exp_committed(const Id& id, const tx::Transaction& t)
|
||||
bool exp_committed(const Id &id, const tx::Transaction &t)
|
||||
{
|
||||
return committed(hints.exp, id, t);
|
||||
}
|
||||
|
||||
bool exp_committed(const tx::Transaction& t)
|
||||
bool exp_committed(const tx::Transaction &t)
|
||||
{
|
||||
return committed(hints.exp, tx.exp(), t);
|
||||
}
|
||||
|
||||
bool cre_committed(const Id& id, const tx::Transaction& t)
|
||||
bool cre_committed(const Id &id, const tx::Transaction &t)
|
||||
{
|
||||
return committed(hints.cre, id, t);
|
||||
}
|
||||
|
||||
bool cre_committed(const tx::Transaction& t)
|
||||
bool cre_committed(const tx::Transaction &t)
|
||||
{
|
||||
return committed(hints.cre, tx.cre(), t);
|
||||
}
|
||||
|
||||
// TODO: Test this
|
||||
// True if this record is visible for write.
|
||||
bool is_visible_write(const tx::Transaction &t)
|
||||
{
|
||||
return (tx.cre() == t.id && // inserted by the current transaction
|
||||
cmd.cre() <= t.cid && // before this command, and
|
||||
(tx.exp() == Id(0) || // the row has not been deleted, or
|
||||
(tx.exp() == t.id && // it was deleted by the current
|
||||
// transaction
|
||||
cmd.exp() >= t.cid))); // but not before this command,
|
||||
}
|
||||
|
||||
protected:
|
||||
template <class U>
|
||||
bool committed(U& hints, const Id& id, const tx::Transaction& t)
|
||||
bool committed(U &hints, const Id &id, const tx::Transaction &t)
|
||||
{
|
||||
// you certainly can't see the transaction with id greater than yours
|
||||
// as that means it started after this transaction and if it committed,
|
||||
// it committed after this transaction had started.
|
||||
if(id > t.id)
|
||||
return false;
|
||||
if (id > t.id) return false;
|
||||
|
||||
// The creating transaction is still in progress (examine snapshot)
|
||||
if (t.is_active(id)) return false;
|
||||
|
||||
auto hint_bits = hints.load();
|
||||
|
||||
// TODO: Validate if this position is valid for next if.
|
||||
// if hints are set, return if xid is committed
|
||||
if(!hint_bits.is_unknown())
|
||||
return hint_bits.is_committed();
|
||||
if (!hint_bits.is_unknown()) return hint_bits.is_committed();
|
||||
|
||||
// if hints are not set:
|
||||
// - the creating transaction is still in progress (examine snapshot)
|
||||
if(t.snapshot.is_active(id))
|
||||
return false;
|
||||
|
||||
// - you are the first one to check since it ended, consult commit log
|
||||
auto info = t.engine.clog.fetch_info(id);
|
||||
|
||||
if(info.is_committed())
|
||||
return hints.set_committed(), true;
|
||||
if (info.is_committed()) return hints.set_committed(), true;
|
||||
|
||||
assert(info.is_aborted());
|
||||
return hints.set_aborted(), false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -103,13 +103,6 @@ public:
|
||||
T *update(T *record, tx::Transaction &t)
|
||||
{
|
||||
assert(record != nullptr);
|
||||
// TODO: VALIDATE NEXT IF BLOCK
|
||||
if (record->tx.cre() == t.id) {
|
||||
// THEN ONLY THIS TRANSACTION CAN SEE THIS DATA WHICH MENS THAT IT
|
||||
// CAN CHANGE IT.
|
||||
return record;
|
||||
}
|
||||
|
||||
lock_and_validate(record, t);
|
||||
|
||||
auto updated = new T();
|
||||
@ -149,7 +142,6 @@ private:
|
||||
void lock_and_validate(T *record, tx::Transaction &t)
|
||||
{
|
||||
assert(record != nullptr);
|
||||
assert(record == find(t));
|
||||
|
||||
// take a lock on this node
|
||||
t.take_lock(lock);
|
||||
@ -167,9 +159,3 @@ private:
|
||||
RecordLock lock;
|
||||
};
|
||||
}
|
||||
|
||||
class Vertex;
|
||||
class Edge;
|
||||
|
||||
using VertexRecord = mvcc::VersionList<Vertex>;
|
||||
// using EdgeRecord = mvcc::VersionList<Edge>;
|
||||
|
@ -6,10 +6,12 @@
|
||||
#include "query_engine/query_stripper.hpp"
|
||||
#include "query_engine/util.hpp"
|
||||
#include "storage/indexes/impl/nonunique_unordered_index.cpp"
|
||||
// #include "storage/model/properties/properties.cpp"
|
||||
#include "storage/model/properties/property.hpp"
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
#include "utils/command_line/arguments.hpp"
|
||||
#include "utils/iterator/iterator.hpp"
|
||||
// #include "utils/utils.cpp"
|
||||
|
||||
auto load_queries(Db &db)
|
||||
{
|
||||
|
@ -10,10 +10,11 @@
|
||||
|
||||
#include "storage/model/properties/properties.hpp"
|
||||
|
||||
template <class TG>
|
||||
struct ResultList
|
||||
{
|
||||
using sptr = std::shared_ptr<ResultList>;
|
||||
using data_t = std::vector<const Properties *>;
|
||||
using data_t = std::vector<const Properties<TG> *>;
|
||||
|
||||
ResultList() = default;
|
||||
ResultList(ResultList &other) = delete;
|
||||
@ -22,13 +23,15 @@ struct ResultList
|
||||
|
||||
explicit operator bool() const { return data.size() > 0; }
|
||||
|
||||
std::vector<const Properties *> data;
|
||||
std::vector<const Properties<TG> *> data;
|
||||
};
|
||||
|
||||
template <class TG>
|
||||
struct QueryResult
|
||||
{
|
||||
using sptr = std::shared_ptr<QueryResult>;
|
||||
using data_t = std::unordered_map<std::string, ResultList::sptr>;
|
||||
using data_t =
|
||||
std::unordered_map<std::string, typename ResultList<TG>::sptr>;
|
||||
|
||||
QueryResult() = default;
|
||||
QueryResult(QueryResult &other) = delete;
|
||||
|
@ -11,7 +11,8 @@
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
void print_props(const Properties &properties);
|
||||
template <class T>
|
||||
void print_props(const Properties<T> &properties);
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define PRINT_PROPS(_)
|
||||
@ -19,7 +20,8 @@ void print_props(const Properties &properties);
|
||||
#define PRINT_PROPS(_PROPS_) print_props(_PROPS_);
|
||||
#endif
|
||||
|
||||
void cout_properties(const Properties &properties);
|
||||
template <class T>
|
||||
void cout_properties(const Properties<T> &properties);
|
||||
|
||||
void cout_property(const std::string &key, const Property &property);
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "mvcc/record.hpp"
|
||||
#include "storage/model/edge_model.hpp"
|
||||
#include "storage/model/properties/traversers/jsonwriter.hpp"
|
||||
// #include "storage/model/properties/traversers/jsonwriter.hpp"
|
||||
|
||||
class Edge : public mvcc::Record<Edge>
|
||||
{
|
||||
@ -10,14 +10,14 @@ public:
|
||||
class Accessor;
|
||||
|
||||
Edge() = default;
|
||||
Edge(const EdgeModel& data) : data(data) {}
|
||||
Edge(EdgeModel&& data) : data(std::move(data)) {}
|
||||
Edge(const EdgeModel &data) : data(data) {}
|
||||
Edge(EdgeModel &&data) : data(std::move(data)) {}
|
||||
|
||||
Edge(const Edge&) = delete;
|
||||
Edge(Edge&&) = delete;
|
||||
Edge(const Edge &) = delete;
|
||||
Edge(Edge &&) = delete;
|
||||
|
||||
Edge& operator=(const Edge&) = delete;
|
||||
Edge& operator=(Edge&&) = delete;
|
||||
Edge &operator=(const Edge &) = delete;
|
||||
Edge &operator=(Edge &&) = delete;
|
||||
|
||||
EdgeModel data;
|
||||
};
|
||||
|
@ -7,18 +7,23 @@
|
||||
#include "utils/assert.hpp"
|
||||
#include "utils/reference_wrapper.hpp"
|
||||
|
||||
class EdgeType;
|
||||
using edge_type_ref_t = ReferenceWrapper<const EdgeType>;
|
||||
|
||||
class Edges;
|
||||
|
||||
class Edge::Accessor : public RecordAccessor<Edge, Edge::Accessor, EdgeRecord>
|
||||
class EdgeAccessor : public RecordAccessor<TypeGroupEdge, EdgeAccessor>
|
||||
{
|
||||
public:
|
||||
using RecordAccessor::RecordAccessor;
|
||||
typedef Edge record_t;
|
||||
typedef EdgeRecord record_list_t;
|
||||
|
||||
void edge_type(edge_type_ref_t edge_type);
|
||||
|
||||
edge_type_ref_t edge_type() const;
|
||||
|
||||
Vertex::Accessor from() const;
|
||||
VertexAccessor from() const;
|
||||
|
||||
Vertex::Accessor to() const;
|
||||
VertexAccessor to() const;
|
||||
};
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include "mvcc/version_list.hpp"
|
||||
#include "storage/edge.hpp"
|
||||
|
||||
class VertexRecord;
|
||||
|
||||
class EdgeRecord : public mvcc::VersionList<Edge>
|
||||
{
|
||||
public:
|
||||
|
@ -3,18 +3,30 @@
|
||||
#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:
|
||||
EdgeType();
|
||||
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);
|
||||
@ -25,6 +37,8 @@ public:
|
||||
|
||||
CharStr char_str() { return CharStr(&id[0]); }
|
||||
|
||||
std::unique_ptr<type_index_t> index;
|
||||
|
||||
private:
|
||||
std::string id;
|
||||
};
|
||||
|
@ -1,25 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "data_structures/concurrent/concurrent_map.hpp"
|
||||
#include "mvcc/version_list.hpp"
|
||||
#include "storage/common.hpp"
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/model/properties/property_family.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>;
|
||||
|
||||
class Edges
|
||||
{
|
||||
using prop_familys_t = ConcurrentMap<std::string, PropertyFamily *>;
|
||||
using prop_familys_t = ConcurrentMap<std::string, EdgePropertyFamily *>;
|
||||
|
||||
public:
|
||||
Option<const Edge::Accessor> find(DbTransaction &t, const Id &id);
|
||||
Option<const EdgeAccessor> find(DbTransaction &t, const Id &id);
|
||||
|
||||
// Creates new Edge and returns filled Edge::Accessor.
|
||||
Edge::Accessor insert(DbTransaction &t, VertexRecord *from,
|
||||
VertexRecord *to);
|
||||
// Creates new Edge and returns filled EdgeAccessor.
|
||||
EdgeAccessor insert(DbTransaction &t, VertexRecord *from, VertexRecord *to);
|
||||
|
||||
PropertyFamily &property_family_find_or_create(const std::string &name);
|
||||
EdgePropertyFamily &property_family_find_or_create(const std::string &name);
|
||||
|
||||
private:
|
||||
ConcurrentMap<uint64_t, EdgeRecord> edges;
|
||||
|
9
include/storage/garbage/delete_sensitive.hpp
Normal file
9
include/storage/garbage/delete_sensitive.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
// Base class for all classes which need to be safely disposed. Main usage is
|
||||
// for garbage class operations.
|
||||
class DeleteSensitive
|
||||
{
|
||||
public:
|
||||
virtual ~DeleteSensitive() {}
|
||||
};
|
28
include/storage/garbage/garbage.hpp
Normal file
28
include/storage/garbage/garbage.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "data_structures/concurrent/concurrent_list.hpp"
|
||||
#include "mvcc/id.hpp"
|
||||
#include "storage/garbage/delete_sensitive.hpp"
|
||||
#include "transactions/snapshot.hpp"
|
||||
|
||||
namespace tx
|
||||
{
|
||||
class Engine;
|
||||
}
|
||||
|
||||
// Collection of delete sensitive data which need to be safely deleted. That
|
||||
// meens that all transactions that may have pointer to it must finish before
|
||||
// the sensitive data can be safely destroyed.
|
||||
class Garbage
|
||||
{
|
||||
public:
|
||||
void dispose(tx::Snapshot<Id> &&snapshot, DeleteSensitive *data);
|
||||
|
||||
// Cleaner thread shoul call this method every some time. Removes data which
|
||||
// is
|
||||
// safe to be deleted.
|
||||
void clean(tx::Engine &engine);
|
||||
|
||||
private:
|
||||
List<std::pair<tx::Snapshot<Id>, DeleteSensitive *>> gar;
|
||||
};
|
@ -1,26 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "storage/indexes/index_base.hpp"
|
||||
#include "storage/indexes/index_record.hpp"
|
||||
// #include "storage/indexes/index_record.hpp"
|
||||
|
||||
#include "data_structures/concurrent/concurrent_list.hpp"
|
||||
|
||||
template <class T, class K>
|
||||
class NonUniqueUnorderedIndex : public IndexBase<T, K>
|
||||
template <class TG, class K>
|
||||
class NonUniqueUnorderedIndex : public IndexBase<TG, K>
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef K key_type;
|
||||
// typedef T value_type;
|
||||
// typedef K key_type;
|
||||
|
||||
// Created with the database
|
||||
NonUniqueUnorderedIndex();
|
||||
|
||||
NonUniqueUnorderedIndex(tx::Transaction const &t);
|
||||
|
||||
// Insert's value.
|
||||
// nonunique => always succeds.
|
||||
bool insert(IndexRecord<T, K> &&value) final;
|
||||
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.
|
||||
std::unique_ptr<IteratorBase<const typename T::Accessor>>
|
||||
std::unique_ptr<IteratorBase<const typename TG::accessor_t>>
|
||||
for_range(DbAccessor &t, Border<K> from = Border<K>(),
|
||||
Border<K> to = Border<K>()) final;
|
||||
|
||||
@ -34,5 +37,5 @@ public:
|
||||
void clean(DbTransaction &) final;
|
||||
|
||||
private:
|
||||
List<IndexRecord<T, K>> list;
|
||||
List<IndexRecord<TG, K>> list;
|
||||
};
|
||||
|
40
include/storage/indexes/impl/unique_ordered_index.hpp
Normal file
40
include/storage/indexes/impl/unique_ordered_index.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "storage/indexes/index_base.hpp"
|
||||
|
||||
#include "data_structures/concurrent/concurrent_set.hpp"
|
||||
|
||||
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(Order order);
|
||||
|
||||
UniqueOrderedIndex(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.
|
||||
std::unique_ptr<IteratorBase<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.
|
||||
void clean(DbTransaction &) final;
|
||||
|
||||
private:
|
||||
ConcurrentSet<IndexRecord<T, K>> set;
|
||||
};
|
@ -1,41 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
// #include "storage/indexes/index_record.hpp"
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include "mvcc/id.hpp"
|
||||
|
||||
// #include "storage/indexes/index_record.hpp"
|
||||
#include "storage/garbage/delete_sensitive.hpp"
|
||||
#include "utils/border.hpp"
|
||||
#include "utils/iterator/iterator_base.hpp"
|
||||
#include "utils/order.hpp"
|
||||
|
||||
template <class TG, class K>
|
||||
class IndexRecord;
|
||||
|
||||
class DbTransaction;
|
||||
class DbAccessor;
|
||||
|
||||
template <class T, class K>
|
||||
class IndexRecord;
|
||||
|
||||
// Defines ordering of data
|
||||
enum Order
|
||||
namespace tx
|
||||
{
|
||||
None = 0,
|
||||
Ascending = 1,
|
||||
Descending = 2,
|
||||
};
|
||||
class Transaction;
|
||||
}
|
||||
|
||||
// Interface for all indexes.
|
||||
// T type of record.
|
||||
// TG type group
|
||||
// K type of key on which records are ordered
|
||||
template <class T, class K>
|
||||
class IndexBase
|
||||
template <class TG, class K>
|
||||
class IndexBase : public DeleteSensitive
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef K key_type;
|
||||
// typedef T value_type;
|
||||
// typedef K key_type;
|
||||
|
||||
IndexBase(bool unique, Order order) : unique(unique), order(order) {}
|
||||
// Created with the database
|
||||
IndexBase(bool unique, Order order);
|
||||
|
||||
IndexBase(bool unique, Order order, const tx::Transaction &t);
|
||||
|
||||
// Insert's value.
|
||||
// unique => returns false if there is already valid equal value.
|
||||
// nonunique => always succeds.
|
||||
virtual bool insert(IndexRecord<T, K> &&value) = 0;
|
||||
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.
|
||||
@ -44,7 +48,7 @@ public:
|
||||
// order==Descending => guarantees order of returned records will be from
|
||||
// largest to smallest.
|
||||
// Range must be from<=to
|
||||
virtual std::unique_ptr<IteratorBase<const typename T::Accessor>>
|
||||
virtual std::unique_ptr<IteratorBase<const typename TG::accessor_t>>
|
||||
for_range(DbAccessor &, Border<K> from = Border<K>(),
|
||||
Border<K> to = Border<K>()) = 0;
|
||||
|
||||
@ -53,8 +57,23 @@ public:
|
||||
// cleaning.
|
||||
virtual void clean(DbTransaction &) = 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);
|
||||
|
||||
// Are the records unique
|
||||
const bool unique;
|
||||
// Ordering of the records.
|
||||
const Order order;
|
||||
|
||||
private:
|
||||
// Id of transaction which created this index.
|
||||
const Id created;
|
||||
// Active state
|
||||
std::atomic_bool active = {false};
|
||||
};
|
||||
|
49
include/storage/indexes/index_holder.hpp
Normal file
49
include/storage/indexes/index_holder.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "storage/indexes/index_base.hpp"
|
||||
#include "utils/option.hpp"
|
||||
#include "utils/option_ptr.hpp"
|
||||
|
||||
namespace tx
|
||||
{
|
||||
class Transaction;
|
||||
}
|
||||
|
||||
// Holds onde index which can be changed.
|
||||
// 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. Treturns 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,37 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "database/db_transaction.hpp"
|
||||
#include "mvcc/version_list.hpp"
|
||||
#include "utils/border.hpp"
|
||||
#include "utils/total_ordering.hpp"
|
||||
|
||||
// class DbTransaction;
|
||||
// namespace tx
|
||||
// {
|
||||
// class Transaction;
|
||||
// }
|
||||
namespace tx
|
||||
{
|
||||
class Transaction;
|
||||
}
|
||||
class DbTransaction;
|
||||
|
||||
// T type of record.
|
||||
// TG type group
|
||||
// K key on which record is ordered.
|
||||
template <class T, class K>
|
||||
class IndexRecord : public TotalOrdering<IndexRecord<T, K>>
|
||||
template <class TG, class K>
|
||||
class IndexRecord : public TotalOrdering<IndexRecord<TG, K>>,
|
||||
public TotalOrdering<Border<K>, IndexRecord<TG, K>>
|
||||
{
|
||||
public:
|
||||
using vlist_t = mvcc::VersionList<T>;
|
||||
|
||||
IndexRecord() = default;
|
||||
|
||||
IndexRecord(K key, T *record, vlist_t *vlist)
|
||||
: key(std::move(key)), record(record), vlist(vlist)
|
||||
{
|
||||
assert(record != nullptr);
|
||||
assert(vlist != nullptr);
|
||||
}
|
||||
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);
|
||||
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)
|
||||
@ -40,28 +35,29 @@ public:
|
||||
(lhs.vlist != rhs.vlist || lhs.record == rhs.record);
|
||||
}
|
||||
|
||||
bool empty() const { return record == nullptr; }
|
||||
|
||||
bool is_valid(tx::Transaction &t) const
|
||||
friend bool operator<(const Border<K> &lhs, const IndexRecord &rhs)
|
||||
{
|
||||
assert(!empty());
|
||||
return record == vlist->find(t);
|
||||
return lhs < rhs.key;
|
||||
}
|
||||
|
||||
const auto access(DbTransaction &db) const
|
||||
friend bool operator==(const Border<K> &lhs, const IndexRecord &rhs)
|
||||
{
|
||||
return T::Accessor::create(record, vlist, db);
|
||||
return lhs == rhs.key;
|
||||
}
|
||||
|
||||
// Will change ordering of record to descending.
|
||||
void set_descending();
|
||||
|
||||
bool empty() const;
|
||||
|
||||
bool is_valid(tx::Transaction &t) const;
|
||||
|
||||
const auto access(DbTransaction &db) const;
|
||||
|
||||
const K key;
|
||||
|
||||
private:
|
||||
T *const record{nullptr};
|
||||
vlist_t *const vlist{nullptr};
|
||||
bool descending = false;
|
||||
typename TG::record_t *const record{nullptr};
|
||||
typename TG::vlist_t *const vlist{nullptr};
|
||||
};
|
||||
|
||||
template <class K>
|
||||
using VertexIndexRecord = IndexRecord<Vertex, K>;
|
||||
|
||||
template <class K>
|
||||
using EdgeIndexRecord = IndexRecord<Edge, K>;
|
||||
|
41
include/storage/indexes/index_update.hpp
Normal file
41
include/storage/indexes/index_update.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "storage/indexes/index_record.hpp"
|
||||
#include "storage/type_group_edge.hpp"
|
||||
#include "storage/type_group_vertex.hpp"
|
||||
|
||||
struct IndexUpdateEdge
|
||||
{
|
||||
EdgeRecord *vlist;
|
||||
Edge *record;
|
||||
};
|
||||
|
||||
struct IndexUpdateVertex
|
||||
{
|
||||
VertexRecord *vlist;
|
||||
Vertex *record;
|
||||
};
|
||||
|
||||
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);
|
@ -9,13 +9,16 @@
|
||||
#include "utils/char_str.hpp"
|
||||
#include "utils/reference_wrapper.hpp"
|
||||
#include "utils/total_ordering.hpp"
|
||||
// #include "storage/type_group_edge.hpp"
|
||||
#include "storage/type_group_vertex.hpp"
|
||||
|
||||
using LabelIndexRecord = VertexIndexRecord<std::nullptr_t>;
|
||||
using LabelIndexRecord = IndexRecord<TypeGroupVertex, std::nullptr_t>;
|
||||
|
||||
class Label : public TotalOrdering<Label>, TotalOrdering<CharStr, Label>
|
||||
{
|
||||
public:
|
||||
using label_index_t = NonUniqueUnorderedIndex<Vertex, std::nullptr_t>;
|
||||
using label_index_t =
|
||||
NonUniqueUnorderedIndex<TypeGroupVertex, std::nullptr_t>;
|
||||
|
||||
Label() = delete;
|
||||
|
||||
@ -36,10 +39,10 @@ public:
|
||||
|
||||
operator const std::string &() const;
|
||||
|
||||
std::unique_ptr<label_index_t> index;
|
||||
|
||||
CharStr char_str() const { return CharStr(name.c_str()); }
|
||||
|
||||
std::unique_ptr<label_index_t> index;
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
};
|
||||
|
@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "data_structures/map/rh_hashmultimap.hpp"
|
||||
#include "mvcc/version_list.hpp"
|
||||
#include "storage/edge_record.hpp"
|
||||
// #include "storage/vertex_record.hpp"
|
||||
|
||||
class EdgeMap
|
||||
{
|
||||
|
@ -1,10 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "mvcc/version_list.hpp"
|
||||
// #include "mvcc/version_list.hpp"
|
||||
// #include "storage/edge_type/edge_type.hpp"
|
||||
#include "storage/model/property_model.hpp"
|
||||
#include "storage/edge_type/edge_type.hpp"
|
||||
#include "storage/type_group_edge.hpp"
|
||||
|
||||
class EdgeModel : public PropertyModel
|
||||
class EdgeType;
|
||||
|
||||
class EdgeModel : public PropertyModel<TypeGroupEdge>
|
||||
{
|
||||
public:
|
||||
// TODO: here should be the reference
|
||||
|
@ -6,16 +6,26 @@
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
#include "utils/option.hpp"
|
||||
|
||||
using prop_key_t = PropertyFamily::PropertyType::PropertyFamilyKey;
|
||||
template <class TG>
|
||||
using prop_key_t = typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey;
|
||||
|
||||
template <class T>
|
||||
using type_key_t = PropertyFamily::PropertyType::PropertyTypeKey<T>;
|
||||
template <class TG, class T>
|
||||
using type_key_t =
|
||||
typename PropertyFamily<TG>::PropertyType::template PropertyTypeKey<T>;
|
||||
|
||||
template <class TG>
|
||||
class Properties
|
||||
{
|
||||
public:
|
||||
using sptr = std::shared_ptr<Properties>;
|
||||
|
||||
using prop_key_t =
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey;
|
||||
|
||||
template <class T>
|
||||
using type_key_t =
|
||||
typename PropertyFamily<TG>::PropertyType::template PropertyTypeKey<T>;
|
||||
|
||||
auto begin() const { return props.begin(); }
|
||||
auto cbegin() const { return props.cbegin(); }
|
||||
|
||||
@ -24,7 +34,7 @@ public:
|
||||
|
||||
size_t size() const { return props.size(); }
|
||||
|
||||
const Property &at(PropertyFamily &key) const;
|
||||
const Property &at(PropertyFamily<TG> &key) const;
|
||||
|
||||
const Property &at(prop_key_t &key) const;
|
||||
|
||||
@ -38,7 +48,7 @@ public:
|
||||
|
||||
void clear(prop_key_t &key);
|
||||
|
||||
void clear(PropertyFamily &key);
|
||||
void clear(PropertyFamily<TG> &key);
|
||||
|
||||
template <class Handler>
|
||||
void accept(Handler &handler) const
|
||||
@ -58,6 +68,6 @@ public:
|
||||
|
||||
private:
|
||||
using props_t =
|
||||
std::unordered_map<prop_key_t, Property::sptr, PropertyHash>;
|
||||
std::unordered_map<prop_key_t, Property::sptr, PropertyHash<TG>>;
|
||||
props_t props;
|
||||
};
|
||||
|
@ -1,15 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "data_structures/concurrent/concurrent_map.hpp"
|
||||
#include "storage/indexes/index_holder.hpp"
|
||||
#include "storage/model/properties/flags.hpp"
|
||||
#include "utils/option.hpp"
|
||||
#include "utils/total_ordering.hpp"
|
||||
#include "utils/underlying_cast.hpp"
|
||||
|
||||
// #include "storage/indexes/index_base.hpp"
|
||||
|
||||
// Family of properties with the same name but different types.
|
||||
// Ordered on name.
|
||||
class PropertyFamily : public TotalOrdering<PropertyFamily>
|
||||
// TG - group of types Edge/Vertex
|
||||
template <class TG>
|
||||
class PropertyFamily : public TotalOrdering<PropertyFamily<TG>>
|
||||
{
|
||||
friend class PropertyType;
|
||||
friend class PropertyFamilyKey;
|
||||
@ -175,6 +181,8 @@ public:
|
||||
friend bool operator==(const PropertyFamily &lhs,
|
||||
const PropertyFamily &rhs);
|
||||
|
||||
IndexHolder<TG, std::nullptr_t> index;
|
||||
|
||||
private:
|
||||
const std::string name_v;
|
||||
// This is exclusivly for getNull method.
|
||||
@ -184,11 +192,13 @@ private:
|
||||
ConcurrentMap<Type, std::unique_ptr<PropertyType>> types;
|
||||
};
|
||||
|
||||
template <class TG>
|
||||
class PropertyHash
|
||||
{
|
||||
public:
|
||||
size_t
|
||||
operator()(PropertyFamily::PropertyType::PropertyFamilyKey const &key) const
|
||||
size_t operator()(
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey const &key)
|
||||
const
|
||||
{
|
||||
return (std::hash<const void *>()((const void *)(&(key.get_family()))) +
|
||||
7) *
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#include "storage/model/properties/handler.hpp"
|
||||
#include "storage/model/properties/properties.hpp"
|
||||
#include "storage/type_group_edge.hpp"
|
||||
#include "storage/type_group_vertex.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -13,7 +15,24 @@ class ConsoleWriter
|
||||
public:
|
||||
ConsoleWriter() {}
|
||||
|
||||
void handle(const prop_key_t &key, const Property &value)
|
||||
void handle(const typename PropertyFamily<
|
||||
TypeGroupEdge>::PropertyType::PropertyFamilyKey &key,
|
||||
const Property &value)
|
||||
{
|
||||
handle<TypeGroupEdge>(key, value);
|
||||
}
|
||||
|
||||
void handle(const typename PropertyFamily<
|
||||
TypeGroupVertex>::PropertyType::PropertyFamilyKey &key,
|
||||
const Property &value)
|
||||
{
|
||||
handle<TypeGroupVertex>(key, value);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void handle(
|
||||
const typename PropertyFamily<T>::PropertyType::PropertyFamilyKey &key,
|
||||
const Property &value)
|
||||
{
|
||||
cout << "KEY: " << key.family_name() << "; VALUE: ";
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include "storage/model/properties/handler.hpp"
|
||||
#include "storage/model/properties/properties.hpp"
|
||||
#include "storage/type_group_edge.hpp"
|
||||
#include "storage/type_group_vertex.hpp"
|
||||
|
||||
template <class Buffer>
|
||||
struct JsonWriter
|
||||
@ -9,7 +11,24 @@ struct JsonWriter
|
||||
public:
|
||||
JsonWriter(Buffer &buffer) : buffer(buffer) { buffer << '{'; };
|
||||
|
||||
void handle(const prop_key_t &key, const Property &value)
|
||||
void handle(const typename PropertyFamily<
|
||||
TypeGroupEdge>::PropertyType::PropertyFamilyKey &key,
|
||||
const Property &value)
|
||||
{
|
||||
handle<TypeGroupEdge>(key, value);
|
||||
}
|
||||
|
||||
void handle(const typename PropertyFamily<
|
||||
TypeGroupVertex>::PropertyType::PropertyFamilyKey &key,
|
||||
const Property &value)
|
||||
{
|
||||
handle<TypeGroupVertex>(key, value);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void handle(
|
||||
const typename PropertyFamily<T>::PropertyType::PropertyFamilyKey &key,
|
||||
const Property &value)
|
||||
{
|
||||
if (!first) buffer << ',';
|
||||
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
#include "storage/model/properties/properties.hpp"
|
||||
|
||||
template <class TG>
|
||||
class PropertyModel
|
||||
{
|
||||
public:
|
||||
Properties props;
|
||||
Properties<TG> props;
|
||||
};
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "storage/model/edge_map.hpp"
|
||||
#include "storage/model/property_model.hpp"
|
||||
|
||||
class VertexModel : public PropertyModel
|
||||
class VertexModel : public PropertyModel<TypeGroupVertex>
|
||||
{
|
||||
public:
|
||||
EdgeList out;
|
||||
|
@ -3,15 +3,18 @@
|
||||
#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 "transactions/transaction.hpp"
|
||||
|
||||
template <class T, class Derived, class vlist_t = mvcc::VersionList<T>>
|
||||
template <class TG, class Derived>
|
||||
class RecordAccessor
|
||||
{
|
||||
friend DbAccessor;
|
||||
using vlist_t = typename TG::vlist_t;
|
||||
using T = typename TG::record_t;
|
||||
|
||||
public:
|
||||
RecordAccessor(vlist_t *vlist, DbTransaction &db) : vlist(vlist), db(db)
|
||||
@ -47,11 +50,27 @@ public:
|
||||
|
||||
const Id &id() const { return vlist->id; }
|
||||
|
||||
// TODO: Test this
|
||||
Derived update() const
|
||||
{
|
||||
assert(!empty());
|
||||
|
||||
return Derived(vlist->update(db.trans), vlist, db);
|
||||
if (record->is_visible_write(db.trans)) {
|
||||
// TODO: VALIDATE THIS BRANCH. THEN ONLY THIS TRANSACTION CAN SEE
|
||||
// THIS DATA WHICH MEENS 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 remove() const
|
||||
@ -61,30 +80,36 @@ public:
|
||||
return vlist->remove(record, db.trans);
|
||||
}
|
||||
|
||||
const Property &at(PropertyFamily &key) const
|
||||
const Property &at(PropertyFamily<TG> &key) const
|
||||
{
|
||||
return properties().at(key);
|
||||
}
|
||||
|
||||
const Property &at(prop_key_t &key) const { return properties().at(key); }
|
||||
const Property &at(prop_key_t<TG> &key) const
|
||||
{
|
||||
return properties().at(key);
|
||||
}
|
||||
|
||||
template <class V>
|
||||
auto at(type_key_t<V> &key) const;
|
||||
auto at(type_key_t<TG, V> &key) const
|
||||
{
|
||||
return properties().template at<V>(key);
|
||||
}
|
||||
|
||||
template <class V, class... Args>
|
||||
void set(type_key_t<V> &key, Args &&... args)
|
||||
void set(type_key_t<TG, V> &key, Args &&... args)
|
||||
{
|
||||
properties().template set<V>(key, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void set(prop_key_t &key, Property::sptr value)
|
||||
void set(prop_key_t<TG> &key, Property::sptr value)
|
||||
{
|
||||
properties().set(key, std::move(value));
|
||||
}
|
||||
|
||||
void clear(prop_key_t &key) { properties().clear(key); }
|
||||
void clear(prop_key_t<TG> &key) { properties().clear(key); }
|
||||
|
||||
void clear(PropertyFamily &key) { properties().clear(key); }
|
||||
void clear(PropertyFamily<TG> &key) { properties().clear(key); }
|
||||
|
||||
template <class Handler>
|
||||
void accept(Handler &handler) const
|
||||
@ -92,7 +117,7 @@ public:
|
||||
properties().template accept<Handler>(handler);
|
||||
}
|
||||
|
||||
Properties &properties() const { return record->data.props; }
|
||||
Properties<TG> &properties() const { return record->data.props; }
|
||||
|
||||
explicit operator bool() const { return record != nullptr; }
|
||||
|
||||
@ -127,18 +152,6 @@ public:
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
protected:
|
||||
IndexRecord<T, std::nullptr_t> create_index_record()
|
||||
{
|
||||
return create_index_record(std::nullptr_t());
|
||||
}
|
||||
|
||||
template <class K>
|
||||
IndexRecord<T, K> create_index_record(K &&key)
|
||||
{
|
||||
return IndexRecord<T, K>(std::move(key), record, vlist);
|
||||
}
|
||||
|
||||
T *record{nullptr};
|
||||
vlist_t *const vlist;
|
||||
DbTransaction &db;
|
||||
|
19
include/storage/type_group_edge.hpp
Normal file
19
include/storage/type_group_edge.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#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;
|
||||
};
|
19
include/storage/type_group_vertex.hpp
Normal file
19
include/storage/type_group_vertex.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#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;
|
||||
};
|
@ -5,16 +5,12 @@
|
||||
|
||||
class Vertices;
|
||||
|
||||
class Vertex::Accessor : public RecordAccessor<Vertex, Vertex::Accessor>
|
||||
class VertexAccessor : public RecordAccessor<TypeGroupVertex, VertexAccessor>
|
||||
{
|
||||
public:
|
||||
using RecordAccessor::RecordAccessor;
|
||||
|
||||
static Vertex::Accessor create(Vertex *t, mvcc::VersionList<Vertex> *vlist,
|
||||
DbTransaction &db)
|
||||
{
|
||||
return Vertex::Accessor(t, vlist, db);
|
||||
}
|
||||
typedef Vertex record_t;
|
||||
typedef VertexRecord record_list_t;
|
||||
|
||||
size_t out_degree() const;
|
||||
|
||||
@ -37,5 +33,5 @@ public:
|
||||
auto in() const;
|
||||
|
||||
// True if there exists edge other->this
|
||||
bool in_contains(Vertex::Accessor const &other) const;
|
||||
bool in_contains(VertexAccessor const &other) const;
|
||||
};
|
||||
|
12
include/storage/vertex_record.hpp
Normal file
12
include/storage/vertex_record.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
#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,31 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "data_structures/concurrent/concurrent_map.hpp"
|
||||
#include "database/db_transaction.hpp"
|
||||
#include "storage/common.hpp"
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
#include "storage/vertex_accessor.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>;
|
||||
|
||||
class Vertices
|
||||
{
|
||||
public:
|
||||
using vertices_t = ConcurrentMap<uint64_t, VertexRecord>;
|
||||
using prop_familys_t =
|
||||
ConcurrentMap<std::string, std::unique_ptr<PropertyFamily>>;
|
||||
ConcurrentMap<std::string, std::unique_ptr<VertexPropertyFamily>>;
|
||||
|
||||
vertices_t::Accessor access();
|
||||
|
||||
Option<const Vertex::Accessor> find(DbTransaction &t, const Id &id);
|
||||
Option<const VertexAccessor> find(DbTransaction &t, const Id &id);
|
||||
|
||||
// Creates new Vertex and returns filled Vertex::Accessor.
|
||||
Vertex::Accessor insert(DbTransaction &t);
|
||||
// Creates new Vertex and returns filled VertexAccessor.
|
||||
VertexAccessor insert(DbTransaction &t);
|
||||
|
||||
PropertyFamily &property_family_find_or_create(const std::string &name);
|
||||
VertexPropertyFamily &
|
||||
property_family_find_or_create(const std::string &name);
|
||||
|
||||
private:
|
||||
vertices_t vertices;
|
||||
|
@ -48,6 +48,9 @@ public:
|
||||
void set_aborted(const Id &id) { log.set(2 * id + 1); }
|
||||
|
||||
private:
|
||||
// TODO: Searching the log will take more and more time the more and more
|
||||
// transactoins are done. This could be awerted if DynamicBitset is changed
|
||||
// to point to largest chunk instead of the smallest.
|
||||
DynamicBitset<uint8_t, 32768> log;
|
||||
};
|
||||
}
|
||||
|
@ -26,7 +26,10 @@ public:
|
||||
|
||||
Engine() : counter(1) {}
|
||||
|
||||
Transaction &begin()
|
||||
// Begins transaction and runs given functions in same atomic step.
|
||||
// Functions will be given Transaction&
|
||||
template <class... F>
|
||||
Transaction &begin(F... fun)
|
||||
{
|
||||
auto guard = this->acquire_unique();
|
||||
|
||||
@ -36,6 +39,8 @@ public:
|
||||
active.insert(id);
|
||||
store.put(id, t);
|
||||
|
||||
call(*t, fun...);
|
||||
|
||||
return *t;
|
||||
}
|
||||
|
||||
@ -53,6 +58,14 @@ public:
|
||||
return *t;
|
||||
}
|
||||
|
||||
// Returns copy of current snapshot
|
||||
Snapshot<Id> snapshot()
|
||||
{
|
||||
auto guard = this->acquire_unique();
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
void commit(const Transaction &t)
|
||||
{
|
||||
auto guard = this->acquire_unique();
|
||||
@ -92,6 +105,21 @@ public:
|
||||
CommitLog clog;
|
||||
|
||||
private:
|
||||
template <class T, class... F>
|
||||
void call(Transaction &t, T fun, F... funs)
|
||||
{
|
||||
call(t, fun);
|
||||
call(t, funs...);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void call(Transaction &t, T fun)
|
||||
{
|
||||
fun(t);
|
||||
}
|
||||
|
||||
void call(Transaction &t) {}
|
||||
|
||||
void finalize(const Transaction &t)
|
||||
{
|
||||
active.remove(t.id);
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace tx
|
||||
{
|
||||
@ -14,45 +14,31 @@ public:
|
||||
|
||||
Snapshot(std::vector<id_t> active) : active(std::move(active)) {}
|
||||
|
||||
Snapshot(const Snapshot& other)
|
||||
{
|
||||
active = other.active;
|
||||
}
|
||||
Snapshot(const Snapshot &other) { active = other.active; }
|
||||
|
||||
Snapshot(Snapshot&& other)
|
||||
{
|
||||
active = std::move(other.active);
|
||||
}
|
||||
Snapshot(Snapshot &&other) { active = std::move(other.active); }
|
||||
|
||||
bool is_active(id_t xid) const
|
||||
{
|
||||
return std::binary_search(active.begin(), active.end(), xid);
|
||||
}
|
||||
|
||||
void insert(const id_t& id)
|
||||
{
|
||||
active.push_back(id);
|
||||
}
|
||||
void insert(const id_t &id) { active.push_back(id); }
|
||||
|
||||
void remove(const id_t& id)
|
||||
void remove(const id_t &id)
|
||||
{
|
||||
// remove transaction from the active transactions list
|
||||
auto last = std::remove(active.begin(), active.end(), id);
|
||||
active.erase(last, active.end());
|
||||
}
|
||||
|
||||
const id_t& front()
|
||||
{
|
||||
return active.front();
|
||||
}
|
||||
const id_t &front() { return active.front(); }
|
||||
|
||||
size_t size()
|
||||
{
|
||||
return active.size();
|
||||
}
|
||||
const id_t &back() { return active.back(); }
|
||||
|
||||
size_t size() { return active.size(); }
|
||||
|
||||
private:
|
||||
std::vector<id_t> active;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -28,8 +28,13 @@ public:
|
||||
// index of the current command in the current transaction;
|
||||
uint8_t cid;
|
||||
// a snapshot of currently active transactions
|
||||
const Snapshot<Id> snapshot;
|
||||
|
||||
// Blocks until all transactions from snapshot finish. After this method,
|
||||
// snapshot will be empty.
|
||||
void wait_for_active();
|
||||
|
||||
// True if id is in snapshot.
|
||||
bool is_active(const Id &id) const;
|
||||
void take_lock(RecordLock &lock);
|
||||
void commit();
|
||||
void abort();
|
||||
@ -37,6 +42,7 @@ public:
|
||||
Engine &engine;
|
||||
|
||||
private:
|
||||
Snapshot<Id> snapshot;
|
||||
LockStore<RecordLock> locks;
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/option.hpp"
|
||||
#include "utils/total_ordering.hpp"
|
||||
|
||||
// Defines Including as [ and Excluding < for ranges.
|
||||
enum BorderType
|
||||
@ -9,6 +10,7 @@ enum BorderType
|
||||
Excluding = 1,
|
||||
};
|
||||
|
||||
// If key is not present he is both the largest and the smallest of the keys.
|
||||
template <class T>
|
||||
class Border
|
||||
{
|
||||
@ -26,22 +28,60 @@ public:
|
||||
Border &operator=(Border &&other) = default;
|
||||
Border &operator=(Border &other) = default;
|
||||
|
||||
// true if no border or this > key or this >= key depends on border type.
|
||||
bool operator>(const T &other) const
|
||||
friend bool operator<(const Border<T> &a, const T &other)
|
||||
{
|
||||
return !key.is_present() || key.get() > other ||
|
||||
(type == Including && key.get() == other);
|
||||
return !a.key.is_present() ||
|
||||
(a.type == Excluding && a.key.get() <= other) ||
|
||||
(a.type == Including && a.key.get() < other);
|
||||
}
|
||||
|
||||
// true if no border or this < key or this <= key depends on border type.
|
||||
bool operator<(const T &other) const
|
||||
friend bool operator==(const Border<T> &a, const T &other)
|
||||
{
|
||||
return !key.is_present() || key.get() < other ||
|
||||
(type == Including && key.get() == other);
|
||||
return a.type == Including && a.key.is_present() &&
|
||||
a.key.get() == other;
|
||||
}
|
||||
|
||||
friend bool operator>(const Border<T> &a, const T &other)
|
||||
{
|
||||
return !a.key.is_present() ||
|
||||
(a.type == Excluding && a.key.get() >= other) ||
|
||||
(a.type == Including && a.key.get() > other);
|
||||
}
|
||||
|
||||
friend bool operator!=(const Border<T> &a, const T &b) { return !(a == b); }
|
||||
|
||||
friend bool operator<=(const Border<T> &a, const T &b)
|
||||
{
|
||||
return a < b || a == b;
|
||||
}
|
||||
|
||||
friend bool operator>=(const Border<T> &a, const T &b)
|
||||
{
|
||||
return a > b || a == b;
|
||||
}
|
||||
|
||||
// // true if no border or this > key or this >= key depends on border type.
|
||||
// bool operator>(const T &other) const
|
||||
// {
|
||||
// return !key.is_present() || key.get() > other ||
|
||||
// (type == Including && key.get() == other);
|
||||
// }
|
||||
//
|
||||
// // true if this border is inclusive and key is present and key == other.
|
||||
// bool operator==(const T &other) const
|
||||
// {
|
||||
// return type == Including && key.is_present() && key.get() == other;
|
||||
// }
|
||||
//
|
||||
// // true if no border or this < key or this <= key depends on border type.
|
||||
// bool operator<(const T &other) const
|
||||
// {
|
||||
// return !key.is_present() || key.get() < other ||
|
||||
// (type == Including && key.get() == other);
|
||||
// }
|
||||
|
||||
Option<T> key;
|
||||
const BorderType type;
|
||||
BorderType type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
@ -18,3 +18,9 @@ public:
|
||||
private:
|
||||
T *ptr = nullptr;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
auto make_option_ptr(T *t)
|
||||
{
|
||||
return OptionPtr<T>(t);
|
||||
}
|
||||
|
9
include/utils/order.hpp
Normal file
9
include/utils/order.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
// Defines ordering of data
|
||||
enum Order
|
||||
{
|
||||
None = 0,
|
||||
Ascending = 1,
|
||||
Descending = 2,
|
||||
};
|
@ -28,7 +28,7 @@
|
||||
const int max_score = 1000000;
|
||||
|
||||
using namespace std;
|
||||
typedef Vertex::Accessor VertexAccessor;
|
||||
typedef VertexAccessor VertexAccessor;
|
||||
|
||||
void add_scores(Db &db);
|
||||
|
||||
@ -36,17 +36,18 @@ class Node
|
||||
{
|
||||
public:
|
||||
Node *parent = {nullptr};
|
||||
type_key_t<Double> tkey;
|
||||
type_key_t<TypeGroupVertex, Double> tkey;
|
||||
double cost;
|
||||
int depth = {0};
|
||||
VertexAccessor vacc;
|
||||
|
||||
Node(VertexAccessor vacc, double cost, type_key_t<Double> tkey)
|
||||
Node(VertexAccessor vacc, double cost,
|
||||
type_key_t<TypeGroupVertex, Double> tkey)
|
||||
: cost(cost), vacc(vacc), tkey(tkey)
|
||||
{
|
||||
}
|
||||
Node(VertexAccessor vacc, double cost, Node *parent,
|
||||
type_key_t<Double> tkey)
|
||||
type_key_t<TypeGroupVertex, Double> tkey)
|
||||
: cost(cost), vacc(vacc), parent(parent), depth(parent->depth + 1),
|
||||
tkey(tkey)
|
||||
{
|
||||
@ -84,27 +85,27 @@ void found_result(Node *res)
|
||||
}
|
||||
}
|
||||
|
||||
double calc_heuristic_cost_dummy(type_key_t<Double> tkey, Edge::Accessor &edge,
|
||||
Vertex::Accessor &vertex)
|
||||
double calc_heuristic_cost_dummy(type_key_t<TypeGroupVertex, Double> tkey,
|
||||
EdgeAccessor &edge, VertexAccessor &vertex)
|
||||
{
|
||||
assert(!vertex.empty());
|
||||
return 1 - *vertex.at(tkey).get();
|
||||
}
|
||||
|
||||
typedef bool (*EdgeFilter)(DbAccessor &t, Edge::Accessor &, Node *before);
|
||||
typedef bool (*VertexFilter)(DbAccessor &t, Vertex::Accessor &, Node *before);
|
||||
typedef bool (*EdgeFilter)(DbAccessor &t, EdgeAccessor &, Node *before);
|
||||
typedef bool (*VertexFilter)(DbAccessor &t, VertexAccessor &, Node *before);
|
||||
|
||||
bool edge_filter_dummy(DbAccessor &t, Edge::Accessor &e, Node *before)
|
||||
bool edge_filter_dummy(DbAccessor &t, EdgeAccessor &e, Node *before)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vertex_filter_dummy(DbAccessor &t, Vertex::Accessor &va, Node *before)
|
||||
bool vertex_filter_dummy(DbAccessor &t, VertexAccessor &va, Node *before)
|
||||
{
|
||||
return va.fill();
|
||||
}
|
||||
|
||||
bool vertex_filter_contained_dummy(DbAccessor &t, Vertex::Accessor &v,
|
||||
bool vertex_filter_contained_dummy(DbAccessor &t, VertexAccessor &v,
|
||||
Node *before)
|
||||
{
|
||||
if (v.fill()) {
|
||||
@ -128,7 +129,7 @@ bool vertex_filter_contained_dummy(DbAccessor &t, Vertex::Accessor &v,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool vertex_filter_contained(DbAccessor &t, Vertex::Accessor &v, Node *before)
|
||||
bool vertex_filter_contained(DbAccessor &t, VertexAccessor &v, Node *before)
|
||||
{
|
||||
if (v.fill()) {
|
||||
bool found;
|
||||
@ -146,17 +147,18 @@ bool vertex_filter_contained(DbAccessor &t, Vertex::Accessor &v, Node *before)
|
||||
// Vertex filter ima max_depth funkcija te edge filter ima max_depth funkcija.
|
||||
// Jedan za svaku dubinu.
|
||||
// Filtri vracaju true ako element zadovoljava uvjete.
|
||||
auto a_star(Db &db, int64_t sys_id_start, uint max_depth, EdgeFilter e_filter[],
|
||||
VertexFilter v_filter[],
|
||||
double (*calc_heuristic_cost)(type_key_t<Double> tkey,
|
||||
Edge::Accessor &edge,
|
||||
Vertex::Accessor &vertex),
|
||||
int limit)
|
||||
auto a_star(
|
||||
Db &db, int64_t sys_id_start, uint max_depth, EdgeFilter e_filter[],
|
||||
VertexFilter v_filter[],
|
||||
double (*calc_heuristic_cost)(type_key_t<TypeGroupVertex, Double> tkey,
|
||||
EdgeAccessor &edge, VertexAccessor &vertex),
|
||||
int limit)
|
||||
{
|
||||
DbAccessor t(db);
|
||||
type_key_t<Double> tkey = t.vertex_property_family_get("score")
|
||||
.get(Flags::Double)
|
||||
.type_key<Double>();
|
||||
type_key_t<TypeGroupVertex, Double> tkey =
|
||||
t.vertex_property_family_get("score")
|
||||
.get(Flags::Double)
|
||||
.type_key<Double>();
|
||||
|
||||
auto best_found = new std::map<Id, Score>[max_depth];
|
||||
|
||||
|
56
poc/tool.cpp
56
poc/tool.cpp
@ -20,7 +20,7 @@ using namespace std;
|
||||
// generation.
|
||||
|
||||
template <class C>
|
||||
void fill_to_fill(Edge::Accessor &e, const EdgeType &type, C &&consumer)
|
||||
void fill_to_fill(EdgeAccessor &e, const EdgeType &type, C &&consumer)
|
||||
{
|
||||
if (e.fill() && e.edge_type() == type) {
|
||||
auto to = e.to();
|
||||
@ -31,7 +31,7 @@ void fill_to_fill(Edge::Accessor &e, const EdgeType &type, C &&consumer)
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void fill_from_fill(Edge::Accessor &e, const EdgeType &type, C &&consumer)
|
||||
void fill_from_fill(EdgeAccessor &e, const EdgeType &type, C &&consumer)
|
||||
{
|
||||
if (e.fill() && e.edge_type() == type) {
|
||||
auto from = e.from();
|
||||
@ -42,7 +42,7 @@ void fill_from_fill(Edge::Accessor &e, const EdgeType &type, C &&consumer)
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void fill_to_fill(Edge::Accessor &e, C &&consumer)
|
||||
void fill_to_fill(EdgeAccessor &e, C &&consumer)
|
||||
{
|
||||
if (e.fill()) {
|
||||
auto to = e.to();
|
||||
@ -53,7 +53,7 @@ void fill_to_fill(Edge::Accessor &e, C &&consumer)
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void to_fill(Edge::Accessor &e, C &&consumer)
|
||||
void to_fill(EdgeAccessor &e, C &&consumer)
|
||||
{
|
||||
auto to = e.to();
|
||||
if (to.fill()) {
|
||||
@ -62,7 +62,7 @@ void to_fill(Edge::Accessor &e, C &&consumer)
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void to_fill(Edge::Accessor &e, const Label &label, C &&consumer)
|
||||
void to_fill(EdgeAccessor &e, const Label &label, C &&consumer)
|
||||
{
|
||||
auto to = e.to();
|
||||
if (to.fill() && to.has_label(label)) {
|
||||
@ -71,7 +71,7 @@ void to_fill(Edge::Accessor &e, const Label &label, C &&consumer)
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void to_fill(Edge::Accessor &e, const EdgeType &type, const Label &label,
|
||||
void to_fill(EdgeAccessor &e, const EdgeType &type, const Label &label,
|
||||
C &&consumer)
|
||||
{
|
||||
if (e.edge_type() == type) {
|
||||
@ -83,7 +83,7 @@ void to_fill(Edge::Accessor &e, const EdgeType &type, const Label &label,
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void from_fill(Edge::Accessor &e, const EdgeType &type, C &&consumer)
|
||||
void from_fill(EdgeAccessor &e, const EdgeType &type, C &&consumer)
|
||||
{
|
||||
if (e.edge_type() == type) {
|
||||
auto from = e.from();
|
||||
@ -94,7 +94,7 @@ void from_fill(Edge::Accessor &e, const EdgeType &type, C &&consumer)
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void fill_from_fill(Edge::Accessor &e, C &&consumer)
|
||||
void fill_from_fill(EdgeAccessor &e, C &&consumer)
|
||||
{
|
||||
if (e.fill()) {
|
||||
auto from = e.from();
|
||||
@ -144,10 +144,10 @@ void find_fill(I iter, C &&consumer)
|
||||
}
|
||||
}
|
||||
|
||||
void fill_with_bt(unordered_map<string, double> &values, Vertex::Accessor &com,
|
||||
double weight,
|
||||
PropertyFamily::PropertyType::PropertyTypeKey<ArrayString>
|
||||
&prop_vertex_business_types)
|
||||
void fill_with_bt(
|
||||
unordered_map<string, double> &values, VertexAccessor &com, double weight,
|
||||
VertexPropertyFamily::PropertyType::PropertyTypeKey<ArrayString>
|
||||
&prop_vertex_business_types)
|
||||
{
|
||||
auto bus_t = com.at(prop_vertex_business_types);
|
||||
if (bus_t.is_present()) {
|
||||
@ -158,8 +158,8 @@ void fill_with_bt(unordered_map<string, double> &values, Vertex::Accessor &com,
|
||||
}
|
||||
|
||||
void oportunity_employe_company(
|
||||
Vertex::Accessor &va, unordered_map<string, double> &values, double weight,
|
||||
PropertyFamily::PropertyType::PropertyTypeKey<ArrayString>
|
||||
VertexAccessor &va, unordered_map<string, double> &values, double weight,
|
||||
VertexPropertyFamily::PropertyType::PropertyTypeKey<ArrayString>
|
||||
&prop_vertex_business_types,
|
||||
const EdgeType &type_created, const EdgeType &type_works_in,
|
||||
const Label &label_company)
|
||||
@ -192,16 +192,17 @@ auto query(DbAccessor &t, const Id &start_id)
|
||||
const Label &label_company = t.label_find_or_create("Company");
|
||||
const Label &label_opportunuty = t.label_find_or_create("Opportunity");
|
||||
|
||||
auto type_works_in = t.type_find_or_create("Works_In");
|
||||
auto type_reached_to = t.type_find_or_create("Reached_To");
|
||||
auto type_partnered_with = t.type_find_or_create("Partnered_With");
|
||||
auto type_interested_in = t.type_find_or_create("Interested_In");
|
||||
auto type_viewed = t.type_find_or_create("Viewed");
|
||||
auto type_has_match = t.type_find_or_create("Has_Match");
|
||||
auto type_searched_and_clicked =
|
||||
const EdgeType &type_works_in = t.type_find_or_create("Works_In");
|
||||
const EdgeType &type_reached_to = t.type_find_or_create("Reached_To");
|
||||
const EdgeType &type_partnered_with =
|
||||
t.type_find_or_create("Partnered_With");
|
||||
const EdgeType &type_interested_in = t.type_find_or_create("Interested_In");
|
||||
const EdgeType &type_viewed = t.type_find_or_create("Viewed");
|
||||
const EdgeType &type_has_match = t.type_find_or_create("Has_Match");
|
||||
const EdgeType &type_searched_and_clicked =
|
||||
t.type_find_or_create("Searched_And_Clicked");
|
||||
auto type_is_employee = t.type_find_or_create("Is_Employee");
|
||||
auto type_created = t.type_find_or_create("Created");
|
||||
const EdgeType &type_is_employee = t.type_find_or_create("Is_Employee");
|
||||
const EdgeType &type_created = t.type_find_or_create("Created");
|
||||
|
||||
auto prop_edge_status = t.edge_property_family_get("status")
|
||||
.get(Flags::String)
|
||||
@ -362,18 +363,21 @@ int main(int argc, char **argv)
|
||||
DbAccessor t(db);
|
||||
|
||||
int n = 300 * 1000;
|
||||
vector<pair<Vertex::Accessor, unordered_map<string, double>>> coll;
|
||||
vector<pair<VertexAccessor, unordered_map<string, double>>> coll;
|
||||
|
||||
// QUERY BENCHMARK
|
||||
auto begin = clock();
|
||||
int i = 0;
|
||||
iter::for_all_fill(
|
||||
iter::find_fill(
|
||||
t.label_find_or_create("Company").index->for_range_exact(t),
|
||||
[&](auto v) {
|
||||
if (i < n) {
|
||||
coll.push_back(make_pair(v, query(t, v.id())));
|
||||
i++;
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
});
|
||||
n = i;
|
||||
clock_t end = clock();
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
|
||||
return std::move(vertex_accessor);
|
||||
},
|
||||
[&req, &res](Vertex::Accessor&& vertex_accessor) {
|
||||
[&req, &res](VertexAccessor&& vertex_accessor) {
|
||||
return res.send(
|
||||
http::Status::Created,
|
||||
vertex_create_response(vertex_accessor)
|
||||
@ -69,7 +69,7 @@ public:
|
||||
|
||||
return std::move(vertex_accessor);
|
||||
},
|
||||
[&req, &res](Vertex::Accessor&& vertex_accessor) {
|
||||
[&req, &res](VertexAccessor&& vertex_accessor) {
|
||||
if (vertex_accessor.empty()) {
|
||||
return res.send(
|
||||
http::Status::NotFound,
|
||||
@ -111,7 +111,7 @@ public:
|
||||
|
||||
return std::move(vertex_accessor);
|
||||
},
|
||||
[&req, &res](Vertex::Accessor&& vertex_accessor) {
|
||||
[&req, &res](VertexAccessor&& vertex_accessor) {
|
||||
if (vertex_accessor.empty()) {
|
||||
return res.send(
|
||||
http::Status::NotFound,
|
||||
|
@ -29,7 +29,7 @@ using RJStringBuffer = rapidjson::StringBuffer;
|
||||
using RJStringWriter = rapidjson::Writer<RJStringBuffer>;
|
||||
using ptr_RJStringWriter = std::shared_ptr<RJStringWriter>;
|
||||
|
||||
std::string vertex_create_response(const Vertex::Accessor& vertex_accessor)
|
||||
std::string vertex_create_response(const VertexAccessor& vertex_accessor)
|
||||
{
|
||||
// make a string buffer
|
||||
RJStringBuffer buffer;
|
||||
|
@ -5,3 +5,60 @@ Db::Db() = default;
|
||||
Db::Db(const std::string &name) : name_(name) {}
|
||||
|
||||
std::string &Db::name() { return name_; }
|
||||
|
||||
template <class TG, class I, class G>
|
||||
bool Db::create_index_on_vertex_property_family(const char *name, G &coll,
|
||||
I &create_index)
|
||||
{
|
||||
auto &family = coll.property_family_find_or_create(name);
|
||||
bool added_index = false;
|
||||
DbTransaction t(*this, tx_engine.begin([&](auto t) {
|
||||
added_index = family.index.set_index(create_index(t));
|
||||
}));
|
||||
|
||||
if (added_index) {
|
||||
t.trans.wait_for_active();
|
||||
|
||||
auto oindex = family.index.get_write(t.trans);
|
||||
if (oindex.is_present()) {
|
||||
auto index = oindex.get();
|
||||
|
||||
for (auto &vr : coll.access()) {
|
||||
auto v = vr.second.find(t.trans);
|
||||
if (v != nullptr) {
|
||||
if (!index->insert(IndexRecord<TG, std::nullptr_t>(
|
||||
std::nullptr_t(), v, &vr.second))) {
|
||||
// Index is probably unique.
|
||||
auto owned_maybe = family.index.remove_index(index);
|
||||
if (owned_maybe.is_present()) {
|
||||
garbage.dispose(tx_engine.snapshot(),
|
||||
owned_maybe.get().release());
|
||||
}
|
||||
|
||||
t.trans.abort();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index->activate();
|
||||
t.trans.commit();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
t.trans.abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class TG, class K>
|
||||
bool Db::remove_index(IndexHolder<TG, K> &ih)
|
||||
{
|
||||
auto owned_maybe = ih.remove_index();
|
||||
if (owned_maybe.is_present()) {
|
||||
garbage.dispose(tx_engine.snapshot(), owned_maybe.get().release());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -7,35 +7,40 @@ DbAccessor::DbAccessor(Db &db)
|
||||
{
|
||||
}
|
||||
|
||||
DbAccessor::DbAccessor(Db &db, tx::Transaction &t)
|
||||
: db_transaction(DbTransaction(db, t))
|
||||
{
|
||||
}
|
||||
|
||||
// VERTEX METHODS
|
||||
auto DbAccessor::vertex_access()
|
||||
{
|
||||
return iter::make_map(
|
||||
iter::make_iter(this->db_transaction.db.graph.vertices.access()),
|
||||
[&](auto e) -> auto {
|
||||
return Vertex::Accessor(&(e->second), db_transaction);
|
||||
return VertexAccessor(&(e->second), db_transaction);
|
||||
});
|
||||
}
|
||||
|
||||
Option<const Vertex::Accessor> DbAccessor::vertex_find(const Id &id)
|
||||
Option<const VertexAccessor> DbAccessor::vertex_find(const Id &id)
|
||||
{
|
||||
return this->db_transaction.db.graph.vertices.find(db_transaction, id);
|
||||
}
|
||||
|
||||
Vertex::Accessor DbAccessor::vertex_insert()
|
||||
VertexAccessor DbAccessor::vertex_insert()
|
||||
{
|
||||
return this->db_transaction.db.graph.vertices.insert(db_transaction);
|
||||
}
|
||||
|
||||
// EDGE METHODS
|
||||
|
||||
Option<const Edge::Accessor> DbAccessor::edge_find(const Id &id)
|
||||
Option<const EdgeAccessor> DbAccessor::edge_find(const Id &id)
|
||||
{
|
||||
return db_transaction.db.graph.edges.find(db_transaction, id);
|
||||
}
|
||||
|
||||
Edge::Accessor DbAccessor::edge_insert(Vertex::Accessor const &from,
|
||||
Vertex::Accessor const &to)
|
||||
EdgeAccessor DbAccessor::edge_insert(VertexAccessor const &from,
|
||||
VertexAccessor const &to)
|
||||
{
|
||||
auto edge_accessor = db_transaction.db.graph.edges.insert(
|
||||
db_transaction, from.vlist, to.vlist);
|
||||
@ -67,30 +72,55 @@ bool DbAccessor::type_contains(const char *name)
|
||||
}
|
||||
|
||||
// PROPERTY METHODS
|
||||
PropertyFamily &DbAccessor::vertex_property_family_get(const std::string &name)
|
||||
VertexPropertyFamily &
|
||||
DbAccessor::vertex_property_family_get(const std::string &name)
|
||||
{
|
||||
return db_transaction.db.graph.vertices.property_family_find_or_create(
|
||||
name);
|
||||
}
|
||||
|
||||
PropertyFamily &DbAccessor::edge_property_family_get(const std::string &name)
|
||||
EdgePropertyFamily &
|
||||
DbAccessor::edge_property_family_get(const std::string &name)
|
||||
{
|
||||
return db_transaction.db.graph.edges.property_family_find_or_create(name);
|
||||
}
|
||||
|
||||
// PROPERTY HELPER METHODS
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey
|
||||
VertexPropertyFamily::PropertyType::PropertyFamilyKey
|
||||
DbAccessor::vertex_property_key(const std::string &name, Type type)
|
||||
{
|
||||
return vertex_property_family_get(name).get(type).family_key();
|
||||
}
|
||||
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey
|
||||
EdgePropertyFamily::PropertyType::PropertyFamilyKey
|
||||
DbAccessor::edge_property_key(const std::string &name, Type type)
|
||||
{
|
||||
return edge_property_family_get(name).get(type).family_key();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
VertexPropertyFamily::PropertyType::PropertyTypeKey<T>
|
||||
DbAccessor::vertex_property_key(const std::string &name)
|
||||
{
|
||||
return vertex_property_family_get(name).get(T::type).template type_key<T>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
EdgePropertyFamily::PropertyType::PropertyTypeKey<T>
|
||||
DbAccessor::edge_property_key(const std::string &name)
|
||||
{
|
||||
return edge_property_family_get(name).get(T::type).template type_key<T>();
|
||||
}
|
||||
|
||||
// TRANSACTION METHODS
|
||||
void DbAccessor::commit() { db_transaction.trans.commit(); }
|
||||
bool DbAccessor::commit()
|
||||
{
|
||||
if (db_transaction.update_indexes()) {
|
||||
db_transaction.trans.commit();
|
||||
return true;
|
||||
} else {
|
||||
db_transaction.trans.abort();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void DbAccessor::abort() { db_transaction.trans.abort(); }
|
||||
|
63
src/database/db_transaction.cpp
Normal file
63
src/database/db_transaction.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "database/db_transaction.hpp"
|
||||
|
||||
#include "storage/edge.hpp"
|
||||
#include "storage/edge_type/edge_type.hpp"
|
||||
#include "storage/label/label.hpp"
|
||||
#include "storage/vertex.hpp"
|
||||
|
||||
#define TRY(x) \
|
||||
if (!x) { \
|
||||
return false; \
|
||||
}
|
||||
|
||||
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.first.get_family().index.get_write(t);
|
||||
if (opi.is_present()) {
|
||||
TRY(opi.get()->insert(IndexRecord<TG, std::nullptr_t>(
|
||||
std::nullptr_t(), iu.record, iu.vlist)));
|
||||
}
|
||||
|
||||
// TODO: other properti indexes
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DbTransaction::update_indexes()
|
||||
{
|
||||
while (!index_updates.empty()) {
|
||||
auto iu = index_updates.back();
|
||||
|
||||
if (iu.tag == IndexUpdate::EDGE) {
|
||||
auto e = iu.e;
|
||||
|
||||
// TODO: This could be done in batch
|
||||
// NOTE: This assumes that type index is created with the database.
|
||||
TRY(e.record->data.edge_type->index->insert(
|
||||
EdgeTypeIndexRecord(std::nullptr_t(), e.record, e.vlist)));
|
||||
|
||||
TRY(update_property_indexes<TypeGroupEdge>(e, trans));
|
||||
|
||||
} else {
|
||||
auto v = iu.v;
|
||||
|
||||
for (auto l : v.record->data.labels()) {
|
||||
// TODO: This could be done in batch
|
||||
// NOTE: This assumes that label index is created with the
|
||||
// database.
|
||||
TRY(l.get().index->insert(
|
||||
LabelIndexRecord(std::nullptr_t(), v.record, v.vlist)));
|
||||
}
|
||||
|
||||
TRY(update_property_indexes<TypeGroupVertex>(v, trans));
|
||||
}
|
||||
|
||||
index_updates.pop_back();
|
||||
}
|
||||
return true;
|
||||
}
|
@ -20,7 +20,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
static Option<Vertex::Accessor> empty_op_vacc;
|
||||
static Option<VertexAccessor> empty_op_vacc;
|
||||
|
||||
// Base importer with common facilities.
|
||||
class BaseImporter
|
||||
@ -186,7 +186,7 @@ public:
|
||||
// }
|
||||
}
|
||||
|
||||
Option<Vertex::Accessor> const &get_vertex(size_t id)
|
||||
Option<VertexAccessor> const &get_vertex(size_t id)
|
||||
{
|
||||
if (vertices.size() > id) {
|
||||
return vertices[id];
|
||||
@ -214,5 +214,5 @@ protected:
|
||||
ostream &err_stream;
|
||||
|
||||
// All created vertices which have import local id
|
||||
vector<Option<Vertex::Accessor>> vertices;
|
||||
vector<Option<VertexAccessor>> vertices;
|
||||
};
|
||||
|
@ -50,18 +50,18 @@ public:
|
||||
// Loads data from stream and returns number of loaded vertexes.
|
||||
size_t import_vertices(std::fstream &file)
|
||||
{
|
||||
return import(file, create_vertex, true);
|
||||
return import<TypeGroupVertex>(file, create_vertex, true);
|
||||
}
|
||||
|
||||
// Loads data from stream and returns number of loaded edges.
|
||||
size_t import_edges(std::fstream &file)
|
||||
{
|
||||
return import(file, create_edge, false);
|
||||
return import<TypeGroupEdge>(file, create_edge, false);
|
||||
}
|
||||
|
||||
private:
|
||||
// Loads data from file and returns number of loaded name.
|
||||
template <class F>
|
||||
template <class TG, class F>
|
||||
size_t import(std::fstream &file, F f, bool vertex)
|
||||
{
|
||||
string line;
|
||||
@ -81,7 +81,7 @@ private:
|
||||
}
|
||||
|
||||
for (auto p : sub_str) {
|
||||
auto o = get_filler(p, tmp, vertex);
|
||||
auto o = get_filler<TG>(p, tmp, vertex);
|
||||
if (o.is_present()) {
|
||||
fillers.push_back(o.take());
|
||||
} else {
|
||||
@ -132,8 +132,7 @@ private:
|
||||
if (id.is_present()) {
|
||||
|
||||
if (im->vertices.size() <= id.get()) {
|
||||
Option<Vertex::Accessor> empty =
|
||||
make_option<Vertex::Accessor>();
|
||||
Option<VertexAccessor> empty = make_option<VertexAccessor>();
|
||||
im->vertices.insert(im->vertices.end(),
|
||||
id.get() - im->vertices.size() + 1, empty);
|
||||
}
|
||||
@ -166,7 +165,31 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// template <typename F>
|
||||
// Option<unique_ptr<Filler>> make_filler_property(bool vertex,
|
||||
// const char name, Flags
|
||||
// type)
|
||||
// {
|
||||
// if (vertex) {
|
||||
// std::unique_ptr<Filler> f(
|
||||
// F(db.vertex_property_key(name, Type(type))));
|
||||
// return make_option(std::move(f));
|
||||
// } else {
|
||||
// std::unique_ptr<Filler> f(
|
||||
// F(db.edge_property_key(name, Type(type))));
|
||||
// return make_option(std::move(f));
|
||||
// }
|
||||
// }
|
||||
|
||||
template <class TG>
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey
|
||||
prop_key(const char *name, Flags type)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// Returns filler for name:type in header_part. None if error occured.
|
||||
template <class TG>
|
||||
Option<unique_ptr<Filler>> get_filler(char *header_part,
|
||||
vector<char *> &tmp_vec, bool vertex)
|
||||
{
|
||||
@ -193,20 +216,20 @@ private:
|
||||
|
||||
// cout << name << " # " << type << endl;
|
||||
|
||||
auto prop_key = [&](auto name, auto type) -> auto
|
||||
{
|
||||
if (vertex) {
|
||||
return db.vertex_property_key(name, Type(type));
|
||||
} else {
|
||||
return db.edge_property_key(name, Type(type));
|
||||
}
|
||||
};
|
||||
// auto prop_key = [&](auto name, auto type) -> auto
|
||||
// {
|
||||
// if (vertex) {
|
||||
// return db.vertex_property_key(name, Type(type));
|
||||
// } else {
|
||||
// return db.edge_property_key(name, Type(type));
|
||||
// }
|
||||
// };
|
||||
|
||||
if (equal_str(type, "id")) {
|
||||
std::unique_ptr<Filler> f(
|
||||
name[0] == '\0'
|
||||
? new IdFiller()
|
||||
: new IdFiller(make_option(prop_key(name, Flags::Int64))));
|
||||
name[0] == '\0' ? new IdFiller<TG>()
|
||||
: new IdFiller<TG>(make_option(
|
||||
prop_key<TG>(name, Flags::Int64))));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "start_id") || equal_str(type, "from_id") ||
|
||||
@ -234,63 +257,69 @@ private:
|
||||
|
||||
// *********************** PROPERTIES
|
||||
} else if (equal_str(type, "bool")) {
|
||||
// return make_filler_property<BoolFiller>(vertex, name,
|
||||
// Flags::Bool);
|
||||
std::unique_ptr<Filler> f(
|
||||
new BoolFiller(prop_key(name, Flags::Bool)));
|
||||
new BoolFiller<TG>(prop_key<TG>(name, Flags::Bool)));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "double")) {
|
||||
std::unique_ptr<Filler> f(
|
||||
new DoubleFiller(prop_key(name, Flags::Double)));
|
||||
new DoubleFiller<TG>(prop_key<TG>(name, Flags::Double)));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "float")) {
|
||||
std::unique_ptr<Filler> f(
|
||||
new FloatFiller(prop_key(name, Flags::Float)));
|
||||
new FloatFiller<TG>(prop_key<TG>(name, Flags::Float)));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "int")) {
|
||||
std::unique_ptr<Filler> f(
|
||||
new Int32Filler(prop_key(name, Flags::Int32)));
|
||||
new Int32Filler<TG>(prop_key<TG>(name, Flags::Int32)));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "long")) {
|
||||
std::unique_ptr<Filler> f(
|
||||
new Int64Filler(prop_key(name, Flags::Int64)));
|
||||
new Int64Filler<TG>(prop_key<TG>(name, Flags::Int64)));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "string")) {
|
||||
std::unique_ptr<Filler> f(
|
||||
new StringFiller(prop_key(name, Flags::String)));
|
||||
new StringFiller<TG>(prop_key<TG>(name, Flags::String)));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "bool[]")) {
|
||||
std::unique_ptr<Filler> f(make_array_filler<bool, ArrayBool>(
|
||||
*this, prop_key(name, Flags::ArrayBool), to_bool));
|
||||
std::unique_ptr<Filler> f(make_array_filler<TG, bool, ArrayBool>(
|
||||
*this, prop_key<TG>(name, Flags::ArrayBool), to_bool));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "float[]")) {
|
||||
std::unique_ptr<Filler> f(make_array_filler<float, ArrayFloat>(
|
||||
*this, prop_key(name, Flags::ArrayFloat), to_float));
|
||||
std::unique_ptr<Filler> f(make_array_filler<TG, float, ArrayFloat>(
|
||||
*this, prop_key<TG>(name, Flags::ArrayFloat), to_float));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "double[]")) {
|
||||
std::unique_ptr<Filler> f(make_array_filler<double, ArrayDouble>(
|
||||
*this, prop_key(name, Flags::ArrayDouble), to_double));
|
||||
std::unique_ptr<Filler> f(
|
||||
make_array_filler<TG, double, ArrayDouble>(
|
||||
*this, prop_key<TG>(name, Flags::ArrayDouble), to_double));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "int[]")) {
|
||||
std::unique_ptr<Filler> f(make_array_filler<int32_t, ArrayInt32>(
|
||||
*this, prop_key(name, Flags::ArrayInt32), to_int32));
|
||||
std::unique_ptr<Filler> f(
|
||||
make_array_filler<TG, int32_t, ArrayInt32>(
|
||||
*this, prop_key<TG>(name, Flags::ArrayInt32), to_int32));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "long[]")) {
|
||||
std::unique_ptr<Filler> f(make_array_filler<int64_t, ArrayInt64>(
|
||||
*this, prop_key(name, Flags::ArrayInt64), to_int64));
|
||||
std::unique_ptr<Filler> f(
|
||||
make_array_filler<TG, int64_t, ArrayInt64>(
|
||||
*this, prop_key<TG>(name, Flags::ArrayInt64), to_int64));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else if (equal_str(type, "string[]")) {
|
||||
std::unique_ptr<Filler> f(make_array_filler<string, ArrayString>(
|
||||
*this, prop_key(name, Flags::ArrayString), to_string));
|
||||
std::unique_ptr<Filler> f(
|
||||
make_array_filler<TG, string, ArrayString>(
|
||||
*this, prop_key<TG>(name, Flags::ArrayString), to_string));
|
||||
return make_option(std::move(f));
|
||||
|
||||
} else {
|
||||
@ -315,6 +344,20 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
PropertyFamily<TypeGroupVertex>::PropertyType::PropertyFamilyKey
|
||||
CSVImporter::prop_key<TypeGroupVertex>(const char *name, Flags type)
|
||||
{
|
||||
return db.vertex_property_key(name, Type(type));
|
||||
}
|
||||
|
||||
template <>
|
||||
PropertyFamily<TypeGroupEdge>::PropertyType::PropertyFamilyKey
|
||||
CSVImporter::prop_key<TypeGroupEdge>(const char *name, Flags type)
|
||||
{
|
||||
return db.edge_property_key(name, Type(type));
|
||||
}
|
||||
|
||||
// Imports all -v "vertex_file_path.csv" vertices and -e "edge_file_path.csv"
|
||||
// edges from specified files. Also defines arguments -d, -ad, -w, -err, -info.
|
||||
// -d delimiter => sets delimiter for parsing .csv files. Default is ,
|
||||
|
@ -14,20 +14,36 @@ class ElementSkeleton
|
||||
{
|
||||
|
||||
public:
|
||||
Prop(PropertyFamily::PropertyType::PropertyFamilyKey key,
|
||||
Prop(VertexPropertyFamily::PropertyType::PropertyFamilyKey key,
|
||||
Option<std::shared_ptr<Property>> &&prop)
|
||||
: key(key), prop(std::move(prop))
|
||||
: key_v(key), prop(std::move(prop))
|
||||
{
|
||||
}
|
||||
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey key;
|
||||
Prop(EdgePropertyFamily::PropertyType::PropertyFamilyKey key,
|
||||
Option<std::shared_ptr<Property>> &&prop)
|
||||
: key_e(key), prop(std::move(prop))
|
||||
{
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
VertexPropertyFamily::PropertyType::PropertyFamilyKey key_v;
|
||||
EdgePropertyFamily::PropertyType::PropertyFamilyKey key_e;
|
||||
};
|
||||
Option<std::shared_ptr<Property>> prop;
|
||||
};
|
||||
|
||||
public:
|
||||
ElementSkeleton(DbAccessor &db) : db(db){};
|
||||
|
||||
void add_property(PropertyFamily::PropertyType::PropertyFamilyKey key,
|
||||
void add_property(VertexPropertyFamily::PropertyType::PropertyFamilyKey key,
|
||||
std::shared_ptr<Property> &&prop)
|
||||
{
|
||||
properties.push_back(Prop(key, make_option(std::move(prop))));
|
||||
}
|
||||
|
||||
void add_property(EdgePropertyFamily::PropertyType::PropertyFamilyKey key,
|
||||
std::shared_ptr<Property> &&prop)
|
||||
{
|
||||
properties.push_back(Prop(key, make_option(std::move(prop))));
|
||||
@ -42,17 +58,17 @@ public:
|
||||
|
||||
void set_type(EdgeType const &type) { this->type = make_option(&type); }
|
||||
|
||||
void set_from(Vertex::Accessor &&va)
|
||||
void set_from(VertexAccessor &&va)
|
||||
{
|
||||
from_va = make_option<Vertex::Accessor>(std::move(va));
|
||||
from_va = make_option<VertexAccessor>(std::move(va));
|
||||
}
|
||||
|
||||
void set_to(Vertex::Accessor &&va)
|
||||
void set_to(VertexAccessor &&va)
|
||||
{
|
||||
to_va = make_option<Vertex::Accessor>(std::move(va));
|
||||
to_va = make_option<VertexAccessor>(std::move(va));
|
||||
}
|
||||
|
||||
Vertex::Accessor add_vertex()
|
||||
VertexAccessor add_vertex()
|
||||
{
|
||||
auto va = db.vertex_insert();
|
||||
|
||||
@ -60,7 +76,11 @@ public:
|
||||
// std::cout << *l << std::endl;
|
||||
va.add_label(*l);
|
||||
}
|
||||
add_propreties(va);
|
||||
|
||||
for (auto prop : properties) {
|
||||
assert(prop.prop.is_present());
|
||||
va.set(prop.key_v, prop.prop.take());
|
||||
}
|
||||
|
||||
return va;
|
||||
}
|
||||
@ -79,7 +99,11 @@ public:
|
||||
if (type.is_present()) {
|
||||
ve.edge_type(*type.get());
|
||||
}
|
||||
add_propreties(ve);
|
||||
|
||||
for (auto prop : properties) {
|
||||
assert(prop.prop.is_present());
|
||||
ve.set(prop.key_e, prop.prop.take());
|
||||
}
|
||||
|
||||
return make_option<std::string>();
|
||||
}
|
||||
@ -87,8 +111,8 @@ public:
|
||||
void clear()
|
||||
{
|
||||
el_id = make_option<size_t>();
|
||||
to_va = make_option<Vertex::Accessor>();
|
||||
from_va = make_option<Vertex::Accessor>();
|
||||
to_va = make_option<VertexAccessor>();
|
||||
from_va = make_option<VertexAccessor>();
|
||||
type = make_option<EdgeType const *>();
|
||||
labels.clear();
|
||||
properties.clear();
|
||||
@ -98,20 +122,20 @@ public:
|
||||
Option<size_t> element_id() { return el_id; }
|
||||
|
||||
private:
|
||||
template <class A>
|
||||
void add_propreties(A &ra)
|
||||
{
|
||||
for (auto prop : properties) {
|
||||
assert(prop.prop.is_present());
|
||||
ra.set(prop.key, prop.prop.take());
|
||||
}
|
||||
}
|
||||
// template <class A>
|
||||
// void add_propreties(A &ra)
|
||||
// {
|
||||
// for (auto prop : properties) {
|
||||
// assert(prop.prop.is_present());
|
||||
// ra.set(prop.key, prop.prop.take());
|
||||
// }
|
||||
// }
|
||||
|
||||
DbAccessor &db;
|
||||
|
||||
Option<size_t> el_id;
|
||||
Option<Vertex::Accessor> to_va;
|
||||
Option<Vertex::Accessor> from_va;
|
||||
Option<VertexAccessor> to_va;
|
||||
Option<VertexAccessor> from_va;
|
||||
Option<EdgeType const *> type;
|
||||
std::vector<Label const *> labels;
|
||||
std::vector<Prop> properties;
|
||||
|
@ -4,14 +4,15 @@
|
||||
#include "import/fillings/common.hpp"
|
||||
#include "import/fillings/filler.hpp"
|
||||
|
||||
template <class T, class A>
|
||||
template <class TG, class T, class A>
|
||||
class ArrayFiller : public Filler
|
||||
{
|
||||
|
||||
public:
|
||||
ArrayFiller(BaseImporter &db,
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey key,
|
||||
T (*f)(const char *))
|
||||
ArrayFiller(
|
||||
BaseImporter &db,
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key,
|
||||
T (*f)(const char *))
|
||||
: bim(db), key(key), f(f)
|
||||
{
|
||||
}
|
||||
@ -36,15 +37,16 @@ public:
|
||||
|
||||
private:
|
||||
BaseImporter &bim;
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey key;
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
|
||||
vector<char *> sub_str;
|
||||
T (*f)(const char *);
|
||||
};
|
||||
|
||||
template <class T, class A>
|
||||
auto make_array_filler(BaseImporter &db,
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey key,
|
||||
T (*f)(const char *))
|
||||
template <class TG, class T, class A>
|
||||
auto make_array_filler(
|
||||
BaseImporter &db,
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key,
|
||||
T (*f)(const char *))
|
||||
{
|
||||
return new ArrayFiller<T, A>(db, key, f);
|
||||
return new ArrayFiller<TG, T, A>(db, key, f);
|
||||
}
|
||||
|
@ -6,11 +6,13 @@
|
||||
#include "storage/model/properties/flags.hpp"
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
|
||||
template <class TG>
|
||||
class BoolFiller : public Filler
|
||||
{
|
||||
|
||||
public:
|
||||
BoolFiller(PropertyFamily::PropertyType::PropertyFamilyKey key) : key(key)
|
||||
BoolFiller(typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
|
||||
: key(key)
|
||||
{
|
||||
}
|
||||
|
||||
@ -26,5 +28,5 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey key;
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
|
||||
};
|
||||
|
@ -6,11 +6,14 @@
|
||||
#include "storage/model/properties/flags.hpp"
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
|
||||
template <class TG>
|
||||
class DoubleFiller : public Filler
|
||||
{
|
||||
|
||||
public:
|
||||
DoubleFiller(PropertyFamily::PropertyType::PropertyFamilyKey key) : key(key)
|
||||
DoubleFiller(
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
|
||||
: key(key)
|
||||
{
|
||||
}
|
||||
// Fills skeleton with data from str. Returns error description if
|
||||
@ -25,5 +28,5 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey key;
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
|
||||
};
|
||||
|
@ -6,11 +6,14 @@
|
||||
#include "storage/model/properties/flags.hpp"
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
|
||||
template <class TG>
|
||||
class FloatFiller : public Filler
|
||||
{
|
||||
|
||||
public:
|
||||
FloatFiller(PropertyFamily::PropertyType::PropertyFamilyKey key) : key(key)
|
||||
FloatFiller(
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
|
||||
: key(key)
|
||||
{
|
||||
}
|
||||
// Fills skeleton with data from str. Returns error description if
|
||||
@ -25,5 +28,5 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey key;
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
|
||||
};
|
||||
|
@ -18,9 +18,9 @@ public:
|
||||
{
|
||||
if (str[0] != '\0') {
|
||||
auto id = atol(str);
|
||||
Option<Vertex::Accessor> const &oav = bim.get_vertex(id);
|
||||
Option<VertexAccessor> const &oav = bim.get_vertex(id);
|
||||
if (oav.is_present()) {
|
||||
data.set_from(Vertex::Accessor(oav.get()));
|
||||
data.set_from(VertexAccessor(oav.get()));
|
||||
return make_option<std::string>();
|
||||
} else {
|
||||
return make_option(
|
||||
|
@ -2,16 +2,20 @@
|
||||
|
||||
#include "import/fillings/filler.hpp"
|
||||
|
||||
template <class TG>
|
||||
class IdFiller : public Filler
|
||||
{
|
||||
|
||||
public:
|
||||
IdFiller()
|
||||
: key(make_option<PropertyFamily::PropertyType::PropertyFamilyKey>())
|
||||
: key(make_option<
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey>())
|
||||
{
|
||||
}
|
||||
|
||||
IdFiller(Option<PropertyFamily::PropertyType::PropertyFamilyKey> key)
|
||||
IdFiller(
|
||||
Option<typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey>
|
||||
key)
|
||||
: key(key)
|
||||
{
|
||||
assert(!key.is_present() ||
|
||||
@ -34,5 +38,5 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
Option<PropertyFamily::PropertyType::PropertyFamilyKey> key;
|
||||
Option<typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey> key;
|
||||
};
|
||||
|
@ -6,11 +6,14 @@
|
||||
#include "storage/model/properties/flags.hpp"
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
|
||||
template <class TG>
|
||||
class Int32Filler : public Filler
|
||||
{
|
||||
|
||||
public:
|
||||
Int32Filler(PropertyFamily::PropertyType::PropertyFamilyKey key) : key(key)
|
||||
Int32Filler(
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
|
||||
: key(key)
|
||||
{
|
||||
}
|
||||
|
||||
@ -26,5 +29,5 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey key;
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
|
||||
};
|
||||
|
@ -6,11 +6,14 @@
|
||||
#include "storage/model/properties/flags.hpp"
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
|
||||
template <class TG>
|
||||
class Int64Filler : public Filler
|
||||
{
|
||||
|
||||
public:
|
||||
Int64Filler(PropertyFamily::PropertyType::PropertyFamilyKey key) : key(key)
|
||||
Int64Filler(
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
|
||||
: key(key)
|
||||
{
|
||||
}
|
||||
// Fills skeleton with data from str. Returns error description if
|
||||
@ -25,5 +28,5 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey key;
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
|
||||
};
|
||||
|
@ -6,11 +6,14 @@
|
||||
#include "storage/model/properties/flags.hpp"
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
|
||||
template <class TG>
|
||||
class StringFiller : public Filler
|
||||
{
|
||||
|
||||
public:
|
||||
StringFiller(PropertyFamily::PropertyType::PropertyFamilyKey key) : key(key)
|
||||
StringFiller(
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
|
||||
: key(key)
|
||||
{
|
||||
}
|
||||
// Fills skeleton with data from str. Returns error description if
|
||||
@ -25,5 +28,5 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey key;
|
||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
|
||||
};
|
||||
|
@ -18,9 +18,9 @@ public:
|
||||
{
|
||||
if (str[0] != '\0') {
|
||||
auto id = atol(str);
|
||||
Option<Vertex::Accessor> const &oav = bim.get_vertex(id);
|
||||
Option<VertexAccessor> const &oav = bim.get_vertex(id);
|
||||
if (oav.is_present()) {
|
||||
data.set_to(Vertex::Accessor(oav.get()));
|
||||
data.set_to(VertexAccessor(oav.get()));
|
||||
return make_option<std::string>();
|
||||
} else {
|
||||
return make_option(
|
||||
|
@ -1,6 +1,10 @@
|
||||
#include "query_engine/util.hpp"
|
||||
|
||||
void print_props(const Properties &properties)
|
||||
#include "storage/type_group_edge.hpp"
|
||||
#include "storage/type_group_vertex.hpp"
|
||||
|
||||
template <class T>
|
||||
void print_props(const Properties<T> &properties)
|
||||
{
|
||||
StringBuffer buffer;
|
||||
JsonWriter<StringBuffer> writer(buffer);
|
||||
@ -8,16 +12,42 @@ void print_props(const Properties &properties)
|
||||
cout << buffer.str() << endl;
|
||||
}
|
||||
|
||||
void cout_properties(const Properties &properties)
|
||||
template <class T>
|
||||
void cout_properties(const Properties<T> &properties)
|
||||
{
|
||||
ConsoleWriter writer;
|
||||
properties.accept(writer);
|
||||
cout << "----" << endl;
|
||||
}
|
||||
|
||||
void cout_property(const prop_key_t &key, const Property &property)
|
||||
template <class T>
|
||||
void cout_property(
|
||||
const typename PropertyFamily<T>::PropertyType::PropertyFamilyKey &key,
|
||||
const Property &property)
|
||||
{
|
||||
ConsoleWriter writer;
|
||||
writer.handle(key, property);
|
||||
writer.handle<T>(key, property);
|
||||
cout << "----" << endl;
|
||||
}
|
||||
|
||||
template void
|
||||
print_props<TypeGroupEdge>(const Properties<TypeGroupEdge> &properties);
|
||||
|
||||
template void
|
||||
print_props<TypeGroupVertex>(const Properties<TypeGroupVertex> &properties);
|
||||
|
||||
template void
|
||||
cout_properties<TypeGroupEdge>(const Properties<TypeGroupEdge> &properties);
|
||||
|
||||
template void
|
||||
cout_properties<TypeGroupVertex>(const Properties<TypeGroupVertex> &properties);
|
||||
|
||||
template void cout_property<TypeGroupEdge>(
|
||||
const typename PropertyFamily<
|
||||
TypeGroupEdge>::PropertyType::PropertyFamilyKey &key,
|
||||
const Property &property);
|
||||
|
||||
template void cout_property<TypeGroupVertex>(
|
||||
const typename PropertyFamily<
|
||||
TypeGroupVertex>::PropertyType::PropertyFamilyKey &key,
|
||||
const Property &property);
|
||||
|
@ -1,22 +1,22 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
|
||||
void Edge::Accessor::edge_type(edge_type_ref_t edge_type)
|
||||
void EdgeAccessor::edge_type(edge_type_ref_t edge_type)
|
||||
{
|
||||
this->record->data.edge_type = &edge_type.get();
|
||||
}
|
||||
|
||||
edge_type_ref_t Edge::Accessor::edge_type() const
|
||||
edge_type_ref_t EdgeAccessor::edge_type() const
|
||||
{
|
||||
runtime_assert(this->record->data.edge_type != nullptr, "EdgeType is null");
|
||||
return edge_type_ref_t(*this->record->data.edge_type);
|
||||
}
|
||||
|
||||
Vertex::Accessor Edge::Accessor::from() const
|
||||
VertexAccessor EdgeAccessor::from() const
|
||||
{
|
||||
return Vertex::Accessor(this->vlist->from(), this->db);
|
||||
return VertexAccessor(this->vlist->from(), this->db);
|
||||
}
|
||||
|
||||
Vertex::Accessor Edge::Accessor::to() const
|
||||
VertexAccessor EdgeAccessor::to() const
|
||||
{
|
||||
return Vertex::Accessor(this->vlist->to(), this->db);
|
||||
return VertexAccessor(this->vlist->to(), this->db);
|
||||
}
|
||||
|
@ -1,9 +1,19 @@
|
||||
#include "storage/edge_type/edge_type.hpp"
|
||||
|
||||
EdgeType::EdgeType() {}
|
||||
EdgeType::EdgeType(const std::string &id) : id(id) {}
|
||||
EdgeType::EdgeType(const char *id) : id(std::string(id)) {}
|
||||
EdgeType::EdgeType(std::string &&id) : id(std::move(id)) {}
|
||||
EdgeType::EdgeType(const std::string &id)
|
||||
: id(id), index(std::unique_ptr<type_index_t>(new type_index_t()))
|
||||
{
|
||||
}
|
||||
EdgeType::EdgeType(const char *id)
|
||||
: id(std::string(id)),
|
||||
index(std::unique_ptr<type_index_t>(new type_index_t()))
|
||||
{
|
||||
}
|
||||
EdgeType::EdgeType(std::string &&id)
|
||||
: id(std::move(id)),
|
||||
index(std::unique_ptr<type_index_t>(new type_index_t()))
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const EdgeType &lhs, const EdgeType &rhs)
|
||||
{
|
||||
|
@ -1,20 +1,21 @@
|
||||
#include "storage/edges.hpp"
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "utils/iterator/iterator.hpp"
|
||||
|
||||
Option<const Edge::Accessor> Edges::find(DbTransaction &t, const Id &id)
|
||||
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 Edge::Accessor>();
|
||||
return make_option<const EdgeAccessor>();
|
||||
|
||||
return make_option_const(Edge::Accessor(&edges_iterator->second, t));
|
||||
return make_option_const(EdgeAccessor(&edges_iterator->second, t));
|
||||
}
|
||||
|
||||
Edge::Accessor Edges::insert(DbTransaction &t, VertexRecord *from,
|
||||
VertexRecord *to)
|
||||
EdgeAccessor Edges::insert(DbTransaction &t, VertexRecord *from,
|
||||
VertexRecord *to)
|
||||
{
|
||||
// get next vertex id
|
||||
auto next = counter.next(std::memory_order_acquire);
|
||||
@ -29,16 +30,18 @@ Edge::Accessor Edges::insert(DbTransaction &t, VertexRecord *from,
|
||||
// create new vertex
|
||||
auto inserted_edge_record = result.first;
|
||||
auto edge = inserted_edge_record->second.insert(t.trans);
|
||||
t.to_update_index<TypeGroupEdge>(&inserted_edge_record->second, edge);
|
||||
|
||||
return Edge::Accessor(edge, &inserted_edge_record->second, t);
|
||||
return EdgeAccessor(edge, &inserted_edge_record->second, t);
|
||||
}
|
||||
|
||||
PropertyFamily &Edges::property_family_find_or_create(const std::string &name)
|
||||
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()) {
|
||||
PropertyFamily *family = new PropertyFamily(name);
|
||||
EdgePropertyFamily *family = new EdgePropertyFamily(name);
|
||||
auto res = acc.insert(name, family);
|
||||
if (!res.second) {
|
||||
delete family;
|
||||
|
11
src/storage/garbage/garbage.cpp
Normal file
11
src/storage/garbage/garbage.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "storage/garbage/garbage.hpp"
|
||||
|
||||
void Garbage::dispose(tx::Snapshot<Id> &&snapshot, DeleteSensitive *data)
|
||||
{
|
||||
// TODO: add to list
|
||||
}
|
||||
|
||||
void Garbage::clean(tx::Engine &engine)
|
||||
{
|
||||
// TODO: iterator throug list and check snapshot
|
||||
}
|
@ -2,14 +2,28 @@
|
||||
|
||||
#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()
|
||||
: IndexBase<T, K>(false, None)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T, class K>
|
||||
NonUniqueUnorderedIndex<T, K>::NonUniqueUnorderedIndex(tx::Transaction const &t)
|
||||
: IndexBase<T, K>(false, None, t)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T, class K>
|
||||
bool NonUniqueUnorderedIndex<T, K>::insert(IndexRecord<T, K> &&value)
|
||||
{
|
||||
@ -18,7 +32,7 @@ bool NonUniqueUnorderedIndex<T, K>::insert(IndexRecord<T, K> &&value)
|
||||
}
|
||||
|
||||
template <class T, class K>
|
||||
std::unique_ptr<IteratorBase<const typename T::Accessor>>
|
||||
std::unique_ptr<IteratorBase<const typename T::accessor_t>>
|
||||
NonUniqueUnorderedIndex<T, K>::for_range(DbAccessor &t, Border<K> from,
|
||||
Border<K> to)
|
||||
{
|
||||
@ -39,14 +53,14 @@ auto NonUniqueUnorderedIndex<T, K>::for_range_exact(DbAccessor &t_v,
|
||||
const IndexRecord<T, K> &r = *it;
|
||||
if (from < r.key && to > r.key &&
|
||||
r.is_valid(t.db_transaction.trans)) {
|
||||
const typename T::Accessor acc = r.access(t.db_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>();
|
||||
return Option<const typename T::accessor_t>();
|
||||
});
|
||||
}
|
||||
|
||||
@ -56,6 +70,5 @@ void NonUniqueUnorderedIndex<T, K>::clean(DbTransaction &)
|
||||
// TODO: Actual cleaning
|
||||
}
|
||||
|
||||
#include "storage/vertex.hpp"
|
||||
// #include "utils/singleton.hpp"
|
||||
template class NonUniqueUnorderedIndex<Vertex, std::nullptr_t>;
|
||||
template class NonUniqueUnorderedIndex<TypeGroupEdge, std::nullptr_t>;
|
||||
template class NonUniqueUnorderedIndex<TypeGroupVertex, std::nullptr_t>;
|
||||
|
91
src/storage/indexes/impl/unique_ordered_index.cpp
Normal file
91
src/storage/indexes/impl/unique_ordered_index.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
#include "storage/indexes/impl/unique_ordered_index.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(Order order)
|
||||
: IndexBase<T, K>(true, order)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T, class K>
|
||||
UniqueOrderedIndex<T, K>::UniqueOrderedIndex(Order order,
|
||||
tx::Transaction const &t)
|
||||
: IndexBase<T, K>(true, order, t)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T, class K>
|
||||
bool UniqueOrderedIndex<T, K>::insert(IndexRecord<T, K> &&value)
|
||||
{
|
||||
if (this->order == Descending) {
|
||||
value.set_descending();
|
||||
}
|
||||
return set.access().insert(std::move(value)).second;
|
||||
}
|
||||
|
||||
template <class T, class K>
|
||||
std::unique_ptr<IteratorBase<const typename T::accessor_t>>
|
||||
UniqueOrderedIndex<T, K>::for_range(DbAccessor &t, Border<K> from, Border<K> to)
|
||||
{
|
||||
return std::make_unique<decltype(
|
||||
for_range_exact(t, std::move(from), std::move(to)))>(
|
||||
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->order == Ascending && from_v.key.is_present()) {
|
||||
begin = acc.cfind_or_larger(from_v);
|
||||
} else if (this->order == Descending && to_v.key.is_present()) {
|
||||
begin = acc.cfind_or_larger(to_v);
|
||||
end = from_v;
|
||||
} else {
|
||||
assert(this->order != None);
|
||||
}
|
||||
|
||||
return iter::make_iterator([
|
||||
it = std::move(begin), b_end = std::move(end), t = t_v,
|
||||
hold_acc = std::move(acc)
|
||||
]() mutable->auto {
|
||||
while (b_end >= it->key) {
|
||||
const IndexRecord<T, K> &r = *it;
|
||||
if (r.is_valid(t.db_transaction.trans)) {
|
||||
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>();
|
||||
});
|
||||
}
|
||||
|
||||
template <class T, class K>
|
||||
void UniqueOrderedIndex<T, K>::clean(DbTransaction &)
|
||||
{
|
||||
// TODO: Actual cleaning
|
||||
}
|
||||
|
||||
template class UniqueOrderedIndex<TypeGroupEdge, std::nullptr_t>;
|
||||
template class UniqueOrderedIndex<TypeGroupVertex, std::nullptr_t>;
|
39
src/storage/indexes/index_base.cpp
Normal file
39
src/storage/indexes/index_base.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#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(bool unique, Order order)
|
||||
: unique(unique), order(order), created(Id(0)), active(true)
|
||||
{
|
||||
}
|
||||
|
||||
template <class TG, class K>
|
||||
IndexBase<TG, K>::IndexBase(bool unique, Order order, const tx::Transaction &t)
|
||||
: unique(unique), order(order), 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>;
|
66
src/storage/indexes/index_holder.cpp
Normal file
66
src/storage/indexes/index_holder.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#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>;
|
46
src/storage/indexes/index_record.cpp
Normal file
46
src/storage/indexes/index_record.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include "storage/indexes/index_record.hpp"
|
||||
|
||||
#include "storage/type_group_edge.hpp"
|
||||
#include "storage/type_group_vertex.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());
|
||||
return record == vlist->find(t);
|
||||
}
|
||||
|
||||
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>;
|
14
src/storage/indexes/index_update.cpp
Normal file
14
src/storage/indexes/index_update.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#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}};
|
||||
}
|
@ -4,7 +4,11 @@
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
#include "utils/option.hpp"
|
||||
|
||||
const Property &Properties::at(PropertyFamily &fam) const
|
||||
#include "storage/type_group_edge.hpp"
|
||||
#include "storage/type_group_vertex.hpp"
|
||||
|
||||
template <class TG>
|
||||
const Property &Properties<TG>::at(PropertyFamily<TG> &fam) const
|
||||
{
|
||||
// It doesn't matter whit which type
|
||||
// find is called, thats why getNull
|
||||
@ -18,7 +22,8 @@ const Property &Properties::at(PropertyFamily &fam) const
|
||||
return *it->second.get();
|
||||
}
|
||||
|
||||
const Property &Properties::at(prop_key_t &key) const
|
||||
template <class TG>
|
||||
const Property &Properties<TG>::at(prop_key_t &key) const
|
||||
{
|
||||
auto it = props.find(key);
|
||||
|
||||
@ -28,8 +33,9 @@ const Property &Properties::at(prop_key_t &key) const
|
||||
return *it->second.get();
|
||||
}
|
||||
|
||||
template <class TG>
|
||||
template <class T>
|
||||
auto Properties::at(type_key_t<T> &key) const
|
||||
auto Properties<TG>::at(type_key_t<T> &key) const
|
||||
{
|
||||
auto f_key = key.family_key();
|
||||
auto it = props.find(f_key);
|
||||
@ -41,8 +47,9 @@ auto Properties::at(type_key_t<T> &key) const
|
||||
return make_option(&(it->second.get()->template as<T>().value_ref()));
|
||||
}
|
||||
|
||||
template <class TG>
|
||||
template <class T, class... Args>
|
||||
void Properties::set(type_key_t<T> &key, Args &&... args)
|
||||
void Properties<TG>::set(type_key_t<T> &key, Args &&... args)
|
||||
{
|
||||
auto value = std::make_shared<T>(std::forward<Args>(args)...);
|
||||
|
||||
@ -59,7 +66,8 @@ void Properties::set(type_key_t<T> &key, Args &&... args)
|
||||
}
|
||||
}
|
||||
|
||||
void Properties::set(prop_key_t &key, Property::sptr value)
|
||||
template <class TG>
|
||||
void Properties<TG>::set(prop_key_t &key, Property::sptr value)
|
||||
{
|
||||
// TODO: There is uneccesary copying of value here.
|
||||
auto result = props.insert(make_pair(key, value));
|
||||
@ -72,9 +80,14 @@ void Properties::set(prop_key_t &key, Property::sptr value)
|
||||
}
|
||||
}
|
||||
|
||||
void Properties::clear(prop_key_t &key) { props.erase(key); }
|
||||
template <class TG>
|
||||
void Properties<TG>::clear(prop_key_t &key)
|
||||
{
|
||||
props.erase(key);
|
||||
}
|
||||
|
||||
void Properties::clear(PropertyFamily &fam)
|
||||
template <class TG>
|
||||
void Properties<TG>::clear(PropertyFamily<TG> &fam)
|
||||
{
|
||||
// It doesn't matter whit which type
|
||||
// find is called, thats why getNull
|
||||
@ -84,9 +97,6 @@ void Properties::clear(PropertyFamily &fam)
|
||||
props.erase(key);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void Properties::set<Null>(type_key_t<Null> &key)
|
||||
{
|
||||
auto fk = key.family_key();
|
||||
clear(fk);
|
||||
}
|
||||
template class Properties<TypeGroupEdge>;
|
||||
|
||||
template class Properties<TypeGroupVertex>;
|
||||
|
@ -1,19 +1,31 @@
|
||||
#include "storage/model/properties/property_family.hpp"
|
||||
|
||||
PropertyFamily::PropertyFamily(std::string const &name_v)
|
||||
#include "storage/type_group_edge.hpp"
|
||||
#include "storage/type_group_vertex.hpp"
|
||||
|
||||
template <class T>
|
||||
PropertyFamily<T>::PropertyFamily(std::string const &name_v)
|
||||
: name_v(std::forward<const std::string>(name_v))
|
||||
{
|
||||
null_type = &get(Flags::Null);
|
||||
}
|
||||
PropertyFamily::PropertyFamily(std::string &&name_v) : name_v(std::move(name_v))
|
||||
|
||||
template <class T>
|
||||
PropertyFamily<T>::PropertyFamily(std::string &&name_v)
|
||||
: name_v(std::move(name_v))
|
||||
{
|
||||
null_type = &get(Flags::Null);
|
||||
}
|
||||
|
||||
std::string const &PropertyFamily::name() const { return name_v; }
|
||||
template <class T>
|
||||
std::string const &PropertyFamily<T>::name() const
|
||||
{
|
||||
return name_v;
|
||||
}
|
||||
|
||||
// Returns type if it exists otherwise creates it.
|
||||
PropertyFamily::PropertyType &PropertyFamily::get(Type type)
|
||||
template <class T>
|
||||
typename PropertyFamily<T>::PropertyType &PropertyFamily<T>::get(Type type)
|
||||
{
|
||||
auto acc = types.access();
|
||||
auto it = acc.find(type);
|
||||
@ -26,16 +38,25 @@ PropertyFamily::PropertyType &PropertyFamily::get(Type type)
|
||||
return *(it->second);
|
||||
}
|
||||
|
||||
PropertyFamily::PropertyType::PropertyType(PropertyFamily &family, Type type)
|
||||
template <class T>
|
||||
PropertyFamily<T>::PropertyType::PropertyType(PropertyFamily &family, Type type)
|
||||
: family(family), type(std::move(type))
|
||||
{
|
||||
}
|
||||
|
||||
bool PropertyFamily::PropertyType::is(Type &t) const { return type == t; }
|
||||
template <class T>
|
||||
bool PropertyFamily<T>::PropertyType::is(Type &t) const
|
||||
{
|
||||
return type == t;
|
||||
}
|
||||
|
||||
// Returns key ordered on POINTERS to PropertyFamily
|
||||
PropertyFamily::PropertyType::PropertyFamilyKey
|
||||
PropertyFamily::PropertyType::family_key()
|
||||
template <class T>
|
||||
typename PropertyFamily<T>::PropertyType::PropertyFamilyKey
|
||||
PropertyFamily<T>::PropertyType::family_key()
|
||||
{
|
||||
return PropertyFamilyKey(*this);
|
||||
}
|
||||
|
||||
template class PropertyFamily<TypeGroupEdge>;
|
||||
template class PropertyFamily<TypeGroupVertex>;
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "storage/record_accessor.hpp"
|
||||
|
||||
template <class T, class Derived, class vlist_t>
|
||||
template <class V>
|
||||
auto RecordAccessor<T, Derived, vlist_t>::at(type_key_t<V> &key) const
|
||||
{
|
||||
return properties().template at<V>(key);
|
||||
}
|
||||
// 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);
|
||||
// }
|
||||
|
@ -1,64 +1,61 @@
|
||||
#include "database/db.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
|
||||
#include "database/db.hpp"
|
||||
#include "storage/vertex_record.hpp"
|
||||
#include "storage/vertices.hpp"
|
||||
#include "utils/iterator/iterator.hpp"
|
||||
|
||||
size_t Vertex::Accessor::out_degree() const
|
||||
size_t VertexAccessor::out_degree() const
|
||||
{
|
||||
return this->record->data.out.degree();
|
||||
}
|
||||
|
||||
size_t Vertex::Accessor::in_degree() const
|
||||
size_t VertexAccessor::in_degree() const
|
||||
{
|
||||
return this->record->data.in.degree();
|
||||
}
|
||||
|
||||
size_t Vertex::Accessor::degree() const { return in_degree() + out_degree(); }
|
||||
size_t VertexAccessor::degree() const { return in_degree() + out_degree(); }
|
||||
|
||||
bool Vertex::Accessor::add_label(const Label &label)
|
||||
bool VertexAccessor::add_label(const Label &label)
|
||||
{
|
||||
// update vertex
|
||||
if (this->record->data.labels.add(label)) {
|
||||
label.index->insert(create_index_record());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return this->record->data.labels.add(label);
|
||||
}
|
||||
|
||||
bool Vertex::Accessor::remove_label(const Label &label)
|
||||
bool VertexAccessor::remove_label(const Label &label)
|
||||
{
|
||||
// update vertex
|
||||
return this->record->data.labels.remove(label);
|
||||
}
|
||||
|
||||
bool Vertex::Accessor::has_label(const Label &label) const
|
||||
bool VertexAccessor::has_label(const Label &label) const
|
||||
{
|
||||
return this->record->data.labels.has(label);
|
||||
}
|
||||
|
||||
const std::set<label_ref_t> &Vertex::Accessor::labels() const
|
||||
const std::set<label_ref_t> &VertexAccessor::labels() const
|
||||
{
|
||||
return this->record->data.labels();
|
||||
}
|
||||
|
||||
// Returns unfilled accessors
|
||||
auto Vertex::Accessor::out() const
|
||||
auto VertexAccessor::out() const
|
||||
{
|
||||
DbTransaction &t = this->db;
|
||||
return iter::make_map(
|
||||
iter::make_iter_ref(record->data.out),
|
||||
[&](auto e) -> auto { return Edge::Accessor(*e, t); });
|
||||
return iter::make_map(iter::make_iter_ref(record->data.out),
|
||||
[&](auto e) -> auto { return EdgeAccessor(*e, t); });
|
||||
}
|
||||
|
||||
// Returns unfilled accessors
|
||||
auto Vertex::Accessor::in() const
|
||||
auto VertexAccessor::in() const
|
||||
{
|
||||
DbTransaction &t = this->db;
|
||||
return iter::make_map(iter::make_iter_ref(record->data.in),
|
||||
[&](auto e) -> auto { return Edge::Accessor(e, t); });
|
||||
[&](auto e) -> auto { return EdgeAccessor(e, t); });
|
||||
}
|
||||
|
||||
bool Vertex::Accessor::in_contains(Vertex::Accessor const &other) const
|
||||
bool VertexAccessor::in_contains(VertexAccessor const &other) const
|
||||
{
|
||||
return record->data.in.contains(other.vlist);
|
||||
}
|
||||
|
@ -1,20 +1,22 @@
|
||||
#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 Vertex::Accessor> Vertices::find(DbTransaction &t, const Id &id)
|
||||
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 Vertex::Accessor>();
|
||||
return make_option<const VertexAccessor>();
|
||||
|
||||
return make_option_const(Vertex::Accessor(&vertices_iterator->second, t));
|
||||
return make_option_const(VertexAccessor(&vertices_iterator->second, t));
|
||||
}
|
||||
|
||||
Vertex::Accessor Vertices::insert(DbTransaction &t)
|
||||
VertexAccessor Vertices::insert(DbTransaction &t)
|
||||
{
|
||||
// get next vertex id
|
||||
auto next = counter.next();
|
||||
@ -30,17 +32,19 @@ Vertex::Accessor Vertices::insert(DbTransaction &t)
|
||||
// create new vertex
|
||||
auto inserted_vertex_record = result.first;
|
||||
auto vertex = inserted_vertex_record->second.insert(t.trans);
|
||||
t.to_update_index<TypeGroupVertex>(&inserted_vertex_record->second, vertex);
|
||||
|
||||
return Vertex::Accessor(vertex, &inserted_vertex_record->second, t);
|
||||
return VertexAccessor(vertex, &inserted_vertex_record->second, t);
|
||||
}
|
||||
|
||||
PropertyFamily &
|
||||
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<PropertyFamily>(new PropertyFamily(name));
|
||||
auto family = std::unique_ptr<VertexPropertyFamily>(
|
||||
new VertexPropertyFamily(name));
|
||||
auto res = acc.insert(name, std::move(family));
|
||||
it = res.first;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
#include "transactions/transaction.hpp"
|
||||
|
||||
#include <chrono> // std::chrono::seconds
|
||||
|
||||
#include <thread> // std::this_thread::sleep_for
|
||||
|
||||
#include "transactions/engine.hpp"
|
||||
|
||||
namespace tx
|
||||
@ -11,10 +15,25 @@ Transaction::Transaction(const Id &id, const Snapshot<Id> &snapshot,
|
||||
{
|
||||
}
|
||||
|
||||
void Transaction::wait_for_active()
|
||||
{
|
||||
while (snapshot.size() > 0) {
|
||||
auto id = snapshot.back();
|
||||
while (engine.clog.fetch_info(id).is_active()) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(100));
|
||||
}
|
||||
snapshot.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
bool Transaction::is_active(const Id &id) const
|
||||
{
|
||||
return snapshot.is_active(id);
|
||||
}
|
||||
|
||||
void Transaction::take_lock(RecordLock &lock) { locks.take(&lock, id); }
|
||||
|
||||
void Transaction::commit() { engine.commit(*this); }
|
||||
|
||||
void Transaction::abort() { engine.abort(*this); }
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user