diff --git a/include/barrier/barrier.hpp b/include/barrier/barrier.hpp index 6520c0cf7..fe848c88d 100644 --- a/include/barrier/barrier.hpp +++ b/include/barrier/barrier.hpp @@ -145,7 +145,7 @@ public: VertexAccessor update() const; - bool remove() const; + void remove() const; const Property &at(VertexPropertyFamily &key) const; @@ -204,7 +204,7 @@ public: EdgeAccessor update() const; - bool remove() const; + void remove() const; const Property &at(EdgePropertyFamily &key) const; diff --git a/include/mvcc/version_list.hpp b/include/mvcc/version_list.hpp index 2b7046548..0523559b6 100644 --- a/include/mvcc/version_list.hpp +++ b/include/mvcc/version_list.hpp @@ -178,12 +178,11 @@ public: return remove(record, t), true; } - bool remove(T *record, tx::Transaction &t) + void remove(T *record, tx::Transaction &t) { assert(record != nullptr); lock_and_validate(record, t); record->mark_deleted(t); - return true; } const Id id; diff --git a/include/query_engine/hardcode/queries.hpp b/include/query_engine/hardcode/queries.hpp index 303b664d2..6424b745a 100644 --- a/include/query_engine/hardcode/queries.hpp +++ b/include/query_engine/hardcode/queries.hpp @@ -271,13 +271,111 @@ auto load_queries(Db &db) DbAccessor t(db); auto &type = t.type_find_or_create("TYPE"); + auto prop_name = t.vertex_property_key("name", args[0]->flags); - auto it_type = type.index().for_range(t); - auto it_vertex = t.vertex_access(); + Option<const EdgeAccessor> r; - // TODO - // if (it_type.count().max > it_vertex.count().max) { - // } + auto it_type = type.index() + .for_range(t) + .clone_to(r) // Savepoint + .from() // Backtracing + .has_property(prop_name, *args[0].get()) + .replace(r); // Load savepoint + + auto it_vertex = t.vertex_access() + .fill() + .has_property(prop_name, *args[0].get()) + .out() + .type(type); + + if (it_type.count() > it_vertex.count()) { + // Going through vertices wiil probably be faster + it_vertex.to().for_all([&](auto m) { + // PRINT m + }); + + } else { + // Going through edges wiil probably be faster + it_type.to().for_all([&](auto m) { + // PRINT m + }); + } + + return t.commit(); + }; + + // MATCH (n)-[:TYPE]->(m) WHERE n.name = "kruno" RETURN n,m + auto match_name_type_return_cross = [&db](const properties_t &args) { + DbAccessor t(db); + + auto &type = t.type_find_or_create("TYPE"); + auto prop_name = t.vertex_property_key("name", args[0]->flags); + + Option<const VertexAccessor> n; + Option<const EdgeAccessor> r; + + auto it_type = type.index() + .for_range(t) + .clone_to(r) // Savepoint + .from() // Backtracing + .has_property(prop_name, *args[0].get()) + .clone_to(n) // Savepoint + .replace(r); // Load savepoint + + auto it_vertex = t.vertex_access() + .fill() + .has_property(prop_name, *args[0].get()) + .clone_to(n) // Savepoint + .out() + .type(type); + + if (it_type.count() > it_vertex.count()) { + // Going through vertices wiil probably be faster + it_vertex.to().for_all([&](auto m) { + // PRINT n,m + }); + + } else { + // Going through edges wiil probably be faster + it_type.to().for_all([&](auto m) { + // PRINT n,m + }); + } + + return t.commit(); + }; + + // MATCH (n:LABEL)-[:TYPE]->(m) RETURN n + auto match_label_type_return = [&db](const properties_t &args) { + DbAccessor t(db); + + auto &type = t.type_find_or_create("TYPE"); + auto &label = t.label_find_or_create("LABEL"); + + Option<const VertexAccessor> bt; + + auto it_type = type.index().for_range(t).from().label(label); + + auto it_vertex = t.vertex_access() + .fill() + .label(label) + .clone_to(bt) // Savepoint + .out() + .type(type) + .replace(bt); // Load savepoint + + if (it_type.count() > it_vertex.count()) { + // Going through vertices wiil probably be faster + it_vertex.for_all([&](auto n) { + // PRINT n + }); + + } else { + // Going through edges wiil probably be faster + it_type.for_all([&](auto n) { + // PRINT n + }); + } return t.commit(); }; @@ -307,6 +405,9 @@ auto load_queries(Db &db) queries[14897166600223619735u] = match_edge_all_delete; queries[16888549834923624215u] = match_edge_type_delete; queries[11675960684124428508u] = match_id_type_return; + queries[1554436524951961398u] = match_name_type_return; + queries[8537338362659537296u] = match_name_type_return_cross; + queries[8918221081398321263u] = match_label_type_return; return queries; } diff --git a/include/storage/edge_accessor.hpp b/include/storage/edge_accessor.hpp index 05d266290..197cf378d 100644 --- a/include/storage/edge_accessor.hpp +++ b/include/storage/edge_accessor.hpp @@ -15,19 +15,23 @@ class Edges; // There exists circular dependecy with VertexAccessor. class EdgeAccessor : public RecordAccessor<TypeGroupEdge, EdgeAccessor> { + friend VertexAccessor; + public: using RecordAccessor::RecordAccessor; typedef Edge record_t; typedef EdgeRecord record_list_t; // Removes self and disconects vertices from it. - bool remove() const; + void remove() const; void edge_type(EdgeType const &edge_type); const EdgeType &edge_type() const; + // EdgeAccessor doesnt need to be filled VertexAccessor from() const; + // EdgeAccessor doesnt need to be filled VertexAccessor to() const; }; diff --git a/include/storage/record_accessor.hpp b/include/storage/record_accessor.hpp index 9a8e80fb8..a818f4324 100644 --- a/include/storage/record_accessor.hpp +++ b/include/storage/record_accessor.hpp @@ -146,7 +146,7 @@ public: } protected: - bool remove() const; + void remove() const; T *record{nullptr}; vlist_t *const vlist; diff --git a/include/storage/vertex_accessor.hpp b/include/storage/vertex_accessor.hpp index 7b73e8cb3..e9d6b216e 100644 --- a/include/storage/vertex_accessor.hpp +++ b/include/storage/vertex_accessor.hpp @@ -17,8 +17,8 @@ public: typedef Vertex record_t; typedef VertexRecord record_list_t; - // Removes only self. - bool remove() const { return RecordAccessor::remove(); } + // Removes self and all edges connected to it. + void remove() const; size_t out_degree() const; diff --git a/include/utils/iterator/count.hpp b/include/utils/iterator/count.hpp index 20016970f..074f4a44d 100644 --- a/include/utils/iterator/count.hpp +++ b/include/utils/iterator/count.hpp @@ -1,8 +1,10 @@ #pragma once +#include "utils/total_ordering.hpp" + // Represents number of to be returned elements from iterator. Where acutal // number is probably somwhere in [min,max]. -class Count +class Count : public TotalOrdering<Count> { public: @@ -16,6 +18,18 @@ public: return *this; } + size_t avg() const { return ((max - min) >> 1) + min; } + + friend constexpr bool operator<(const Count &lhs, const Count &rhs) + { + return lhs.avg() < rhs.avg(); + } + + friend constexpr bool operator==(const Count &lhs, const Count &rhs) + { + return lhs.avg() == rhs.avg(); + } + size_t min; size_t max; }; diff --git a/include/utils/iterator/flat_map.hpp b/include/utils/iterator/flat_map.hpp new file mode 100644 index 000000000..9fc748740 --- /dev/null +++ b/include/utils/iterator/flat_map.hpp @@ -0,0 +1,77 @@ +#pragma once + +namespace iter +{ + +// Class which maps values returned by I iterator into iterators of type J +// ,which +// return value of type T, with function OP. +// function. +// T - type of return value +// I - iterator type +// J - iterator type returned from OP +// OP - type of mapper function +template <class T, class I, class J, class OP> +class FlatMap : public IteratorBase<T> +{ + +public: + FlatMap() = delete; + + // FlatMap operation is designed to be used in chained calls which operate + // on a + // iterator. FlatMap will in that usecase receive other iterator by value + // and + // std::move is a optimization for it. + FlatMap(I &&iter, OP &&op) : iter(std::move(iter)), op(std::move(op)) {} + + FlatMap(FlatMap &&m) + : iter(std::move(m.iter)), op(std::move(m.op)), + sub_iter(std::move(m.sub_iter)) + { + } + + ~FlatMap() final {} + + Option<T> next() final + { + do { + if (!sub_iter.is_present()) { + auto item = iter.next(); + if (item.is_present()) { + sub_iter = Option<J>(op(item.take())); + } else { + return Option<T>(); + } + } + + auto item = sub_iter.get().next(); + if (item.is_present()) { + return std::move(item); + } else { + sub_iter.take(); + } + } while (true); + } + + Count count() final + { + // TODO: Correct count, are at least correcter + return iter.count(); + } + +private: + I iter; + Option<J> sub_iter; + OP op; +}; + +template <class I, class OP> +auto make_flat_map(I &&iter, OP &&op) +{ + // Compiler cant deduce type T and J. decltype is here to help with it. + return FlatMap<decltype(op(iter.next().take()).next().take()), I, + decltype(op(iter.next().take())), OP>(std::move(iter), + std::move(op)); +} +} diff --git a/include/utils/iterator/inspect.hpp b/include/utils/iterator/inspect.hpp new file mode 100644 index 000000000..8fba73b37 --- /dev/null +++ b/include/utils/iterator/inspect.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include "utils/iterator/iterator_base.hpp" +#include "utils/option.hpp" + +namespace iter +{ + +// Class which inspects values returned by I iterator before passing thenm as +// result. +// function. +// T - type of return value +// I - iterator type +// OP - type of inspector function. OP: T&->void +template <class T, class I, class OP> +class Inspect : public IteratorBase<T> +{ + +public: + Inspect() = delete; + + // Inspect operation is designed to be used in chained calls which operate + // on a + // iterator. Inspect will in that usecase receive other iterator by value + // and + // std::move is a optimization for it. + Inspect(I &&iter, OP &&op) : iter(std::move(iter)), op(std::move(op)) {} + + Inspect(Inspect &&m) : iter(std::move(m.iter)), op(std::move(m.op)) {} + + ~Inspect() final {} + + Option<T> next() final + { + auto item = iter.next(); + if (item.is_present()) { + op(item.get()); + return std::move(item); + } else { + return Option<T>(); + } + } + + Count count() final { return iter.count(); } + +private: + I iter; + OP op; +}; + +template <class I, class OP> +auto make_inspect(I &&iter, OP &&op) +{ + // Compiler cant deduce type T. decltype is here to help with it. + return Inspect<decltype(iter.next().take()), I, OP>(std::move(iter), + std::move(op)); +} +} diff --git a/include/utils/iterator/iterator.hpp b/include/utils/iterator/iterator.hpp index fb9d41655..44091046b 100644 --- a/include/utils/iterator/iterator.hpp +++ b/include/utils/iterator/iterator.hpp @@ -3,9 +3,12 @@ #include "utils/iterator/accessor.hpp" #include "utils/iterator/count.hpp" #include "utils/iterator/filter.hpp" +#include "utils/iterator/flat_map.hpp" #include "utils/iterator/for_all.hpp" +#include "utils/iterator/inspect.hpp" #include "utils/iterator/iterator_accessor.hpp" #include "utils/iterator/iterator_base.hpp" #include "utils/iterator/lambda_iterator.hpp" +#include "utils/iterator/limited_map.hpp" #include "utils/iterator/map.hpp" #include "utils/iterator/range_iterator.hpp" diff --git a/include/utils/iterator/iterator_base.hpp b/include/utils/iterator/iterator_base.hpp index b11906673..019aeb5f2 100644 --- a/include/utils/iterator/iterator_base.hpp +++ b/include/utils/iterator/iterator_base.hpp @@ -15,6 +15,15 @@ auto make_filter(I &&iter, OP &&op); template <class I, class C> void for_all(I &&iter, C &&consumer); + +template <class I, class OP> +auto make_flat_map(I &&iter, OP &&op); + +template <class I, class OP> +auto make_inspect(I &&iter, OP &&op); + +template <class I, class OP> +auto make_limited_map(I &&iter, OP &&op); } // Base iterator for next() kind iterator. @@ -43,12 +52,64 @@ public: std::move(*this), std::move(op)); } + // Replaces every item with item taken from n if it exists. + template <class R> + auto replace(Option<R> &n) + { + return iter::make_limited_map<decltype(std::move(*this))>( + std::move(*this), [&](auto v) mutable { return std::move(n); }); + } + // Maps with call to method to() and filters with call to fill. auto to() { return map([](auto er) { return er.to(); }).fill(); } + // Maps with call to method from() and filters with call to fill. + auto from() + { + return map([](auto er) { return er.from(); }).fill(); + } + + // Combines out iterators into one iterator. + auto out() + { + return iter::make_flat_map<decltype(std::move(*this))>( + std::move(*this), [](auto vr) { return vr.out().fill(); }); + } + + // Filters with label on from vertex. + template <class LABEL> + auto from_label(LABEL const &label) + { + return filter([&](auto &ra) { + auto va = ra.from(); + return va.fill() && va.has_label(label); + }); + } + + // Filters with property under given key + template <class KEY, class PROP> + auto has_property(KEY &key, PROP const &prop) + { + return filter([&](auto &va) { return va.at(key) == prop; }); + } + + // Copy-s all pasing value to t before they are returned. + // auto clone_to(Option<T> &t) + // { + // return iter::make_inspect<decltype(std::move(*this))>( + // std::move(*this), [&](auto &v) { t = Option<T>(v); }); + // } + + // Copy-s pasing value to t before they are returned. + auto clone_to(Option<const T> &t) + { + return iter::make_inspect<decltype(std::move(*this))>( + std::move(*this), [&](auto &v) mutable { t = Option<const T>(v); }); + } + // Filters with call to method fill() auto fill() { @@ -62,6 +123,13 @@ public: return filter([&](auto &ra) { return ra.edge_type() == type; }); } + // Filters with label. + template <class LABEL> + auto label(LABEL const &label) + { + return filter([&](auto &va) { return va.has_label(label); }); + } + // Filters out vertices which are connected. auto isolated() { diff --git a/include/utils/iterator/limited_map.hpp b/include/utils/iterator/limited_map.hpp new file mode 100644 index 000000000..83d4402e4 --- /dev/null +++ b/include/utils/iterator/limited_map.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include "utils/iterator/iterator_base.hpp" +#include "utils/option.hpp" + +namespace iter +{ + +// Class which maps values returned by I iterator into value of type T with OP +// function and ends when op return empty optional. +// T - type of return value +// I - iterator type +// OP - type of mapper function. OP: V -> Option<T> +template <class T, class I, class OP> +class LimitedMap : public IteratorBase<T> +{ + +public: + LimitedMap() = delete; + + // LimitedMap operation is designed to be used in chained calls which + // operate on a + // iterator. LimitedMap will in that usecase receive other iterator by value + // and + // std::move is a optimization for it. + LimitedMap(I &&iter, OP &&op) : iter(std::move(iter)), op(std::move(op)) {} + + LimitedMap(LimitedMap &&m) : iter(std::move(m.iter)), op(std::move(m.op)) {} + + ~LimitedMap() final {} + + Option<T> next() final + { + auto item = iter.next(); + if (item.is_present()) { + return op(item.take()); + } else { + return Option<T>(); + } + } + + Count count() final { return iter.count(); } + +private: + I iter; + OP op; +}; + +template <class I, class OP> +auto make_limited_map(I &&iter, OP &&op) +{ + // Compiler cant deduce type T. decltype is here to help with it. + return LimitedMap<decltype(op(iter.next().take()).take()), I, OP>( + std::move(iter), std::move(op)); +} +} diff --git a/src/barrier/barrier.cpp b/src/barrier/barrier.cpp index 3c1702dac..65fc1f710 100644 --- a/src/barrier/barrier.cpp +++ b/src/barrier/barrier.cpp @@ -282,7 +282,7 @@ const Id &VertexAccessor::id() const { return HALF_CALL(id()); } VertexAccessor VertexAccessor::update() const { return CALL(update()); } -bool VertexAccessor::remove() const { return HALF_CALL(remove()); } +void VertexAccessor::remove() const { HALF_CALL(remove()); } const Property &VertexAccessor::at(VertexPropertyFamily &key) const { @@ -372,7 +372,7 @@ const Id &EdgeAccessor::id() const { return HALF_CALL(id()); } EdgeAccessor EdgeAccessor::update() const { return CALL(update()); } -bool EdgeAccessor::remove() const { return HALF_CALL(remove()); } +void EdgeAccessor::remove() const { HALF_CALL(remove()); } const Property &EdgeAccessor::at(EdgePropertyFamily &key) const { diff --git a/src/storage/edge_accessor.cpp b/src/storage/edge_accessor.cpp index 8e5c91e64..15031a9af 100644 --- a/src/storage/edge_accessor.cpp +++ b/src/storage/edge_accessor.cpp @@ -2,24 +2,19 @@ #include "storage/vertex_record.hpp" -bool EdgeAccessor::remove() const +void EdgeAccessor::remove() const { - if (RecordAccessor::remove()) { - auto from_v = from(); - bool f_from = from_v.fill(); - assert(f_from); + RecordAccessor::remove(); + auto from_v = from(); + bool f_from = from_v.fill(); + assert(f_from); - auto to_v = to(); - bool f_to = to_v.fill(); - assert(f_to); + auto to_v = to(); + bool f_to = to_v.fill(); + assert(f_to); - from_v.update().record->data.out.remove(vlist); - to_v.update().record->data.in.remove(vlist); - - return true; - } else { - return false; - } + from_v.update().record->data.out.remove(vlist); + to_v.update().record->data.in.remove(vlist); } void EdgeAccessor::edge_type(const EdgeType &edge_type) diff --git a/src/storage/record_accessor.cpp b/src/storage/record_accessor.cpp index fdbb25a77..3f62e8ad4 100644 --- a/src/storage/record_accessor.cpp +++ b/src/storage/record_accessor.cpp @@ -13,11 +13,11 @@ // } template <class T, class Derived> -bool RecordAccessor<T, Derived>::remove() const +void RecordAccessor<T, Derived>::remove() const { assert(!empty()); - return vlist->remove(record, db.trans); + vlist->remove(record, db.trans); } template class RecordAccessor<TypeGroupEdge, EdgeAccessor>; diff --git a/src/storage/vertex_accessor.cpp b/src/storage/vertex_accessor.cpp index 6b17464ff..06347c24c 100644 --- a/src/storage/vertex_accessor.cpp +++ b/src/storage/vertex_accessor.cpp @@ -48,3 +48,23 @@ bool VertexAccessor::in_contains(VertexAccessor const &other) const { return record->data.in.contains(other.vlist); } + +void VertexAccessor::remove() const +{ + RecordAccessor::remove(); + + for (auto evr : record->data.out) { + auto ea = EdgeAccessor(evr, db); + ea.vlist->remove(db.trans); + auto to_v = ea.to(); + to_v.fill(); + to_v.update().record->data.in.remove(ea.vlist); + } + for (auto evr : record->data.in) { + auto ea = EdgeAccessor(evr, db); + ea.vlist->remove(db.trans); + auto from_v = ea.from(); + from_v.fill(); + from_v.update().record->data.out.remove(ea.vlist); + } +}