Database interface refactor.
DbAccessor: -Guarantees that access to Vertex and Edge is possible only through Vertex::Accessor and Edge::Accessor. -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. -Offers CRUD for Vertex and Edge except iterating over all edges. Squashed commit messages: First step in database accessor refactoring done. It's compiling. All tests with exception of integration_querys pass Tests now initialize logging facilities. Refactored accessors. RecordAccessor now has 3 states. From,To,Out,In in there respecive Accessors return unfilled RecordAccessor. Added iterator classes into utils/itearator/.
This commit is contained in:
parent
2113546b9c
commit
df0bf6fa5f
CMakeLists.txt
include
communication/bolt/v1/serialization
database
query_engine/hardcode
storage
edge_accessor.hppedge_record.hppedges.hpp
model
record_accessor.hppvertex.hppvertex_accessor.hppvertices.hpputils
poc
src
cypher/tokenizer
data_structures/map
database
storage
tests
concurrent
common.hlinkedlist.cppsl_insert.cppsl_insert_competetive.cppsl_map.cppsl_memory.cppsl_memory_leak.cppsl_multiiterator.cppsl_multiiterator_remove.cppsl_multiiterator_remove_duplicates.cppsl_multimap.cppsl_multiset.cppsl_remove_competetive.cppsl_remove_disjoint.cppsl_remove_joint.cppsl_set.cppsl_simulation.cpp
unit
@ -15,7 +15,7 @@ find_package(Threads REQUIRED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
|
||||
|
||||
# glibcxx debug (useful for gdb)
|
||||
# the problem is that the query engine doesn't work as it should work if
|
||||
# the problem is that the query engine doesn't work as it should work if
|
||||
# this flag is present
|
||||
# TODO: find more appropriate way to use this flag only when it is needed
|
||||
# set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_GLIBCXX_DEBUG")
|
||||
@ -288,7 +288,7 @@ endif()
|
||||
|
||||
# release flags
|
||||
set(CMAKE_CXX_FLAGS_RELEASE
|
||||
"${CMAKE_CXX_FLAGS_RELEASE} -march=native -Wall -Werror")
|
||||
"${CMAKE_CXX_FLAGS_RELEASE} -march=native -Wall")
|
||||
|
||||
# -- configure defines -- default is ON | true | enabled ----------------------
|
||||
# -- logging ------------------------------------------------------------------
|
||||
@ -412,6 +412,10 @@ set(memgraph_src_files
|
||||
${src_dir}/logging/default.cpp
|
||||
${src_dir}/logging/log.cpp
|
||||
${src_dir}/io/network/tls.cpp
|
||||
${src_dir}/database/db.cpp
|
||||
${src_dir}/database/db_accessor.cpp
|
||||
${src_dir}/database/db_transaction.cpp
|
||||
${src_dir}/storage/edge_accessor.cpp
|
||||
)
|
||||
|
||||
# STATIC library used by memgraph executables
|
||||
@ -434,7 +438,7 @@ endif()
|
||||
|
||||
# memgraph build name
|
||||
execute_process(
|
||||
OUTPUT_VARIABLE COMMIT_NO
|
||||
OUTPUT_VARIABLE COMMIT_NO
|
||||
COMMAND git rev-list --count HEAD
|
||||
)
|
||||
execute_process(
|
||||
|
@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "communication/bolt/v1/transport/bolt_encoder.hpp"
|
||||
#include "communication/bolt/v1/packing/codes.hpp"
|
||||
#include "communication/bolt/v1/transport/bolt_encoder.hpp"
|
||||
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
|
||||
#include "storage/model/properties/properties.hpp"
|
||||
#include "storage/model/properties/all.hpp"
|
||||
#include "storage/model/properties/properties.hpp"
|
||||
|
||||
namespace bolt
|
||||
{
|
||||
@ -22,7 +22,7 @@ class BoltSerializer
|
||||
// friend void accept(const Property &property, Handler &h);
|
||||
|
||||
public:
|
||||
BoltSerializer(Stream& stream) : encoder(stream) {}
|
||||
BoltSerializer(Stream &stream) : encoder(stream) {}
|
||||
|
||||
/* Serializes the vertex accessor into the packstream format
|
||||
*
|
||||
@ -33,7 +33,7 @@ public:
|
||||
* }
|
||||
*
|
||||
*/
|
||||
void write(const Vertex::Accessor& vertex)
|
||||
void write(const Vertex::Accessor &vertex)
|
||||
{
|
||||
// write signatures for the node struct and node data type
|
||||
encoder.write_struct_header(3);
|
||||
@ -47,7 +47,7 @@ public:
|
||||
|
||||
encoder.write_list_header(labels.size());
|
||||
|
||||
for(auto& label : labels)
|
||||
for (auto &label : labels)
|
||||
encoder.write_string(label.get());
|
||||
|
||||
// write the property map
|
||||
@ -55,7 +55,7 @@ public:
|
||||
|
||||
encoder.write_map_header(props.size());
|
||||
|
||||
for(auto& prop : props) {
|
||||
for (auto &prop : props) {
|
||||
write(prop.first);
|
||||
write(*prop.second);
|
||||
}
|
||||
@ -72,7 +72,7 @@ public:
|
||||
* }
|
||||
*
|
||||
*/
|
||||
void write(const Edge::Accessor& edge)
|
||||
void write(const Edge::Accessor &edge)
|
||||
{
|
||||
// write signatures for the edge struct and edge data type
|
||||
encoder.write_struct_header(5);
|
||||
@ -82,8 +82,8 @@ public:
|
||||
encoder.write_integer(edge.id());
|
||||
|
||||
// TODO refactor when from() and to() start returning Accessors
|
||||
encoder.write_integer(edge.from()->id);
|
||||
encoder.write_integer(edge.to()->id);
|
||||
encoder.write_integer(edge.from().id());
|
||||
encoder.write_integer(edge.to().id());
|
||||
|
||||
// write the type of the edge
|
||||
encoder.write_string(edge.edge_type());
|
||||
@ -93,65 +93,37 @@ public:
|
||||
|
||||
encoder.write_map_header(props.size());
|
||||
|
||||
for(auto& prop : props) {
|
||||
for (auto &prop : props) {
|
||||
write(prop.first);
|
||||
write(*prop.second);
|
||||
}
|
||||
}
|
||||
|
||||
void write(const Property& prop)
|
||||
{
|
||||
accept(prop, *this);
|
||||
}
|
||||
void write(const Property &prop) { accept(prop, *this); }
|
||||
|
||||
void write_null()
|
||||
{
|
||||
encoder.write_null();
|
||||
}
|
||||
void write_null() { encoder.write_null(); }
|
||||
|
||||
void write(const Bool& prop)
|
||||
{
|
||||
encoder.write_bool(prop.value());
|
||||
}
|
||||
void write(const Bool &prop) { encoder.write_bool(prop.value()); }
|
||||
|
||||
void write(const Float& prop)
|
||||
{
|
||||
encoder.write_double(prop.value);
|
||||
}
|
||||
void write(const Float &prop) { encoder.write_double(prop.value); }
|
||||
|
||||
void write(const Double& prop)
|
||||
{
|
||||
encoder.write_double(prop.value);
|
||||
}
|
||||
void write(const Double &prop) { encoder.write_double(prop.value); }
|
||||
|
||||
void write(const Int32& prop)
|
||||
{
|
||||
encoder.write_integer(prop.value);
|
||||
}
|
||||
void write(const Int32 &prop) { encoder.write_integer(prop.value); }
|
||||
|
||||
void write(const Int64& prop)
|
||||
{
|
||||
encoder.write_integer(prop.value);
|
||||
}
|
||||
void write(const Int64 &prop) { encoder.write_integer(prop.value); }
|
||||
|
||||
void write(const std::string& value)
|
||||
{
|
||||
encoder.write_string(value);
|
||||
}
|
||||
void write(const std::string &value) { encoder.write_string(value); }
|
||||
|
||||
void write(const String& prop)
|
||||
{
|
||||
encoder.write_string(prop.value);
|
||||
}
|
||||
void write(const String &prop) { encoder.write_string(prop.value); }
|
||||
|
||||
template <class T>
|
||||
void handle(const T& prop)
|
||||
void handle(const T &prop)
|
||||
{
|
||||
write(prop);
|
||||
}
|
||||
|
||||
protected:
|
||||
Stream& encoder;
|
||||
Stream &encoder;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,25 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "storage/graph.hpp"
|
||||
// #include "transactions/commit_log.hpp"
|
||||
#include "transactions/engine.hpp"
|
||||
#include "transactions/commit_log.hpp"
|
||||
|
||||
class Db
|
||||
{
|
||||
public:
|
||||
using sptr = std::shared_ptr<Db>;
|
||||
|
||||
Db() = default;
|
||||
Db(const std::string& name) : name_(name) {}
|
||||
Db(const Db& db) = delete;
|
||||
Db();
|
||||
Db(const std::string &name);
|
||||
Db(const Db &db) = delete;
|
||||
|
||||
Graph graph;
|
||||
tx::Engine tx_engine;
|
||||
|
||||
std::string& name()
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
std::string &name();
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
|
91
include/database/db_accessor.hpp
Normal file
91
include/database/db_accessor.hpp
Normal file
@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
#include "database/db.hpp"
|
||||
#include "database/db_accessor.hpp"
|
||||
#include "storage/record_accessor.hpp"
|
||||
#include "storage/vertex.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "storage/vertices.hpp"
|
||||
#include "transactions/transaction.hpp"
|
||||
#include "utils/iterator/iterator.hpp"
|
||||
#include "utils/option.hpp"
|
||||
|
||||
/*
|
||||
* DbAccessor
|
||||
* -Guarantees that access to Vertex and Edge is possible only through
|
||||
* Vertex::Accessor and Edge::Accessor.
|
||||
* -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.
|
||||
* -Offers CRUD for Vertex and Edge except iterating over all edges.
|
||||
*
|
||||
* Vertex::Accessor
|
||||
* 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.
|
||||
*
|
||||
* Edge::Accessor
|
||||
* 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
|
||||
* true
|
||||
* 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.
|
||||
*/
|
||||
class DbAccessor
|
||||
{
|
||||
|
||||
public:
|
||||
DbAccessor(Db &db);
|
||||
|
||||
//*******************VERTEX METHODS
|
||||
|
||||
auto vertex_access();
|
||||
|
||||
Option<const Vertex::Accessor> vertex_find(const Id &id);
|
||||
|
||||
// Creates new Vertex and returns filled Vertex::Accessor.
|
||||
Vertex::Accessor vertex_insert();
|
||||
|
||||
//*******************EDGE METHODS
|
||||
|
||||
Option<const Edge::Accessor> 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);
|
||||
|
||||
//*******************LABEL METHODS
|
||||
|
||||
const Label &label_find_or_create(const std::string &name);
|
||||
|
||||
bool label_contains(const std::string &name);
|
||||
|
||||
VertexIndexRecordCollection &label_find_index(const Label &label);
|
||||
|
||||
//********************TYPE METHODS
|
||||
|
||||
const EdgeType &type_find_or_create(const std::string &name);
|
||||
|
||||
bool type_contains(const std::string &name);
|
||||
|
||||
//********************TRANSACTION METHODS
|
||||
|
||||
void commit();
|
||||
void abort();
|
||||
|
||||
private:
|
||||
DbTransaction db;
|
||||
};
|
||||
|
||||
//**********************CONVENIENT FUNCTIONS
|
||||
|
||||
template <class R>
|
||||
bool option_fill(Option<R> &o)
|
||||
{
|
||||
return o.is_present() && o.get().fill();
|
||||
}
|
25
include/database/db_transaction.hpp
Normal file
25
include/database/db_transaction.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "storage/indexes/index_record.hpp"
|
||||
#include "storage/label/label.hpp"
|
||||
#include "transactions/transaction.hpp"
|
||||
|
||||
class Db;
|
||||
class DbAccessor;
|
||||
|
||||
// Inner structures local to transaction can hold ref to this structure and use
|
||||
// its methods.
|
||||
class DbTransaction
|
||||
{
|
||||
friend DbAccessor;
|
||||
|
||||
public:
|
||||
DbTransaction(Db &db, tx::Transaction &trans) : db(db), trans(trans) {}
|
||||
|
||||
void update_label_index(const Label &label,
|
||||
VertexIndexRecord &&index_record);
|
||||
|
||||
tx::Transaction &trans;
|
||||
|
||||
Db &db;
|
||||
};
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "database/db.hpp"
|
||||
#include "database/db_accessor.cpp"
|
||||
#include "database/db_accessor.hpp"
|
||||
#include "query_engine/query_stripper.hpp"
|
||||
#include "query_engine/util.hpp"
|
||||
#include "storage/model/properties/property.hpp"
|
||||
@ -12,8 +14,8 @@ auto load_queries(Db &db)
|
||||
|
||||
// CREATE (n {prop: 0}) RETURN n)
|
||||
auto create_node = [&db](const properties_t &args) {
|
||||
auto &t = db.tx_engine.begin();
|
||||
auto vertex_accessor = db.graph.vertices.insert(t);
|
||||
DbAccessor t(db);
|
||||
auto vertex_accessor = t.vertex_insert();
|
||||
vertex_accessor.property("prop", args[0]);
|
||||
t.commit();
|
||||
return true;
|
||||
@ -21,10 +23,10 @@ auto load_queries(Db &db)
|
||||
queries[11597417457737499503u] = create_node;
|
||||
|
||||
auto create_labeled_and_named_node = [&db](const properties_t &args) {
|
||||
auto &t = db.tx_engine.begin();
|
||||
auto vertex_accessor = db.graph.vertices.insert(t);
|
||||
DbAccessor t(db);
|
||||
auto vertex_accessor = t.vertex_insert();
|
||||
vertex_accessor.property("name", args[0]);
|
||||
auto &label = db.graph.label_store.find_or_create("LABEL");
|
||||
auto &label = t.label_find_or_create("LABEL");
|
||||
vertex_accessor.add_label(label);
|
||||
cout_properties(vertex_accessor.properties());
|
||||
t.commit();
|
||||
@ -32,13 +34,13 @@ auto load_queries(Db &db)
|
||||
};
|
||||
|
||||
auto create_account = [&db](const properties_t &args) {
|
||||
auto &t = db.tx_engine.begin();
|
||||
auto vertex_accessor = db.graph.vertices.insert(t);
|
||||
DbAccessor t(db);
|
||||
auto vertex_accessor = t.vertex_insert();
|
||||
vertex_accessor.property("id", args[0]);
|
||||
vertex_accessor.property("name", args[1]);
|
||||
vertex_accessor.property("country", args[2]);
|
||||
vertex_accessor.property("created_at", args[3]);
|
||||
auto &label = db.graph.label_store.find_or_create("ACCOUNT");
|
||||
auto &label = t.label_find_or_create("ACCOUNT");
|
||||
vertex_accessor.add_label(label);
|
||||
cout_properties(vertex_accessor.properties());
|
||||
t.commit();
|
||||
@ -46,14 +48,15 @@ auto load_queries(Db &db)
|
||||
};
|
||||
|
||||
auto find_node_by_internal_id = [&db](const properties_t &args) {
|
||||
auto &t = db.tx_engine.begin();
|
||||
DbAccessor t(db);
|
||||
auto id = static_cast<Int32 &>(*args[0]);
|
||||
auto vertex_accessor = db.graph.vertices.find(t, Id(id.value));
|
||||
if (!vertex_accessor) {
|
||||
auto maybe_va = t.vertex_find(Id(id.value));
|
||||
if (!option_fill(maybe_va)) {
|
||||
cout << "vertex doesn't exist" << endl;
|
||||
t.commit();
|
||||
return false;
|
||||
}
|
||||
auto vertex_accessor = maybe_va.get();
|
||||
cout_properties(vertex_accessor.properties());
|
||||
cout << "LABELS:" << endl;
|
||||
for (auto label_ref : vertex_accessor.labels()) {
|
||||
@ -64,20 +67,17 @@ auto load_queries(Db &db)
|
||||
};
|
||||
|
||||
auto create_edge = [&db](const properties_t &args) {
|
||||
auto &t = db.tx_engine.begin();
|
||||
DbAccessor t(db);
|
||||
|
||||
auto v1 = db.graph.vertices.find(t, args[0]->as<Int32>().value);
|
||||
if (!v1) return t.commit(), false;
|
||||
auto v1 = t.vertex_find(args[0]->as<Int32>().value);
|
||||
if (!option_fill(v1)) return t.commit(), false;
|
||||
|
||||
auto v2 = db.graph.vertices.find(t, args[1]->as<Int32>().value);
|
||||
if (!v2) return t.commit(), false;
|
||||
auto v2 = t.vertex_find(args[1]->as<Int32>().value);
|
||||
if (!option_fill(v2)) return t.commit(), false;
|
||||
|
||||
auto edge_accessor = db.graph.edges.insert(t, v1.vlist, v2.vlist);
|
||||
auto edge_accessor = t.edge_insert(v1.get(), v2.get());
|
||||
|
||||
v1.vlist->update(t)->data.out.add(edge_accessor.vlist);
|
||||
v2.vlist->update(t)->data.in.add(edge_accessor.vlist);
|
||||
|
||||
auto &edge_type = db.graph.edge_type_store.find_or_create("IS");
|
||||
auto &edge_type = t.type_find_or_create("IS");
|
||||
edge_accessor.edge_type(edge_type);
|
||||
|
||||
t.commit();
|
||||
@ -90,20 +90,25 @@ auto load_queries(Db &db)
|
||||
};
|
||||
|
||||
auto find_edge_by_internal_id = [&db](const properties_t &args) {
|
||||
auto &t = db.tx_engine.begin();
|
||||
auto edge_accessor = db.graph.edges.find(t, args[0]->as<Int32>().value);
|
||||
if (!edge_accessor) return t.commit(), false;
|
||||
DbAccessor t(db);
|
||||
auto maybe_ea = t.edge_find(args[0]->as<Int32>().value);
|
||||
if (!option_fill(maybe_ea)) return t.commit(), false;
|
||||
auto edge_accessor = maybe_ea.get();
|
||||
|
||||
// print edge type and properties
|
||||
cout << "EDGE_TYPE: " << edge_accessor.edge_type() << endl;
|
||||
|
||||
auto from = edge_accessor.from();
|
||||
if (!from.fill()) return t.commit(), false;
|
||||
|
||||
cout << "FROM:" << endl;
|
||||
cout_properties(from->find(t)->data.props);
|
||||
cout_properties(from->data.props);
|
||||
|
||||
auto to = edge_accessor.to();
|
||||
if (!to.fill()) return t.commit(), false;
|
||||
|
||||
cout << "TO:" << endl;
|
||||
cout_properties(to->find(t)->data.props);
|
||||
cout_properties(to->data.props);
|
||||
|
||||
t.commit();
|
||||
|
||||
@ -111,10 +116,11 @@ auto load_queries(Db &db)
|
||||
};
|
||||
|
||||
auto update_node = [&db](const properties_t &args) {
|
||||
auto &t = db.tx_engine.begin();
|
||||
DbAccessor t(db);
|
||||
|
||||
auto v = db.graph.vertices.find(t, args[0]->as<Int32>().value);
|
||||
if (!v) return t.commit(), false;
|
||||
auto maybe_v = t.vertex_find(args[0]->as<Int32>().value);
|
||||
if (!option_fill(maybe_v)) return t.commit(), false;
|
||||
auto v = maybe_v.get();
|
||||
|
||||
v.property("name", args[1]);
|
||||
cout_properties(v.properties());
|
||||
@ -127,18 +133,17 @@ auto load_queries(Db &db)
|
||||
// MATCH (n1), (n2) WHERE ID(n1)=0 AND ID(n2)=1 CREATE (n1)<-[r:IS {age: 25,
|
||||
// weight: 70}]-(n2) RETURN r
|
||||
auto create_edge_v2 = [&db](const properties_t &args) {
|
||||
auto &t = db.tx_engine.begin();
|
||||
auto n1 = db.graph.vertices.find(t, args[0]->as<Int64>().value);
|
||||
if (!n1) return t.commit(), false;
|
||||
auto n2 = db.graph.vertices.find(t, args[1]->as<Int64>().value);
|
||||
if (!n2) return t.commit(), false;
|
||||
auto r = db.graph.edges.insert(t, n2.vlist, n1.vlist);
|
||||
DbAccessor t(db);
|
||||
auto n1 = t.vertex_find(args[0]->as<Int64>().value);
|
||||
if (!option_fill(n1)) return t.commit(), false;
|
||||
auto n2 = t.vertex_find(args[1]->as<Int64>().value);
|
||||
if (!option_fill(n2)) return t.commit(), false;
|
||||
auto r = t.edge_insert(n2.get(), n1.get());
|
||||
r.property("age", args[2]);
|
||||
r.property("weight", args[3]);
|
||||
auto &IS = db.graph.edge_type_store.find_or_create("IS");
|
||||
auto &IS = t.type_find_or_create("IS");
|
||||
r.edge_type(IS);
|
||||
n2.vlist->update(t)->data.out.add(r.vlist);
|
||||
n1.vlist->update(t)->data.in.add(r.vlist);
|
||||
|
||||
t.commit();
|
||||
return true;
|
||||
};
|
||||
@ -146,14 +151,13 @@ auto load_queries(Db &db)
|
||||
|
||||
// MATCH (n) RETURN n
|
||||
auto match_all_nodes = [&db](const properties_t &args) {
|
||||
auto &t = db.tx_engine.begin();
|
||||
DbAccessor t(db);
|
||||
|
||||
auto vertices_accessor = db.graph.vertices.access();
|
||||
for (auto &it : vertices_accessor) {
|
||||
auto vertex = it.second.find(t);
|
||||
if (vertex == nullptr) continue;
|
||||
cout_properties(vertex->data.props);
|
||||
}
|
||||
iter::for_all(t.vertex_access(), [&](auto vertex) {
|
||||
if (vertex.fill()) {
|
||||
cout_properties(vertex->data.props);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO
|
||||
// db.graph.vertices.filter().all(t, handler);
|
||||
@ -166,12 +170,11 @@ auto load_queries(Db &db)
|
||||
|
||||
// MATCH (n:LABEL) RETURN n
|
||||
auto find_by_label = [&db](const properties_t &args) {
|
||||
auto &t = db.tx_engine.begin();
|
||||
DbAccessor t(db);
|
||||
|
||||
auto &label = db.graph.label_store.find_or_create("LABEL");
|
||||
auto &label = t.label_find_or_create("LABEL");
|
||||
|
||||
auto &index_record_collection =
|
||||
db.graph.vertices.find_label_index(label);
|
||||
auto &index_record_collection = t.label_find_index(label);
|
||||
auto accessor = index_record_collection.access();
|
||||
cout << "VERTICES" << endl;
|
||||
for (auto &v : accessor) {
|
||||
|
@ -3,31 +3,23 @@
|
||||
#include "storage/edge.hpp"
|
||||
#include "storage/edge_record.hpp"
|
||||
#include "storage/record_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
#include "utils/reference_wrapper.hpp"
|
||||
|
||||
class Edges;
|
||||
|
||||
// TODO: Edge, Db, Edge::Accessor
|
||||
class Edge::Accessor
|
||||
: public RecordAccessor<Edge, Edges, Edge::Accessor, EdgeRecord>
|
||||
class Edge::Accessor : public RecordAccessor<Edge, Edge::Accessor, EdgeRecord>
|
||||
{
|
||||
public:
|
||||
using RecordAccessor::RecordAccessor;
|
||||
|
||||
void edge_type(edge_type_ref_t edge_type)
|
||||
{
|
||||
this->record->data.edge_type = &edge_type.get();
|
||||
}
|
||||
void edge_type(edge_type_ref_t edge_type);
|
||||
|
||||
edge_type_ref_t edge_type() const
|
||||
{
|
||||
runtime_assert(this->record->data.edge_type != nullptr,
|
||||
"EdgeType is null");
|
||||
return edge_type_ref_t(*this->record->data.edge_type);
|
||||
}
|
||||
edge_type_ref_t edge_type() const;
|
||||
|
||||
auto from() const { return this->vlist->from(); }
|
||||
Vertex::Accessor from() const;
|
||||
|
||||
auto to() const { return this->vlist->to(); }
|
||||
Vertex::Accessor to() const;
|
||||
};
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
|
||||
auto to() const { return this->to_v; }
|
||||
|
||||
private:
|
||||
protected:
|
||||
VertexRecord *from_v;
|
||||
VertexRecord *to_v;
|
||||
};
|
||||
|
@ -4,12 +4,15 @@
|
||||
#include "mvcc/version_list.hpp"
|
||||
#include "storage/common.hpp"
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "utils/option.hpp"
|
||||
|
||||
class Edges
|
||||
{
|
||||
public:
|
||||
Edge::Accessor find(tx::Transaction &t, const Id &id);
|
||||
Edge::Accessor insert(tx::Transaction &t, VertexRecord *from,
|
||||
Option<const Edge::Accessor> find(DbTransaction &t, const Id &id);
|
||||
|
||||
// Creates new Edge and returns filled Edge::Accessor.
|
||||
Edge::Accessor insert(DbTransaction &t, VertexRecord *from,
|
||||
VertexRecord *to);
|
||||
|
||||
private:
|
||||
|
@ -23,7 +23,7 @@ public:
|
||||
edges.remove(edge); // Currently the return is ignored
|
||||
}
|
||||
|
||||
bool contains(VertexRecord *vr) { return edges.contains(vr); }
|
||||
bool contains(VertexRecord *vr) const { return edges.contains(vr); }
|
||||
|
||||
void clear() { edges.clear(); }
|
||||
|
||||
|
@ -1,45 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "database/db_transaction.hpp"
|
||||
#include "mvcc/version_list.hpp"
|
||||
#include "storage/model/properties/properties.hpp"
|
||||
#include "storage/model/properties/property.hpp"
|
||||
#include "transactions/transaction.hpp"
|
||||
|
||||
template <class T, class Store, class Derived,
|
||||
class vlist_t = mvcc::VersionList<T>>
|
||||
template <class T, class Derived, class vlist_t = mvcc::VersionList<T>>
|
||||
class RecordAccessor
|
||||
{
|
||||
public:
|
||||
RecordAccessor() = default;
|
||||
friend DbAccessor;
|
||||
|
||||
RecordAccessor(T *record, vlist_t *vlist, Store *store)
|
||||
: record(record), vlist(vlist), store(store)
|
||||
public:
|
||||
RecordAccessor(vlist_t *vlist, DbTransaction &db) : vlist(vlist), db(db)
|
||||
{
|
||||
assert(vlist != nullptr);
|
||||
}
|
||||
|
||||
RecordAccessor(T *t, vlist_t *vlist, DbTransaction &db)
|
||||
: record(t), vlist(vlist), db(db)
|
||||
{
|
||||
assert(record != nullptr);
|
||||
assert(vlist != nullptr);
|
||||
assert(store != nullptr);
|
||||
}
|
||||
|
||||
RecordAccessor(RecordAccessor const &other) = default;
|
||||
RecordAccessor(RecordAccessor &&other) = default;
|
||||
|
||||
bool empty() const { return record == nullptr; }
|
||||
|
||||
// Fills accessor and returns true if there is valid data for current
|
||||
// transaction false otherwise.
|
||||
bool fill() const
|
||||
{
|
||||
const_cast<RecordAccessor *>(this)->record = vlist->find(db.trans);
|
||||
return record != nullptr;
|
||||
}
|
||||
|
||||
const Id &id() const
|
||||
{
|
||||
assert(!empty());
|
||||
return vlist->id;
|
||||
}
|
||||
|
||||
Derived update(tx::Transaction &t) const
|
||||
Derived update() const
|
||||
{
|
||||
assert(!empty());
|
||||
|
||||
return Derived(vlist->update(t), vlist, store);
|
||||
return Derived(vlist->update(db.trans), vlist, db);
|
||||
}
|
||||
|
||||
bool remove(tx::Transaction &t) const
|
||||
bool remove() const
|
||||
{
|
||||
assert(!empty());
|
||||
|
||||
return vlist->remove(record, t);
|
||||
return vlist->remove(record, db.trans);
|
||||
}
|
||||
|
||||
const Property &property(const std::string &key) const
|
||||
@ -62,8 +77,23 @@ public:
|
||||
|
||||
explicit operator bool() const { return record != nullptr; }
|
||||
|
||||
// protected:
|
||||
T *const record{nullptr};
|
||||
vlist_t *const vlist{nullptr};
|
||||
Store *const store{nullptr};
|
||||
T const *operator->() const { return record; }
|
||||
T *operator->() { return record; }
|
||||
|
||||
// Assumes same transaction
|
||||
friend bool operator==(const RecordAccessor &a, const RecordAccessor &b)
|
||||
{
|
||||
return a.vlist == b.vlist;
|
||||
}
|
||||
|
||||
// Assumes same transaction
|
||||
friend bool operator!=(const RecordAccessor &a, const RecordAccessor &b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
protected:
|
||||
T *record{nullptr};
|
||||
vlist_t *const vlist;
|
||||
DbTransaction &db;
|
||||
};
|
||||
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "mvcc/record.hpp"
|
||||
#include "storage/model/vertex_model.hpp"
|
||||
#include "storage/model/properties/traversers/jsonwriter.hpp"
|
||||
#include "storage/model/vertex_model.hpp"
|
||||
|
||||
class Vertex : public mvcc::Record<Vertex>
|
||||
{
|
||||
@ -10,19 +10,19 @@ public:
|
||||
class Accessor;
|
||||
|
||||
Vertex() = default;
|
||||
Vertex(const VertexModel& data) : data(data) {}
|
||||
Vertex(VertexModel&& data) : data(std::move(data)) {}
|
||||
Vertex(const VertexModel &data) : data(data) {}
|
||||
Vertex(VertexModel &&data) : data(std::move(data)) {}
|
||||
|
||||
Vertex(const Vertex&) = delete;
|
||||
Vertex(Vertex&&) = delete;
|
||||
Vertex(const Vertex &) = delete;
|
||||
Vertex(Vertex &&) = delete;
|
||||
|
||||
Vertex& operator=(const Vertex&) = delete;
|
||||
Vertex& operator=(Vertex&&) = delete;
|
||||
Vertex &operator=(const Vertex &) = delete;
|
||||
Vertex &operator=(Vertex &&) = delete;
|
||||
|
||||
VertexModel data;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& stream, const Vertex& record)
|
||||
inline std::ostream &operator<<(std::ostream &stream, const Vertex &record)
|
||||
{
|
||||
StringBuffer buffer;
|
||||
JsonWriter<StringBuffer> writer(buffer);
|
||||
@ -33,6 +33,5 @@ inline std::ostream& operator<<(std::ostream& stream, const Vertex& record)
|
||||
|
||||
return stream << "Vertex"
|
||||
<< "(cre = " << record.tx.cre()
|
||||
<< ", exp = " << record.tx.exp()
|
||||
<< "): " << buffer.str();
|
||||
<< ", exp = " << record.tx.exp() << "): " << buffer.str();
|
||||
}
|
||||
|
@ -5,8 +5,7 @@
|
||||
|
||||
class Vertices;
|
||||
|
||||
class Vertex::Accessor
|
||||
: public RecordAccessor<Vertex, Vertices, Vertex::Accessor>
|
||||
class Vertex::Accessor : public RecordAccessor<Vertex, Vertex::Accessor>
|
||||
{
|
||||
public:
|
||||
using RecordAccessor::RecordAccessor;
|
||||
@ -21,5 +20,12 @@ public:
|
||||
|
||||
bool has_label(const Label &label) const;
|
||||
|
||||
const std::set<label_ref_t>& labels() const;
|
||||
const std::set<label_ref_t> &labels() const;
|
||||
|
||||
auto out() const;
|
||||
|
||||
auto in() const;
|
||||
|
||||
// True if there exists edge other->this
|
||||
bool in_contains(Vertex::Accessor const &other) const;
|
||||
};
|
||||
|
@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "data_structures/concurrent/concurrent_map.hpp"
|
||||
#include "database/db_transaction.hpp"
|
||||
#include "storage/common.hpp"
|
||||
#include "storage/indexes/index.hpp"
|
||||
#include "storage/indexes/index_record_collection.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "utils/option.hpp"
|
||||
|
||||
class Vertices
|
||||
{
|
||||
@ -13,17 +15,16 @@ public:
|
||||
|
||||
vertices_t::Accessor access();
|
||||
|
||||
const Vertex::Accessor find(tx::Transaction &t, const Id &id);
|
||||
Option<const Vertex::Accessor> find(DbTransaction &t, const Id &id);
|
||||
|
||||
const Vertex::Accessor first(tx::Transaction &t);
|
||||
|
||||
Vertex::Accessor insert(tx::Transaction &t);
|
||||
// Creates new Vertex and returns filled Vertex::Accessor.
|
||||
Vertex::Accessor insert(DbTransaction &t);
|
||||
|
||||
void update_label_index(const Label &label,
|
||||
VertexIndexRecord &&index_record);
|
||||
|
||||
VertexIndexRecordCollection& find_label_index(const Label& label);
|
||||
|
||||
VertexIndexRecordCollection &find_label_index(const Label &label);
|
||||
|
||||
private:
|
||||
vertices_t vertices;
|
||||
Index<label_ref_t, VertexIndexRecordCollection> label_index;
|
||||
|
28
include/utils/iterator/accessor.hpp
Normal file
28
include/utils/iterator/accessor.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/iterator/wrap.hpp"
|
||||
#include "utils/option.hpp"
|
||||
|
||||
namespace iter
|
||||
{
|
||||
template <class T, class I>
|
||||
class OneTimeAccessor
|
||||
{
|
||||
public:
|
||||
OneTimeAccessor() : it(Option<Wrap<T, I>>()) {}
|
||||
OneTimeAccessor(I &&it) : it(Wrap<T, I>(std::move(it))) {}
|
||||
|
||||
Wrap<T, I> begin() { return it.take(); }
|
||||
|
||||
Wrap<T, I> end() { return Wrap<T, I>(); }
|
||||
|
||||
private:
|
||||
Option<Wrap<T, I>> it;
|
||||
};
|
||||
|
||||
template <class I>
|
||||
auto make_one_time_accessor(I &&iter)
|
||||
{
|
||||
return OneTimeAccessor<decltype(iter.next().take()), I>(std::move(iter));
|
||||
}
|
||||
}
|
17
include/utils/iterator/for_all.hpp
Normal file
17
include/utils/iterator/for_all.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utils/option.hpp"
|
||||
|
||||
namespace iter
|
||||
{
|
||||
template <class I, class C>
|
||||
void for_all(I &&iter, C &&consumer)
|
||||
{
|
||||
auto e = iter.next();
|
||||
while (e.is_present()) {
|
||||
consumer(e.take());
|
||||
e = iter.next();
|
||||
}
|
||||
}
|
||||
}
|
48
include/utils/iterator/iter.hpp
Normal file
48
include/utils/iterator/iter.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/option.hpp"
|
||||
|
||||
namespace iter
|
||||
{
|
||||
template <class T, class I, class A>
|
||||
class Iter
|
||||
{
|
||||
public:
|
||||
Iter() = delete;
|
||||
|
||||
Iter(A &&acc) : begin(std::move(acc.begin())), acc(std::forward<A>(acc)) {}
|
||||
// Iter(const Iter &other) = delete;
|
||||
// Iter(Iter &&other) :
|
||||
// begin(std::move(other.begin)),end(std::move(other.end)) {};
|
||||
|
||||
auto next()
|
||||
{
|
||||
if (begin != acc.end()) {
|
||||
auto ret = Option<T>(&(*(begin.operator->())));
|
||||
begin++;
|
||||
return ret;
|
||||
} else {
|
||||
return Option<T>();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
I begin;
|
||||
A acc;
|
||||
};
|
||||
|
||||
// TODO: Join to make functions into one
|
||||
template <class A>
|
||||
auto make_iter(A &&acc)
|
||||
{
|
||||
return Iter<decltype(&(*(acc.begin().operator->()))), decltype(acc.begin()),
|
||||
A>(std::move(acc));
|
||||
}
|
||||
|
||||
template <class A>
|
||||
auto make_iter_ref(A &acc)
|
||||
{
|
||||
return Iter<decltype(&(*(acc.begin().operator->()))), decltype(acc.begin()),
|
||||
A &>(acc);
|
||||
}
|
||||
}
|
7
include/utils/iterator/iterator.hpp
Normal file
7
include/utils/iterator/iterator.hpp
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/iterator/accessor.hpp"
|
||||
#include "utils/iterator/for_all.hpp"
|
||||
#include "utils/iterator/iter.hpp"
|
||||
#include "utils/iterator/map.hpp"
|
||||
#include "utils/iterator/wrap.hpp"
|
39
include/utils/iterator/map.hpp
Normal file
39
include/utils/iterator/map.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/option.hpp"
|
||||
|
||||
namespace iter
|
||||
{
|
||||
template <class U, class I, class MapOperator>
|
||||
class Map
|
||||
{
|
||||
|
||||
public:
|
||||
Map() = delete;
|
||||
template <class IT, class OP>
|
||||
Map(IT &&iter, OP &&op) : iter(std::move(iter)), op(std::move(op))
|
||||
{
|
||||
}
|
||||
|
||||
auto next()
|
||||
{
|
||||
auto item = iter.next();
|
||||
if (item.is_present()) {
|
||||
return Option<U>(op(item.take()));
|
||||
} else {
|
||||
return Option<U>();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
I iter;
|
||||
MapOperator op;
|
||||
};
|
||||
|
||||
template <class I, class OP>
|
||||
auto make_map(I &&iter, OP &&op)
|
||||
{
|
||||
return Map<decltype(op(iter.next().take())), I, OP>(std::move(iter),
|
||||
std::move(op));
|
||||
}
|
||||
}
|
60
include/utils/iterator/wrap.hpp
Normal file
60
include/utils/iterator/wrap.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/option.hpp"
|
||||
|
||||
namespace iter
|
||||
{
|
||||
template <class T, class I>
|
||||
class Wrap
|
||||
{
|
||||
|
||||
public:
|
||||
Wrap() : iter(Option<I>()), value(Option<T>()){};
|
||||
|
||||
Wrap(I &&iter) : value(iter.next()), iter(Option<I>(std::move(iter))) {}
|
||||
|
||||
T &operator*()
|
||||
{
|
||||
assert(value.is_present());
|
||||
return value.get();
|
||||
}
|
||||
|
||||
T *operator->()
|
||||
{
|
||||
assert(value.is_present());
|
||||
return &value.get();
|
||||
}
|
||||
|
||||
operator T &()
|
||||
{
|
||||
assert(value.is_present());
|
||||
return value.get();
|
||||
}
|
||||
|
||||
Wrap &operator++()
|
||||
{
|
||||
assert(iter.is_present());
|
||||
value = iter.get().next();
|
||||
return (*this);
|
||||
}
|
||||
|
||||
Wrap &operator++(int) { return operator++(); }
|
||||
|
||||
friend bool operator==(const Wrap &a, const Wrap &b)
|
||||
{
|
||||
return a.value.is_present() == b.value.is_present();
|
||||
}
|
||||
|
||||
friend bool operator!=(const Wrap &a, const Wrap &b) { return !(a == b); }
|
||||
|
||||
private:
|
||||
Option<I> iter;
|
||||
Option<T> value;
|
||||
};
|
||||
|
||||
template <class I>
|
||||
auto make_wrap(I &&iter)
|
||||
{
|
||||
return Wrap<decltype(iter.next().take()), I>(std::move(iter));
|
||||
}
|
||||
}
|
95
include/utils/option.hpp
Normal file
95
include/utils/option.hpp
Normal file
@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#include <ext/aligned_buffer.h>
|
||||
#include <utility>
|
||||
|
||||
template <class T>
|
||||
class Option
|
||||
{
|
||||
public:
|
||||
Option() {}
|
||||
|
||||
Option(T const &item)
|
||||
{
|
||||
new (data._M_addr()) T(item);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
Option(T &&item)
|
||||
{
|
||||
new (data._M_addr()) T(std::move(item));
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
Option(Option &other) = default;
|
||||
Option(Option &&other) noexcept
|
||||
{
|
||||
if (other.initialized) {
|
||||
data = std::move(other.data);
|
||||
other.initialized = false;
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
~Option()
|
||||
{
|
||||
if (initialized) get().~T();
|
||||
}
|
||||
|
||||
Option<T> &operator=(Option<T> &&other)
|
||||
{
|
||||
if (initialized) {
|
||||
get().~T();
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
if (other.initialized) {
|
||||
data = std::move(other.data);
|
||||
other.initialized = false;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool is_present() const { return initialized; }
|
||||
|
||||
T &get() noexcept
|
||||
{
|
||||
assert(initialized);
|
||||
return *data._M_ptr();
|
||||
}
|
||||
|
||||
const T &get() const noexcept { assert(initialized); }
|
||||
|
||||
T take()
|
||||
{
|
||||
assert(initialized);
|
||||
initialized = false;
|
||||
return std::move(*data._M_ptr());
|
||||
}
|
||||
|
||||
explicit operator bool() const { return initialized; }
|
||||
|
||||
private:
|
||||
__gnu_cxx::__aligned_buffer<T> data;
|
||||
bool initialized = false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
auto make_option()
|
||||
{
|
||||
return Option<T>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto make_option(T &&data)
|
||||
{
|
||||
return Option<T>(std::move(data));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto make_option_const(const T &&data)
|
||||
{
|
||||
return Option<const T>(std::move(data));
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <ext/aligned_buffer.h>
|
||||
#include <utility>
|
||||
|
||||
template <class T>
|
||||
class Placeholder
|
||||
@ -9,40 +9,41 @@ class Placeholder
|
||||
public:
|
||||
Placeholder() = default;
|
||||
|
||||
Placeholder(Placeholder&) = delete;
|
||||
Placeholder(Placeholder&&) = delete;
|
||||
Placeholder(Placeholder &) = delete;
|
||||
Placeholder(Placeholder &&) = delete;
|
||||
|
||||
~Placeholder()
|
||||
{
|
||||
if(initialized)
|
||||
get().~T();
|
||||
if (initialized) get().~T();
|
||||
};
|
||||
|
||||
T& get() noexcept
|
||||
bool is_initialized() { return initialized; }
|
||||
|
||||
T &get() noexcept
|
||||
{
|
||||
assert(initialized);
|
||||
return *data._M_ptr();
|
||||
}
|
||||
|
||||
const T& get() const noexcept
|
||||
const T &get() const noexcept
|
||||
{
|
||||
assert(initialized);
|
||||
return *data._M_ptr();
|
||||
}
|
||||
|
||||
void set(const T& item)
|
||||
void set(const T &item)
|
||||
{
|
||||
new (data._M_addr()) T(item);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void set(T&& item)
|
||||
void set(T &&item)
|
||||
{
|
||||
new (data._M_addr()) T(std::move(item));
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private:
|
||||
__gnu_cxx::__aligned_buffer<T> data;
|
||||
__gnu_cxx::__aligned_buffer<T> data;
|
||||
bool initialized = false;
|
||||
};
|
||||
|
154
poc/astar.cpp
154
poc/astar.cpp
@ -10,9 +10,12 @@
|
||||
|
||||
#include "data_structures/map/rh_hashmap.hpp"
|
||||
#include "database/db.hpp"
|
||||
#include "database/db_accessor.hpp"
|
||||
#include "storage/vertex_accessor.cpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef Vertex::Accessor VertexAccessor;
|
||||
void load_graph_dummy(Db &db);
|
||||
void load_csv(Db &db, char *file_path, char *edge_file_path);
|
||||
|
||||
@ -22,20 +25,13 @@ public:
|
||||
Node *parent = {nullptr};
|
||||
double cost;
|
||||
int depth = {0};
|
||||
Vertex *vertex;
|
||||
VertexRecord *record;
|
||||
VertexAccessor vacc;
|
||||
|
||||
Node(Vertex *va, VertexRecord *record, double cost)
|
||||
: cost(cost), vertex(va), record(record)
|
||||
Node(VertexAccessor vacc, double cost) : cost(cost), vacc(vacc) {}
|
||||
Node(VertexAccessor vacc, double cost, Node *parent)
|
||||
: cost(cost), vacc(vacc), parent(parent), depth(parent->depth + 1)
|
||||
{
|
||||
}
|
||||
Node(Vertex *va, VertexRecord *record, double cost, Node *parent)
|
||||
: cost(cost), vertex(va), parent(parent), depth(parent->depth + 1),
|
||||
record(record)
|
||||
{
|
||||
}
|
||||
|
||||
VertexRecord *&get_key() { return record; }
|
||||
};
|
||||
|
||||
// class Iterator : public Crtp<Iterator>
|
||||
@ -82,59 +78,66 @@ void found_result(Node *bef)
|
||||
{
|
||||
std::cout << "{score: " << bef->cost << endl;
|
||||
while (bef != nullptr) {
|
||||
std::cout << " " << *(bef->vertex) << endl;
|
||||
std::cout << " " << *(bef->vacc.operator->()) << endl;
|
||||
bef = bef->parent;
|
||||
}
|
||||
}
|
||||
|
||||
double calc_heuristic_cost_dummy(Edge *edge, Vertex *vertex)
|
||||
double calc_heuristic_cost_dummy(Edge::Accessor &edge, Vertex::Accessor &vertex)
|
||||
{
|
||||
assert(!vertex.empty());
|
||||
return 1 - vertex->data.props.at("score").as<Double>().value;
|
||||
}
|
||||
|
||||
typedef bool (*EdgeFilter)(tx::Transaction &t, EdgeRecord *, Node *before);
|
||||
typedef bool (*VertexFilter)(tx::Transaction &t, Vertex *, Node *before);
|
||||
typedef bool (*EdgeFilter)(DbAccessor &t, Edge::Accessor &, Node *before);
|
||||
typedef bool (*VertexFilter)(DbAccessor &t, Vertex::Accessor &, Node *before);
|
||||
|
||||
bool edge_filter_dummy(tx::Transaction &t, EdgeRecord *e, Node *before)
|
||||
bool edge_filter_dummy(DbAccessor &t, Edge::Accessor &e, Node *before)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vertex_filter_dummy(tx::Transaction &t, Vertex *v, Node *before)
|
||||
bool vertex_filter_dummy(DbAccessor &t, Vertex::Accessor &va, Node *before)
|
||||
{
|
||||
return true;
|
||||
return va.fill();
|
||||
}
|
||||
|
||||
bool vertex_filter_contained_dummy(tx::Transaction &t, Vertex *v, Node *before)
|
||||
bool vertex_filter_contained_dummy(DbAccessor &t, Vertex::Accessor &v,
|
||||
Node *before)
|
||||
{
|
||||
bool found;
|
||||
do {
|
||||
found = false;
|
||||
before = before->parent;
|
||||
if (before == nullptr) {
|
||||
return true;
|
||||
}
|
||||
for (auto edge : before->vertex->data.out) {
|
||||
Vertex *e_v = edge->to()->find(t);
|
||||
if (e_v == v) {
|
||||
found = true;
|
||||
break;
|
||||
if (v.fill()) {
|
||||
bool found;
|
||||
do {
|
||||
found = false;
|
||||
before = before->parent;
|
||||
if (before == nullptr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} while (found);
|
||||
auto it = before->vacc.out();
|
||||
for (auto e = it.next(); e.is_present(); e = it.next()) {
|
||||
VertexAccessor va = e.get().to();
|
||||
if (va == v) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (found);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool vertex_filter_contained(tx::Transaction &t, Vertex *v, Node *before)
|
||||
bool vertex_filter_contained(DbAccessor &t, Vertex::Accessor &v, Node *before)
|
||||
{
|
||||
bool found;
|
||||
do {
|
||||
found = false;
|
||||
before = before->parent;
|
||||
if (before == nullptr) {
|
||||
return true;
|
||||
}
|
||||
} while (v->data.in.contains(before->record));
|
||||
if (v.fill()) {
|
||||
bool found;
|
||||
do {
|
||||
found = false;
|
||||
before = before->parent;
|
||||
if (before == nullptr) {
|
||||
return true;
|
||||
}
|
||||
} while (v.in_contains(before->vacc));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -143,23 +146,24 @@ bool vertex_filter_contained(tx::Transaction &t, Vertex *v, Node *before)
|
||||
// Filtri vracaju true ako element zadovoljava uvjete.
|
||||
void a_star(Db &db, int64_t sys_id_start, uint max_depth, EdgeFilter e_filter[],
|
||||
VertexFilter v_filter[],
|
||||
double (*calc_heuristic_cost)(Edge *edge, Vertex *vertex),
|
||||
double (*calc_heuristic_cost)(Edge::Accessor &edge,
|
||||
Vertex::Accessor &vertex),
|
||||
int limit)
|
||||
{
|
||||
auto &t = db.tx_engine.begin();
|
||||
RhHashMap<VertexRecord *, Node> visited;
|
||||
DbAccessor t(db);
|
||||
|
||||
auto cmp = [](Node *left, Node *right) { return left->cost > right->cost; };
|
||||
std::priority_queue<Node *, std::vector<Node *>, decltype(cmp)> queue(cmp);
|
||||
|
||||
auto start_vr = db.graph.vertices.find(t, sys_id_start).vlist;
|
||||
Node *start = new Node(start_vr->find(t), start_vr, 0);
|
||||
auto start_vr = t.vertex_find(sys_id_start);
|
||||
assert(start_vr);
|
||||
start_vr.get().fill();
|
||||
Node *start = new Node(start_vr.take(), 0);
|
||||
queue.push(start);
|
||||
int count = 0;
|
||||
do {
|
||||
auto now = queue.top();
|
||||
queue.pop();
|
||||
|
||||
// if(!visited.insert(now)){
|
||||
// continue;
|
||||
// }
|
||||
@ -173,17 +177,16 @@ void a_star(Db &db, int64_t sys_id_start, uint max_depth, EdgeFilter e_filter[],
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto edge : now->vertex->data.out) {
|
||||
iter::for_all(now->vacc.out(), [&](auto edge) {
|
||||
if (e_filter[now->depth](t, edge, now)) {
|
||||
Vertex *v = edge->to()->find(t);
|
||||
if (v_filter[now->depth](t, v, now)) {
|
||||
Node *n = new Node(
|
||||
v, edge->to(),
|
||||
now->cost + calc_heuristic_cost(edge->find(t), v), now);
|
||||
VertexAccessor va = edge.to();
|
||||
if (v_filter[now->depth](t, va, now)) {
|
||||
auto cost = calc_heuristic_cost(edge, va);
|
||||
Node *n = new Node(va, now->cost + cost, now);
|
||||
queue.push(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} while (!queue.empty());
|
||||
std::cout << "Found: " << count << " resoults\n";
|
||||
// TODO: GUBI SE MEMORIJA JER SE NODOVI NEBRISU
|
||||
@ -266,7 +269,7 @@ void load_csv(Db &db, char *file_path, char *edge_file_path)
|
||||
|
||||
std::string line;
|
||||
|
||||
auto &t = db.tx_engine.begin();
|
||||
DbAccessor t(db);
|
||||
int max_score = 1000000;
|
||||
|
||||
// VERTEX import
|
||||
@ -276,7 +279,7 @@ void load_csv(Db &db, char *file_path, char *edge_file_path)
|
||||
start_vertex_id = id;
|
||||
}
|
||||
|
||||
auto vertex_accessor = db.graph.vertices.insert(t);
|
||||
auto vertex_accessor = t.vertex_insert();
|
||||
vertex_accessor.property("id", std::make_shared<Int32>(id));
|
||||
vertex_accessor.property("garment_id", std::make_shared<Int32>(gar_id));
|
||||
vertex_accessor.property("garment_category_id",
|
||||
@ -286,10 +289,11 @@ void load_csv(Db &db, char *file_path, char *edge_file_path)
|
||||
"score", std::make_shared<Double>((std::rand() % max_score) /
|
||||
(max_score + 0.0)));
|
||||
for (auto l_name : labels) {
|
||||
auto &label = db.graph.label_store.find_or_create(l_name);
|
||||
auto &label = t.label_find_or_create(l_name);
|
||||
vertex_accessor.add_label(label);
|
||||
}
|
||||
return vertex_accessor.id();
|
||||
|
||||
return vertex_accessor;
|
||||
};
|
||||
|
||||
std::getline(file, line);
|
||||
@ -305,11 +309,12 @@ void load_csv(Db &db, char *file_path, char *edge_file_path)
|
||||
auto splited = split(line, ',');
|
||||
vector<string> labels(splited.begin() + 1,
|
||||
splited.begin() + splited.size() - 2);
|
||||
auto id = v(stoi(splited[0]), labels, stoi(splited[splited.size() - 2]),
|
||||
stoi(splited[splited.size() - 1]));
|
||||
auto vacs =
|
||||
v(stoi(splited[0]), labels, stoi(splited[splited.size() - 2]),
|
||||
stoi(splited[splited.size() - 1]));
|
||||
|
||||
assert(va.size() == (uint64_t)id);
|
||||
va.push_back(db.graph.vertices.find(t, id));
|
||||
assert(va.size() == (uint64_t)vacs.id());
|
||||
va.push_back(vacs);
|
||||
}
|
||||
|
||||
// EDGE IMPORT
|
||||
@ -318,12 +323,9 @@ void load_csv(Db &db, char *file_path, char *edge_file_path)
|
||||
|
||||
auto v2 = va[to - start_vertex_id];
|
||||
|
||||
auto edge_accessor = db.graph.edges.insert(t, v1.vlist, v2.vlist);
|
||||
auto edge_accessor = t.edge_insert(v1, v2);
|
||||
|
||||
v1.vlist->update(t)->data.out.add(edge_accessor.vlist);
|
||||
v2.vlist->update(t)->data.in.add(edge_accessor.vlist);
|
||||
|
||||
auto &edge_type = db.graph.edge_type_store.find_or_create(type);
|
||||
auto &edge_type = t.type_find_or_create(type);
|
||||
edge_accessor.edge_type(edge_type);
|
||||
};
|
||||
|
||||
@ -343,9 +345,9 @@ void load_csv(Db &db, char *file_path, char *edge_file_path)
|
||||
|
||||
void load_graph_dummy(Db &db)
|
||||
{
|
||||
auto &t = db.tx_engine.begin();
|
||||
DbAccessor t(db);
|
||||
auto v = [&](auto id, auto score) {
|
||||
auto vertex_accessor = db.graph.vertices.insert(t);
|
||||
auto vertex_accessor = t.vertex_insert();
|
||||
vertex_accessor.property("id", std::make_shared<Int32>(id));
|
||||
vertex_accessor.property("score", std::make_shared<Double>(score));
|
||||
return vertex_accessor.id();
|
||||
@ -356,15 +358,13 @@ void load_graph_dummy(Db &db)
|
||||
};
|
||||
|
||||
auto e = [&](auto from, auto type, auto to) {
|
||||
auto v1 = db.graph.vertices.find(t, va[from]);
|
||||
auto v1 = t.vertex_find(va[from]);
|
||||
|
||||
auto v2 = db.graph.vertices.find(t, va[to]);
|
||||
auto v2 = t.vertex_find(va[to]);
|
||||
|
||||
auto edge_accessor = db.graph.edges.insert(t, v1.vlist, v2.vlist);
|
||||
v1.vlist->update(t)->data.out.add(edge_accessor.vlist);
|
||||
v2.vlist->update(t)->data.in.add(edge_accessor.vlist);
|
||||
auto edge_accessor = t.edge_insert(v1.get(), v2.get());
|
||||
|
||||
auto &edge_type = db.graph.edge_type_store.find_or_create(type);
|
||||
auto &edge_type = t.type_find_or_create(type);
|
||||
edge_accessor.edge_type(edge_type);
|
||||
};
|
||||
|
||||
|
@ -73,6 +73,6 @@ public:
|
||||
|
||||
build();
|
||||
}
|
||||
CypherLexer(CypherLexer& other) = delete;
|
||||
CypherLexer(CypherLexer&& other) = default;
|
||||
CypherLexer(CypherLexer &other) = delete;
|
||||
CypherLexer(CypherLexer &&other) = default;
|
||||
};
|
||||
|
@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
#include "utils/crtp.hpp"
|
||||
#include "utils/option_ptr.hpp"
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include "utils/crtp.hpp"
|
||||
#include "utils/option_ptr.hpp"
|
||||
|
||||
// RobinHood base.
|
||||
// Entrys are POINTERS alligned to 8B.
|
||||
@ -240,6 +241,10 @@ protected:
|
||||
}
|
||||
|
||||
Iterator create_it(size_t index) { return Iterator(this, index); }
|
||||
ConstIterator create_it(size_t index) const
|
||||
{
|
||||
return ConstIterator(this, index);
|
||||
}
|
||||
|
||||
public:
|
||||
void clear()
|
||||
|
@ -1,9 +1,10 @@
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include "rh_common.hpp"
|
||||
#include "utils/crtp.hpp"
|
||||
#include "utils/likely.hpp"
|
||||
#include "utils/option.hpp"
|
||||
#include "utils/option_ptr.hpp"
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
|
||||
// HashMultiMap with RobinHood collision resolution policy.
|
||||
// Single threaded.
|
||||
@ -45,9 +46,30 @@ public:
|
||||
using typename base::ConstIterator;
|
||||
using typename base::Iterator;
|
||||
|
||||
bool contains(const K &key) { return find(key) != end(); }
|
||||
bool contains(const K &key) const { return find_index(key).is_present(); }
|
||||
|
||||
Iterator find(const K &key_in)
|
||||
{
|
||||
auto index = find_index(key_in);
|
||||
if (index) {
|
||||
return create_it(index.get());
|
||||
} else {
|
||||
return end();
|
||||
}
|
||||
}
|
||||
|
||||
ConstIterator find(const K &key_in) const
|
||||
{
|
||||
auto index = find_index(key_in);
|
||||
if (index) {
|
||||
return create_it(index.get());
|
||||
} else {
|
||||
return end();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Option<size_t> find_index(const K &key_in) const
|
||||
{
|
||||
if (count > 0) {
|
||||
auto key = std::ref(key_in);
|
||||
@ -59,7 +81,7 @@ public:
|
||||
while (other.valid() && off < border) {
|
||||
auto other_off = other.off();
|
||||
if (other_off == off && key == other.ptr()->get_key()) {
|
||||
return create_it(now);
|
||||
return Option<size_t>(now);
|
||||
|
||||
} else if (other_off < off) { // Other is rich
|
||||
break;
|
||||
@ -73,9 +95,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
return Option<size_t>();
|
||||
}
|
||||
|
||||
public:
|
||||
// Inserts element.
|
||||
void add(D *data) { add(data->get_key(), data); }
|
||||
|
||||
@ -211,7 +234,7 @@ public:
|
||||
private:
|
||||
// Skips same key valus as other. true if whole map is full of same key
|
||||
// values.
|
||||
bool skip(size_t &now, Combined &other, size_t other_off, size_t mask)
|
||||
bool skip(size_t &now, Combined &other, size_t other_off, size_t mask) const
|
||||
{
|
||||
auto other_key = other.ptr()->get_key();
|
||||
size_t start = now;
|
||||
|
6
src/database/db.cpp
Normal file
6
src/database/db.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include "database/db.hpp"
|
||||
|
||||
Db::Db() = default;
|
||||
Db::Db(const std::string &name) : name_(name) {}
|
||||
|
||||
std::string &Db::name() { return name_; }
|
75
src/database/db_accessor.cpp
Normal file
75
src/database/db_accessor.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include "database/db_accessor.hpp"
|
||||
|
||||
DbAccessor::DbAccessor(Db &db) : db(DbTransaction(db, db.tx_engine.begin())) {}
|
||||
|
||||
// VERTEX METHODS
|
||||
auto DbAccessor::vertex_access()
|
||||
{
|
||||
return iter::make_map(
|
||||
iter::make_iter(this->db.db.graph.vertices.access()),
|
||||
[&](auto e) -> auto { return Vertex::Accessor(&(e->second), db); });
|
||||
}
|
||||
|
||||
Option<const Vertex::Accessor> DbAccessor::vertex_find(const Id &id)
|
||||
{
|
||||
return this->db.db.graph.vertices.find(db, id);
|
||||
}
|
||||
|
||||
Vertex::Accessor DbAccessor::vertex_insert()
|
||||
{
|
||||
return this->db.db.graph.vertices.insert(db);
|
||||
}
|
||||
|
||||
// EDGE METHODS
|
||||
|
||||
Option<const Edge::Accessor> DbAccessor::edge_find(const Id &id)
|
||||
{
|
||||
return db.db.graph.edges.find(db, id);
|
||||
}
|
||||
|
||||
Edge::Accessor DbAccessor::edge_insert(Vertex::Accessor const &from,
|
||||
Vertex::Accessor const &to)
|
||||
{
|
||||
auto edge_accessor = db.db.graph.edges.insert(db, from.vlist, to.vlist);
|
||||
from.update()->data.out.add(edge_accessor.vlist);
|
||||
to.update()->data.in.add(edge_accessor.vlist);
|
||||
return edge_accessor;
|
||||
}
|
||||
|
||||
// LABEL METHODS
|
||||
const Label &DbAccessor::label_find_or_create(const std::string &name)
|
||||
{
|
||||
return db.db.graph.label_store.find_or_create(
|
||||
std::forward<const std::string &>(name));
|
||||
}
|
||||
|
||||
bool DbAccessor::label_contains(const std::string &name)
|
||||
{
|
||||
return db.db.graph.label_store.contains(
|
||||
std::forward<const std::string &>(name));
|
||||
}
|
||||
|
||||
VertexIndexRecordCollection &DbAccessor::label_find_index(const Label &label)
|
||||
{
|
||||
return db.db.graph.vertices.find_label_index(label);
|
||||
}
|
||||
|
||||
// TYPE METHODS
|
||||
const EdgeType &DbAccessor::type_find_or_create(const std::string &name)
|
||||
{
|
||||
return db.db.graph.edge_type_store.find_or_create(
|
||||
std::forward<const std::string &>(name));
|
||||
}
|
||||
|
||||
bool DbAccessor::type_contains(const std::string &name)
|
||||
{
|
||||
return db.db.graph.edge_type_store.contains(
|
||||
std::forward<const std::string &>(name));
|
||||
}
|
||||
|
||||
// TRANSACTION METHODS
|
||||
void DbAccessor::commit() { db.trans.commit(); }
|
||||
void DbAccessor::abort() { db.trans.abort(); }
|
||||
|
||||
// // EASE OF USE METHODS
|
||||
// tx::Transaction &DbAccessor::operator*() { return db.trans; }
|
8
src/database/db_transaction.cpp
Normal file
8
src/database/db_transaction.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
#include "database/db.hpp"
|
||||
#include "database/db_transaction.hpp"
|
||||
|
||||
void DbTransaction::update_label_index(const Label &label,
|
||||
VertexIndexRecord &&index_record)
|
||||
{
|
||||
db.graph.vertices.update_label_index(label, std::move(index_record));
|
||||
}
|
22
src/storage/edge_accessor.cpp
Normal file
22
src/storage/edge_accessor.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
|
||||
void Edge::Accessor::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
|
||||
{
|
||||
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
|
||||
{
|
||||
return Vertex::Accessor(this->vlist->from(), this->db);
|
||||
}
|
||||
|
||||
Vertex::Accessor Edge::Accessor::to() const
|
||||
{
|
||||
return Vertex::Accessor(this->vlist->to(), this->db);
|
||||
}
|
@ -1,21 +1,17 @@
|
||||
#include "storage/edges.hpp"
|
||||
|
||||
Edge::Accessor Edges::find(tx::Transaction &t, const Id &id)
|
||||
Option<const Edge::Accessor> 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 Edge::Accessor();
|
||||
if (edges_iterator == edges_accessor.end())
|
||||
return make_option<const Edge::Accessor>();
|
||||
|
||||
// find edge
|
||||
auto edge = edges_iterator->second.find(t);
|
||||
|
||||
if (edge == nullptr) return Edge::Accessor();
|
||||
|
||||
return Edge::Accessor(edge, &edges_iterator->second, this);
|
||||
return make_option_const(Edge::Accessor(&edges_iterator->second, t));
|
||||
}
|
||||
|
||||
Edge::Accessor Edges::insert(tx::Transaction &t, VertexRecord *from,
|
||||
Edge::Accessor Edges::insert(DbTransaction &t, VertexRecord *from,
|
||||
VertexRecord *to)
|
||||
{
|
||||
// get next vertex id
|
||||
@ -30,7 +26,7 @@ Edge::Accessor Edges::insert(tx::Transaction &t, VertexRecord *from,
|
||||
|
||||
// create new vertex
|
||||
auto inserted_edge_record = result.first;
|
||||
auto edge = inserted_edge_record->second.insert(t);
|
||||
auto edge = inserted_edge_record->second.insert(t.trans);
|
||||
|
||||
return Edge::Accessor(edge, &inserted_edge_record->second, this);
|
||||
return Edge::Accessor(edge, &inserted_edge_record->second, t);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "database/db.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
|
||||
#include "storage/vertices.hpp"
|
||||
#include "utils/iterator/iterator.hpp"
|
||||
|
||||
size_t Vertex::Accessor::out_degree() const
|
||||
{
|
||||
@ -12,10 +13,7 @@ size_t Vertex::Accessor::in_degree() const
|
||||
return this->record->data.in.degree();
|
||||
}
|
||||
|
||||
size_t Vertex::Accessor::degree() const
|
||||
{
|
||||
return in_degree() + out_degree();
|
||||
}
|
||||
size_t Vertex::Accessor::degree() const { return in_degree() + out_degree(); }
|
||||
|
||||
void Vertex::Accessor::add_label(const Label &label)
|
||||
{
|
||||
@ -23,8 +21,8 @@ void Vertex::Accessor::add_label(const Label &label)
|
||||
this->record->data.labels.add(label);
|
||||
|
||||
// update index
|
||||
this->store->update_label_index(
|
||||
label, VertexIndexRecord(this->record, this->vlist));
|
||||
this->db.update_label_index(label,
|
||||
VertexIndexRecord(this->record, this->vlist));
|
||||
}
|
||||
|
||||
bool Vertex::Accessor::has_label(const Label &label) const
|
||||
@ -32,7 +30,30 @@ bool Vertex::Accessor::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> &Vertex::Accessor::labels() const
|
||||
{
|
||||
return this->record->data.labels();
|
||||
}
|
||||
|
||||
// Returns unfilled accessors
|
||||
auto Vertex::Accessor::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); });
|
||||
}
|
||||
|
||||
// Returns unfilled accessors
|
||||
auto Vertex::Accessor::in() const
|
||||
{
|
||||
DbTransaction &t = this->db;
|
||||
return iter::make_one_time_accessor(
|
||||
iter::make_map(iter::make_iter_ref(record->data.in),
|
||||
[&](auto e) -> auto { return Edge::Accessor(e, t); }));
|
||||
}
|
||||
|
||||
bool Vertex::Accessor::in_contains(Vertex::Accessor const &other) const
|
||||
{
|
||||
return record->data.in.contains(other.vlist);
|
||||
}
|
||||
|
@ -1,41 +1,19 @@
|
||||
#include "storage/vertices.hpp"
|
||||
|
||||
Vertices::vertices_t::Accessor Vertices::access()
|
||||
{
|
||||
return vertices.access();
|
||||
}
|
||||
Vertices::vertices_t::Accessor Vertices::access() { return vertices.access(); }
|
||||
|
||||
const Vertex::Accessor Vertices::find(tx::Transaction &t, const Id &id)
|
||||
Option<const Vertex::Accessor> 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 Vertex::Accessor();
|
||||
if (vertices_iterator == vertices_accessor.end())
|
||||
return make_option<const Vertex::Accessor>();
|
||||
|
||||
// find vertex
|
||||
auto vertex = vertices_iterator->second.find(t);
|
||||
|
||||
if (vertex == nullptr) return Vertex::Accessor();
|
||||
|
||||
return Vertex::Accessor(vertex, &vertices_iterator->second, this);
|
||||
return make_option_const(Vertex::Accessor(&vertices_iterator->second, t));
|
||||
}
|
||||
|
||||
// TODO
|
||||
const Vertex::Accessor Vertices::first(tx::Transaction &t)
|
||||
{
|
||||
auto vertices_accessor = vertices.access();
|
||||
auto vertices_iterator = vertices_accessor.begin();
|
||||
|
||||
if (vertices_iterator == vertices_accessor.end()) return Vertex::Accessor();
|
||||
|
||||
auto vertex = vertices_iterator->second.find(t);
|
||||
|
||||
if (vertex == nullptr) return Vertex::Accessor();
|
||||
|
||||
return Vertex::Accessor(vertex, &vertices_iterator->second, this);
|
||||
}
|
||||
|
||||
Vertex::Accessor Vertices::insert(tx::Transaction &t)
|
||||
Vertex::Accessor Vertices::insert(DbTransaction &t)
|
||||
{
|
||||
// get next vertex id
|
||||
auto next = counter.next();
|
||||
@ -50,9 +28,9 @@ Vertex::Accessor Vertices::insert(tx::Transaction &t)
|
||||
|
||||
// create new vertex
|
||||
auto inserted_vertex_record = result.first;
|
||||
auto vertex = inserted_vertex_record->second.insert(t);
|
||||
auto vertex = inserted_vertex_record->second.insert(t.trans);
|
||||
|
||||
return Vertex::Accessor(vertex, &inserted_vertex_record->second, this);
|
||||
return Vertex::Accessor(vertex, &inserted_vertex_record->second, t);
|
||||
}
|
||||
|
||||
void Vertices::update_label_index(const Label &label,
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "data_structures/concurrent/skiplist.hpp"
|
||||
#include "data_structures/static_array.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
#include "logging/default.hpp"
|
||||
#include "logging/streams/stdout.hpp"
|
||||
#include "utils/sysinfo/memory.hpp"
|
||||
|
||||
using std::cout;
|
||||
@ -231,3 +233,9 @@ void memory_check(size_t no_threads, std::function<void()> f)
|
||||
std::cout << "leaked: " << leaked << "\n";
|
||||
permanent_assert(leaked <= 0, "Memory leak check");
|
||||
}
|
||||
|
||||
//Initializes loging faccilityes
|
||||
void init_log(){
|
||||
logging::init_async();
|
||||
logging::log->pipe(std::make_unique<Stdout>());
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "common.h"
|
||||
#include "data_structures/linked_list.hpp"
|
||||
|
||||
using std::cout;
|
||||
@ -10,51 +11,52 @@ using std::endl;
|
||||
template <typename list_type>
|
||||
void test_concurrent_list_access(list_type &list, std::size_t size)
|
||||
{
|
||||
// test concurrent access
|
||||
for (int i = 0; i < 1000000; ++i) {
|
||||
// test concurrent access
|
||||
for (int i = 0; i < 1000000; ++i) {
|
||||
|
||||
std::thread t1([&list] {
|
||||
list.push_front(1);
|
||||
list.pop_front();
|
||||
});
|
||||
std::thread t1([&list] {
|
||||
list.push_front(1);
|
||||
list.pop_front();
|
||||
});
|
||||
|
||||
std::thread t2([&list] {
|
||||
list.push_front(2);
|
||||
list.pop_front();
|
||||
});
|
||||
std::thread t2([&list] {
|
||||
list.push_front(2);
|
||||
list.pop_front();
|
||||
});
|
||||
|
||||
t1.join();
|
||||
t2.join();
|
||||
t1.join();
|
||||
t2.join();
|
||||
|
||||
assert(list.size() == size);
|
||||
}
|
||||
assert(list.size() == size);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
LinkedList<int> list;
|
||||
init_log();
|
||||
LinkedList<int> list;
|
||||
|
||||
// push & pop operations
|
||||
list.push_front(10);
|
||||
list.push_front(20);
|
||||
auto a = list.front();
|
||||
assert(a == 20);
|
||||
list.pop_front();
|
||||
a = list.front();
|
||||
assert(a == 10);
|
||||
list.pop_front();
|
||||
assert(list.size() == 0);
|
||||
// push & pop operations
|
||||
list.push_front(10);
|
||||
list.push_front(20);
|
||||
auto a = list.front();
|
||||
assert(a == 20);
|
||||
list.pop_front();
|
||||
a = list.front();
|
||||
assert(a == 10);
|
||||
list.pop_front();
|
||||
assert(list.size() == 0);
|
||||
|
||||
// concurrent test
|
||||
LinkedList<int> concurrent_list;
|
||||
concurrent_list.push_front(1);
|
||||
concurrent_list.push_front(1);
|
||||
std::list<int> no_concurrent_list;
|
||||
no_concurrent_list.push_front(1);
|
||||
no_concurrent_list.push_front(1);
|
||||
// concurrent test
|
||||
LinkedList<int> concurrent_list;
|
||||
concurrent_list.push_front(1);
|
||||
concurrent_list.push_front(1);
|
||||
std::list<int> no_concurrent_list;
|
||||
no_concurrent_list.push_front(1);
|
||||
no_concurrent_list.push_front(1);
|
||||
|
||||
test_concurrent_list_access(concurrent_list, 2);
|
||||
// test_concurrent_list_access(no_concurrent_list, 2);
|
||||
test_concurrent_list_access(concurrent_list, 2);
|
||||
// test_concurrent_list_access(no_concurrent_list, 2);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ constexpr size_t key_range = elems_per_thread * THREADS_NO * 2;
|
||||
// Test checks for missing data and changed/overwriten data.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
map_t skiplist;
|
||||
|
||||
|
@ -10,6 +10,7 @@ constexpr size_t key_range = elems_per_thread * THREADS_NO * 2;
|
||||
// Test checks for missing data and changed/overwriten data.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
map_t skiplist;
|
||||
|
||||
|
@ -5,6 +5,7 @@ constexpr size_t elems_per_thread = 1e5;
|
||||
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [&] {
|
||||
ds::static_array<std::thread, THREADS_NO> threads;
|
||||
map_t skiplist;
|
||||
|
@ -7,18 +7,20 @@ constexpr size_t elements = 2e6;
|
||||
// Test for simple memory leaks
|
||||
int main()
|
||||
{
|
||||
memory_check(THREADS_NO, [] {
|
||||
map_t skiplist;
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
map_t skiplist;
|
||||
|
||||
auto futures = run<size_t>(THREADS_NO, skiplist, [](auto acc, auto index) {
|
||||
for (size_t i = 0; i < elements; i++) {
|
||||
acc.insert(i, index);
|
||||
}
|
||||
return index;
|
||||
auto futures =
|
||||
run<size_t>(THREADS_NO, skiplist, [](auto acc, auto index) {
|
||||
for (size_t i = 0; i < elements; i++) {
|
||||
acc.insert(i, index);
|
||||
}
|
||||
return index;
|
||||
});
|
||||
collect(futures);
|
||||
|
||||
auto accessor = skiplist.access();
|
||||
check_size<map_t>(accessor, elements);
|
||||
});
|
||||
collect(futures);
|
||||
|
||||
auto accessor = skiplist.access();
|
||||
check_size<map_t>(accessor, elements);
|
||||
});
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ constexpr size_t elems_per_thread = 16e5;
|
||||
// Known memory leak at 1,600,000 elements.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [&] {
|
||||
ds::static_array<std::thread, THREADS_NO> threads;
|
||||
map_t skiplist;
|
||||
|
@ -13,6 +13,7 @@ constexpr size_t no_insert_for_one_delete = 1;
|
||||
// succeed.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
multimap_t skiplist;
|
||||
|
||||
|
@ -14,6 +14,7 @@ constexpr size_t no_insert_for_one_delete = 1;
|
||||
// succeed.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
multimap_t skiplist;
|
||||
|
||||
|
@ -15,6 +15,7 @@ constexpr size_t no_insert_for_one_delete = 2;
|
||||
// succeed.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
multimap_t skiplist;
|
||||
|
||||
|
@ -13,6 +13,7 @@ constexpr size_t no_insert_for_one_delete = 1;
|
||||
// succeed.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
multimap_t skiplist;
|
||||
std::atomic<long long> size(0);
|
||||
|
@ -11,6 +11,7 @@ constexpr size_t no_insert_for_one_delete = 1;
|
||||
// succeed.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
multiset_t skiplist;
|
||||
|
||||
|
@ -12,6 +12,7 @@ constexpr size_t no_insert_for_one_delete = 2;
|
||||
// Calls of remove method are interleaved with insert calls.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
map_t skiplist;
|
||||
|
||||
|
@ -10,6 +10,7 @@ constexpr size_t no_insert_for_one_delete = 1;
|
||||
// Calls of remove method are interleaved with insert calls.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
map_t skiplist;
|
||||
|
||||
|
@ -12,6 +12,7 @@ constexpr size_t no_insert_for_one_delete = 2;
|
||||
// Calls of remove method are interleaved with insert calls.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
map_t skiplist;
|
||||
|
||||
|
@ -10,6 +10,7 @@ constexpr size_t no_insert_for_one_delete = 2;
|
||||
// Calls of remove method are interleaved with insert calls.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
set_t skiplist;
|
||||
|
||||
|
@ -14,6 +14,7 @@ constexpr size_t no_insert_for_one_delete = 1;
|
||||
// no_find_per_change and no_insert_for_one_delete.
|
||||
int main()
|
||||
{
|
||||
init_log();
|
||||
memory_check(THREADS_NO, [] {
|
||||
map_t skiplist;
|
||||
|
||||
|
@ -1,21 +1,20 @@
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
#include <cassert>
|
||||
#include <deque>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "communication/bolt/v1/transport/chunked_encoder.hpp"
|
||||
#include "logging/default.hpp"
|
||||
#include "logging/streams/stdout.hpp"
|
||||
|
||||
using byte = unsigned char;
|
||||
|
||||
void print_hex(byte x)
|
||||
{
|
||||
printf("%02X ", static_cast<byte>(x));
|
||||
}
|
||||
void print_hex(byte x) { printf("%02X ", static_cast<byte>(x)); }
|
||||
|
||||
class DummyStream
|
||||
{
|
||||
public:
|
||||
void write(const byte* values, size_t n)
|
||||
void write(const byte *values, size_t n)
|
||||
{
|
||||
num_calls++;
|
||||
data.insert(data.end(), values, values + n);
|
||||
@ -28,36 +27,33 @@ public:
|
||||
return c;
|
||||
}
|
||||
|
||||
size_t pop_size()
|
||||
{
|
||||
return ((size_t)pop() << 8) | pop();
|
||||
}
|
||||
size_t pop_size() { return ((size_t)pop() << 8) | pop(); }
|
||||
|
||||
void print()
|
||||
{
|
||||
for(size_t i = 0; i < data.size(); ++i)
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
print_hex(data[i]);
|
||||
}
|
||||
|
||||
std::deque<byte> data;
|
||||
size_t num_calls {0};
|
||||
size_t num_calls{0};
|
||||
};
|
||||
|
||||
using Encoder = bolt::ChunkedEncoder<DummyStream>;
|
||||
|
||||
void write_ff(Encoder& encoder, size_t n)
|
||||
void write_ff(Encoder &encoder, size_t n)
|
||||
{
|
||||
std::vector<byte> v;
|
||||
|
||||
for(size_t i = 0; i < n; ++i)
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
v.push_back('\xFF');
|
||||
|
||||
encoder.write(v.data(), v.size());
|
||||
}
|
||||
|
||||
void check_ff(DummyStream& stream, size_t n)
|
||||
void check_ff(DummyStream &stream, size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; ++i)
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
assert(stream.pop() == byte('\xFF'));
|
||||
|
||||
(void)stream;
|
||||
@ -65,6 +61,8 @@ void check_ff(DummyStream& stream, size_t n)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
logging::init_async();
|
||||
logging::log->pipe(std::make_unique<Stdout>());
|
||||
DummyStream stream;
|
||||
bolt::ChunkedEncoder<DummyStream> encoder(stream);
|
||||
|
||||
@ -80,7 +78,7 @@ int main(void)
|
||||
write_ff(encoder, 67000);
|
||||
encoder.flush();
|
||||
|
||||
for(int i = 0; i < 10000; ++i)
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
write_ff(encoder, 1500);
|
||||
encoder.flush();
|
||||
|
||||
@ -100,8 +98,7 @@ int main(void)
|
||||
|
||||
size_t k = 10000 * 1500;
|
||||
|
||||
while(k > 0)
|
||||
{
|
||||
while (k > 0) {
|
||||
auto size = k > encoder.chunk_size ? encoder.chunk_size : k;
|
||||
assert(stream.pop_size() == size);
|
||||
check_ff(stream, size);
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "data_structures/concurrent/concurrent_map.hpp"
|
||||
#include "logging/default.hpp"
|
||||
#include "logging/streams/stdout.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
|
||||
using std::cout;
|
||||
@ -8,59 +10,64 @@ using std::endl;
|
||||
|
||||
using skiplist_t = ConcurrentMap<int, int>;
|
||||
|
||||
void print_skiplist(const skiplist_t::Accessor &skiplist) {
|
||||
cout << "---- skiplist now has: ";
|
||||
void print_skiplist(const skiplist_t::Accessor &skiplist)
|
||||
{
|
||||
cout << "---- skiplist now has: ";
|
||||
|
||||
for (auto &kv : skiplist)
|
||||
cout << "(" << kv.first << ", " << kv.second << ") ";
|
||||
for (auto &kv : skiplist)
|
||||
cout << "(" << kv.first << ", " << kv.second << ") ";
|
||||
|
||||
cout << "----" << endl;
|
||||
cout << "----" << endl;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
skiplist_t skiplist;
|
||||
auto accessor = skiplist.access();
|
||||
int main(void)
|
||||
{
|
||||
logging::init_async();
|
||||
logging::log->pipe(std::make_unique<Stdout>());
|
||||
skiplist_t skiplist;
|
||||
auto accessor = skiplist.access();
|
||||
|
||||
// insert 10
|
||||
permanent_assert(accessor.insert(1, 10).second == true, "add first element");
|
||||
// insert 10
|
||||
permanent_assert(accessor.insert(1, 10).second == true,
|
||||
"add first element");
|
||||
|
||||
// try insert 10 again (should fail)
|
||||
permanent_assert(accessor.insert(1, 10).second == false,
|
||||
"add the same element, should fail");
|
||||
// try insert 10 again (should fail)
|
||||
permanent_assert(accessor.insert(1, 10).second == false,
|
||||
"add the same element, should fail");
|
||||
|
||||
// insert 20
|
||||
permanent_assert(accessor.insert(2, 20).second == true,
|
||||
"insert new unique element");
|
||||
// insert 20
|
||||
permanent_assert(accessor.insert(2, 20).second == true,
|
||||
"insert new unique element");
|
||||
|
||||
print_skiplist(accessor);
|
||||
print_skiplist(accessor);
|
||||
|
||||
// value at key 3 shouldn't exist
|
||||
permanent_assert((accessor.find(3) == accessor.end()) == true,
|
||||
"try to find element which doesn't exist");
|
||||
// value at key 3 shouldn't exist
|
||||
permanent_assert((accessor.find(3) == accessor.end()) == true,
|
||||
"try to find element which doesn't exist");
|
||||
|
||||
// value at key 2 should exist
|
||||
permanent_assert((accessor.find(2) != accessor.end()) == true,
|
||||
"find iterator");
|
||||
// value at key 2 should exist
|
||||
permanent_assert((accessor.find(2) != accessor.end()) == true,
|
||||
"find iterator");
|
||||
|
||||
// at key 2 is 20 (true)
|
||||
permanent_assert(accessor.find(2)->second == 20, "find element");
|
||||
// at key 2 is 20 (true)
|
||||
permanent_assert(accessor.find(2)->second == 20, "find element");
|
||||
|
||||
// removed existing (1)
|
||||
permanent_assert(accessor.remove(1) == true, "try to remove element");
|
||||
// removed existing (1)
|
||||
permanent_assert(accessor.remove(1) == true, "try to remove element");
|
||||
|
||||
// removed non-existing (3)
|
||||
permanent_assert(accessor.remove(3) == false,
|
||||
"try to remove element which doesn't exist");
|
||||
// removed non-existing (3)
|
||||
permanent_assert(accessor.remove(3) == false,
|
||||
"try to remove element which doesn't exist");
|
||||
|
||||
// insert (1, 10)
|
||||
permanent_assert(accessor.insert(1, 10).second == true,
|
||||
"insert unique element");
|
||||
// insert (1, 10)
|
||||
permanent_assert(accessor.insert(1, 10).second == true,
|
||||
"insert unique element");
|
||||
|
||||
// insert (4, 40)
|
||||
permanent_assert(accessor.insert(4, 40).second == true,
|
||||
"insert unique element");
|
||||
// insert (4, 40)
|
||||
permanent_assert(accessor.insert(4, 40).second == true,
|
||||
"insert unique element");
|
||||
|
||||
print_skiplist(accessor);
|
||||
print_skiplist(accessor);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "data_structures/concurrent/concurrent_set.hpp"
|
||||
#include "logging/default.hpp"
|
||||
#include "logging/streams/stdout.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
|
||||
using std::cout;
|
||||
@ -18,6 +20,8 @@ void print_skiplist(const ConcurrentSet<int>::Accessor &skiplist)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
logging::init_async();
|
||||
logging::log->pipe(std::make_unique<Stdout>());
|
||||
ConcurrentSet<int> set;
|
||||
|
||||
auto accessor = set.access();
|
||||
|
Loading…
Reference in New Issue
Block a user