[master < T1110] Add merge optimization to expand dynamically during runtime (#1110)
This commit is contained in:
parent
bd1852f407
commit
07dea328d8
@ -129,10 +129,10 @@ query::Graph *SubgraphDbAccessor::getGraph() { return graph_; }
|
||||
|
||||
VertexAccessor SubgraphVertexAccessor::GetVertexAccessor() const { return impl_; }
|
||||
|
||||
auto SubgraphVertexAccessor::OutEdges(storage::View view) const -> decltype(impl_.OutEdges(view)) {
|
||||
storage::Result<EdgeVertexAccessorResult> SubgraphVertexAccessor::OutEdges(storage::View view) const {
|
||||
auto maybe_edges = impl_.impl_.OutEdges(view, {});
|
||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||
auto edges = std::move(*maybe_edges);
|
||||
auto edges = std::move(maybe_edges->edges);
|
||||
const auto &graph_edges = graph_->edges();
|
||||
|
||||
std::vector<storage::EdgeAccessor> filteredOutEdges;
|
||||
@ -143,13 +143,18 @@ auto SubgraphVertexAccessor::OutEdges(storage::View view) const -> decltype(impl
|
||||
}
|
||||
}
|
||||
|
||||
return iter::imap(VertexAccessor::MakeEdgeAccessor, std::move(filteredOutEdges));
|
||||
std::vector<EdgeAccessor> resulting_edges;
|
||||
resulting_edges.reserve(filteredOutEdges.size());
|
||||
std::ranges::transform(filteredOutEdges, std::back_inserter(resulting_edges),
|
||||
[](auto const &edge) { return VertexAccessor::MakeEdgeAccessor(edge); });
|
||||
|
||||
return EdgeVertexAccessorResult{.edges = std::move(resulting_edges), .expanded_count = maybe_edges->expanded_count};
|
||||
}
|
||||
|
||||
auto SubgraphVertexAccessor::InEdges(storage::View view) const -> decltype(impl_.InEdges(view)) {
|
||||
storage::Result<EdgeVertexAccessorResult> SubgraphVertexAccessor::InEdges(storage::View view) const {
|
||||
auto maybe_edges = impl_.impl_.InEdges(view, {});
|
||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||
auto edges = std::move(*maybe_edges);
|
||||
auto edges = std::move(maybe_edges->edges);
|
||||
const auto &graph_edges = graph_->edges();
|
||||
|
||||
std::vector<storage::EdgeAccessor> filteredOutEdges;
|
||||
@ -160,7 +165,12 @@ auto SubgraphVertexAccessor::InEdges(storage::View view) const -> decltype(impl_
|
||||
}
|
||||
}
|
||||
|
||||
return iter::imap(VertexAccessor::MakeEdgeAccessor, std::move(filteredOutEdges));
|
||||
std::vector<EdgeAccessor> resulting_edges;
|
||||
resulting_edges.reserve(filteredOutEdges.size());
|
||||
std::ranges::transform(filteredOutEdges, std::back_inserter(resulting_edges),
|
||||
[](auto const &edge) { return VertexAccessor::MakeEdgeAccessor(edge); });
|
||||
|
||||
return EdgeVertexAccessorResult{.edges = std::move(resulting_edges), .expanded_count = maybe_edges->expanded_count};
|
||||
}
|
||||
|
||||
} // namespace memgraph::query
|
||||
|
@ -105,6 +105,11 @@ class EdgeAccessor final {
|
||||
bool operator!=(const EdgeAccessor &e) const noexcept { return !(*this == e); }
|
||||
};
|
||||
|
||||
struct EdgeVertexAccessorResult {
|
||||
std::vector<EdgeAccessor> edges;
|
||||
int64_t expanded_count;
|
||||
};
|
||||
|
||||
class VertexAccessor final {
|
||||
public:
|
||||
storage::VertexAccessor impl_;
|
||||
@ -153,37 +158,62 @@ class VertexAccessor final {
|
||||
return impl_.ClearProperties();
|
||||
}
|
||||
|
||||
auto InEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types) const
|
||||
-> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> {
|
||||
auto maybe_edges = impl_.InEdges(view, edge_types);
|
||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
|
||||
storage::Result<EdgeVertexAccessorResult> InEdges(storage::View view,
|
||||
const std::vector<storage::EdgeTypeId> &edge_types) const {
|
||||
auto maybe_result = impl_.InEdges(view, edge_types);
|
||||
if (maybe_result.HasError()) return maybe_result.GetError();
|
||||
|
||||
std::vector<EdgeAccessor> edges;
|
||||
edges.reserve((*maybe_result).edges.size());
|
||||
std::ranges::transform((*maybe_result).edges, std::back_inserter(edges),
|
||||
[](auto const &edge) { return EdgeAccessor(edge); });
|
||||
|
||||
return EdgeVertexAccessorResult{.edges = edges, .expanded_count = (*maybe_result).expanded_count};
|
||||
}
|
||||
|
||||
auto InEdges(storage::View view) const { return InEdges(view, {}); }
|
||||
storage::Result<EdgeVertexAccessorResult> InEdges(storage::View view) const { return InEdges(view, {}); }
|
||||
|
||||
auto InEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types, const VertexAccessor &dest) const
|
||||
-> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> {
|
||||
auto maybe_edges = impl_.InEdges(view, edge_types, &dest.impl_);
|
||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
|
||||
storage::Result<EdgeVertexAccessorResult> InEdges(storage::View view,
|
||||
const std::vector<storage::EdgeTypeId> &edge_types,
|
||||
const VertexAccessor &dest) const {
|
||||
auto maybe_result = impl_.InEdges(view, edge_types, &dest.impl_);
|
||||
if (maybe_result.HasError()) return maybe_result.GetError();
|
||||
|
||||
std::vector<EdgeAccessor> edges;
|
||||
edges.reserve((*maybe_result).edges.size());
|
||||
std::ranges::transform((*maybe_result).edges, std::back_inserter(edges),
|
||||
[](auto const &edge) { return EdgeAccessor(edge); });
|
||||
|
||||
return EdgeVertexAccessorResult{.edges = edges, .expanded_count = (*maybe_result).expanded_count};
|
||||
}
|
||||
|
||||
auto OutEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types) const
|
||||
-> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
|
||||
auto maybe_edges = impl_.OutEdges(view, edge_types);
|
||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
|
||||
storage::Result<EdgeVertexAccessorResult> OutEdges(storage::View view,
|
||||
const std::vector<storage::EdgeTypeId> &edge_types) const {
|
||||
auto maybe_result = impl_.OutEdges(view, edge_types);
|
||||
if (maybe_result.HasError()) return maybe_result.GetError();
|
||||
|
||||
std::vector<EdgeAccessor> edges;
|
||||
edges.reserve((*maybe_result).edges.size());
|
||||
std::ranges::transform((*maybe_result).edges, std::back_inserter(edges),
|
||||
[](auto const &edge) { return EdgeAccessor(edge); });
|
||||
|
||||
return EdgeVertexAccessorResult{.edges = edges, .expanded_count = (*maybe_result).expanded_count};
|
||||
}
|
||||
|
||||
auto OutEdges(storage::View view) const { return OutEdges(view, {}); }
|
||||
storage::Result<EdgeVertexAccessorResult> OutEdges(storage::View view) const { return OutEdges(view, {}); }
|
||||
|
||||
auto OutEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types,
|
||||
const VertexAccessor &dest) const
|
||||
-> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
|
||||
auto maybe_edges = impl_.OutEdges(view, edge_types, &dest.impl_);
|
||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
|
||||
storage::Result<EdgeVertexAccessorResult> OutEdges(storage::View view,
|
||||
const std::vector<storage::EdgeTypeId> &edge_types,
|
||||
const VertexAccessor &dest) const {
|
||||
auto maybe_result = impl_.OutEdges(view, edge_types, &dest.impl_);
|
||||
if (maybe_result.HasError()) return maybe_result.GetError();
|
||||
|
||||
std::vector<EdgeAccessor> edges;
|
||||
edges.reserve((*maybe_result).edges.size());
|
||||
std::ranges::transform((*maybe_result).edges, std::back_inserter(edges),
|
||||
[](auto const &edge) { return EdgeAccessor(edge); });
|
||||
|
||||
return EdgeVertexAccessorResult{.edges = edges, .expanded_count = (*maybe_result).expanded_count};
|
||||
}
|
||||
|
||||
storage::Result<size_t> InDegree(storage::View view) const { return impl_.InDegree(view); }
|
||||
@ -260,7 +290,6 @@ class SubgraphVertexAccessor final {
|
||||
} // namespace memgraph::query
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash<memgraph::query::VertexAccessor> {
|
||||
size_t operator()(const memgraph::query::VertexAccessor &v) const { return std::hash<decltype(v.impl_)>{}(v.impl_); }
|
||||
|
@ -487,8 +487,8 @@ PullPlanDump::PullChunk PullPlanDump::CreateEdgePullChunk() {
|
||||
}
|
||||
auto &maybe_edges = *maybe_edge_iterable;
|
||||
MG_ASSERT(maybe_edges.HasValue(), "Invalid database state!");
|
||||
auto current_edge_iter = maybe_current_edge_iter ? *maybe_current_edge_iter : maybe_edges->begin();
|
||||
for (; current_edge_iter != maybe_edges->end() && (!n || local_counter < *n); ++current_edge_iter) {
|
||||
auto current_edge_iter = maybe_current_edge_iter ? *maybe_current_edge_iter : maybe_edges->edges.begin();
|
||||
for (; current_edge_iter != maybe_edges->edges.end() && (!n || local_counter < *n); ++current_edge_iter) {
|
||||
std::ostringstream os;
|
||||
DumpEdge(&os, dba_, *current_edge_iter);
|
||||
stream->Result({TypedValue(os.str())});
|
||||
@ -496,7 +496,7 @@ PullPlanDump::PullChunk PullPlanDump::CreateEdgePullChunk() {
|
||||
++local_counter;
|
||||
}
|
||||
|
||||
if (current_edge_iter != maybe_edges->end()) {
|
||||
if (current_edge_iter != maybe_edges->edges.end()) {
|
||||
maybe_current_edge_iter.emplace(current_edge_iter);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@ -38,7 +38,7 @@ struct PullPlanDump {
|
||||
using VertexAccessorIterableIterator = decltype(std::declval<VertexAccessorIterable>().begin());
|
||||
|
||||
using EdgeAccessorIterable = decltype(std::declval<VertexAccessor>().OutEdges(storage::View::OLD));
|
||||
using EdgeAccessorIterableIterator = decltype(std::declval<EdgeAccessorIterable>().GetValue().begin());
|
||||
using EdgeAccessorIterableIterator = decltype(std::declval<EdgeAccessorIterable>().GetValue().edges.begin());
|
||||
|
||||
VertexAccessorIterable vertices_iterable_;
|
||||
bool internal_index_created_ = false;
|
||||
|
@ -680,8 +680,8 @@ bool CheckExistingNode(const VertexAccessor &new_node, const Symbol &existing_no
|
||||
return existing_node.ValueVertex() == new_node;
|
||||
}
|
||||
|
||||
template <class TEdges>
|
||||
auto UnwrapEdgesResult(storage::Result<TEdges> &&result) {
|
||||
template <class TEdgesResult>
|
||||
auto UnwrapEdgesResult(storage::Result<TEdgesResult> &&result) {
|
||||
if (result.HasError()) {
|
||||
switch (result.GetError()) {
|
||||
case storage::Error::DELETED_OBJECT:
|
||||
@ -725,6 +725,13 @@ std::vector<Symbol> Expand::ModifiedSymbols(const SymbolTable &table) const {
|
||||
Expand::ExpandCursor::ExpandCursor(const Expand &self, utils::MemoryResource *mem)
|
||||
: self_(self), input_cursor_(self.input_->MakeCursor(mem)) {}
|
||||
|
||||
Expand::ExpandCursor::ExpandCursor(const Expand &self, int64_t input_degree, int64_t existing_node_degree,
|
||||
utils::MemoryResource *mem)
|
||||
: self_(self),
|
||||
input_cursor_(self.input_->MakeCursor(mem)),
|
||||
prev_input_degree_(input_degree),
|
||||
prev_existing_degree_(existing_node_degree) {}
|
||||
|
||||
bool Expand::ExpandCursor::Pull(Frame &frame, ExecutionContext &context) {
|
||||
SCOPED_PROFILE_OP("Expand");
|
||||
|
||||
@ -800,58 +807,131 @@ void Expand::ExpandCursor::Reset() {
|
||||
out_edges_it_ = std::nullopt;
|
||||
}
|
||||
|
||||
ExpansionInfo Expand::ExpandCursor::GetExpansionInfo(Frame &frame) {
|
||||
TypedValue &vertex_value = frame[self_.input_symbol_];
|
||||
|
||||
if (vertex_value.IsNull()) {
|
||||
return ExpansionInfo{};
|
||||
}
|
||||
|
||||
ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex);
|
||||
auto &vertex = vertex_value.ValueVertex();
|
||||
|
||||
auto direction = self_.common_.direction;
|
||||
if (!self_.common_.existing_node) {
|
||||
return ExpansionInfo{.input_node = vertex, .direction = direction};
|
||||
}
|
||||
|
||||
TypedValue &existing_node = frame[self_.common_.node_symbol];
|
||||
|
||||
if (existing_node.IsNull()) {
|
||||
return ExpansionInfo{.input_node = vertex, .direction = direction};
|
||||
}
|
||||
|
||||
ExpectType(self_.common_.node_symbol, existing_node, TypedValue::Type::Vertex);
|
||||
|
||||
auto &existing_vertex = existing_node.ValueVertex();
|
||||
|
||||
// -1 and -1 -> normal expansion
|
||||
// -1 and expanded -> can't happen
|
||||
// expanded and -1 -> reverse
|
||||
// expanded and expanded -> see if can reverse
|
||||
if ((prev_input_degree_ == -1 && prev_existing_degree_ == -1) || prev_input_degree_ < prev_existing_degree_) {
|
||||
return ExpansionInfo{.input_node = vertex, .direction = direction, .existing_node = existing_vertex};
|
||||
}
|
||||
|
||||
auto new_direction = direction;
|
||||
switch (new_direction) {
|
||||
case EdgeAtom::Direction::IN:
|
||||
new_direction = EdgeAtom::Direction::OUT;
|
||||
break;
|
||||
case EdgeAtom::Direction::OUT:
|
||||
new_direction = EdgeAtom::Direction::IN;
|
||||
break;
|
||||
default:
|
||||
new_direction = EdgeAtom::Direction::BOTH;
|
||||
break;
|
||||
}
|
||||
|
||||
return ExpansionInfo{
|
||||
.input_node = existing_vertex, .direction = new_direction, .existing_node = vertex, .reversed = true};
|
||||
}
|
||||
|
||||
bool Expand::ExpandCursor::InitEdges(Frame &frame, ExecutionContext &context) {
|
||||
// Input Vertex could be null if it is created by a failed optional match. In
|
||||
// those cases we skip that input pull and continue with the next.
|
||||
while (true) {
|
||||
if (!input_cursor_->Pull(frame, context)) return false;
|
||||
TypedValue &vertex_value = frame[self_.input_symbol_];
|
||||
|
||||
// Null check due to possible failed optional match.
|
||||
if (vertex_value.IsNull()) continue;
|
||||
expansion_info_ = GetExpansionInfo(frame);
|
||||
|
||||
ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex);
|
||||
auto &vertex = vertex_value.ValueVertex();
|
||||
if (!expansion_info_.input_node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto direction = self_.common_.direction;
|
||||
auto vertex = *expansion_info_.input_node;
|
||||
auto direction = expansion_info_.direction;
|
||||
|
||||
int64_t num_expanded_first = -1;
|
||||
if (direction == EdgeAtom::Direction::IN || direction == EdgeAtom::Direction::BOTH) {
|
||||
if (self_.common_.existing_node) {
|
||||
TypedValue &existing_node = frame[self_.common_.node_symbol];
|
||||
// old_node_value may be Null when using optional matching
|
||||
if (!existing_node.IsNull()) {
|
||||
ExpectType(self_.common_.node_symbol, existing_node, TypedValue::Type::Vertex);
|
||||
if (expansion_info_.existing_node) {
|
||||
auto existing_node = *expansion_info_.existing_node;
|
||||
context.db_accessor->PrefetchInEdges(vertex);
|
||||
in_edges_.emplace(
|
||||
UnwrapEdgesResult(vertex.InEdges(self_.view_, self_.common_.edge_types, existing_node.ValueVertex())));
|
||||
|
||||
auto edges_result = UnwrapEdgesResult(vertex.InEdges(self_.view_, self_.common_.edge_types, existing_node));
|
||||
in_edges_.emplace(edges_result.edges);
|
||||
num_expanded_first = edges_result.expanded_count;
|
||||
}
|
||||
} else {
|
||||
context.db_accessor->PrefetchInEdges(vertex);
|
||||
in_edges_.emplace(UnwrapEdgesResult(vertex.InEdges(self_.view_, self_.common_.edge_types)));
|
||||
|
||||
auto edges_result = UnwrapEdgesResult(vertex.InEdges(self_.view_, self_.common_.edge_types));
|
||||
in_edges_.emplace(edges_result.edges);
|
||||
num_expanded_first = edges_result.expanded_count;
|
||||
}
|
||||
if (in_edges_) {
|
||||
in_edges_it_.emplace(in_edges_->begin());
|
||||
}
|
||||
}
|
||||
|
||||
int64_t num_expanded_second = -1;
|
||||
if (direction == EdgeAtom::Direction::OUT || direction == EdgeAtom::Direction::BOTH) {
|
||||
if (self_.common_.existing_node) {
|
||||
TypedValue &existing_node = frame[self_.common_.node_symbol];
|
||||
// old_node_value may be Null when using optional matching
|
||||
if (!existing_node.IsNull()) {
|
||||
ExpectType(self_.common_.node_symbol, existing_node, TypedValue::Type::Vertex);
|
||||
if (expansion_info_.existing_node) {
|
||||
auto existing_node = *expansion_info_.existing_node;
|
||||
context.db_accessor->PrefetchOutEdges(vertex);
|
||||
out_edges_.emplace(
|
||||
UnwrapEdgesResult(vertex.OutEdges(self_.view_, self_.common_.edge_types, existing_node.ValueVertex())));
|
||||
|
||||
auto edges_result = UnwrapEdgesResult(vertex.OutEdges(self_.view_, self_.common_.edge_types, existing_node));
|
||||
out_edges_.emplace(edges_result.edges);
|
||||
num_expanded_second = edges_result.expanded_count;
|
||||
}
|
||||
} else {
|
||||
context.db_accessor->PrefetchOutEdges(vertex);
|
||||
out_edges_.emplace(UnwrapEdgesResult(vertex.OutEdges(self_.view_, self_.common_.edge_types)));
|
||||
|
||||
auto edges_result = UnwrapEdgesResult(vertex.OutEdges(self_.view_, self_.common_.edge_types));
|
||||
out_edges_.emplace(edges_result.edges);
|
||||
num_expanded_second = edges_result.expanded_count;
|
||||
}
|
||||
if (out_edges_) {
|
||||
out_edges_it_.emplace(out_edges_->begin());
|
||||
}
|
||||
}
|
||||
|
||||
if (!expansion_info_.existing_node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
num_expanded_first = num_expanded_first == -1 ? 0 : num_expanded_first;
|
||||
num_expanded_second = num_expanded_second == -1 ? 0 : num_expanded_second;
|
||||
int64_t total_expanded_edges = num_expanded_first + num_expanded_second;
|
||||
|
||||
if (!expansion_info_.reversed) {
|
||||
prev_input_degree_ = total_expanded_edges;
|
||||
} else {
|
||||
prev_existing_degree_ = total_expanded_edges;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -911,11 +991,12 @@ auto ExpandFromVertex(const VertexAccessor &vertex, EdgeAtom::Direction directio
|
||||
};
|
||||
|
||||
storage::View view = storage::View::OLD;
|
||||
utils::pmr::vector<decltype(wrapper(direction, *vertex.InEdges(view, edge_types)))> chain_elements(memory);
|
||||
utils::pmr::vector<decltype(wrapper(direction, vertex.InEdges(view, edge_types).GetValue().edges))> chain_elements(
|
||||
memory);
|
||||
|
||||
if (direction != EdgeAtom::Direction::OUT) {
|
||||
db_accessor->PrefetchInEdges(vertex);
|
||||
auto edges = UnwrapEdgesResult(vertex.InEdges(view, edge_types));
|
||||
auto edges = UnwrapEdgesResult(vertex.InEdges(view, edge_types)).edges;
|
||||
if (edges.begin() != edges.end()) {
|
||||
chain_elements.emplace_back(wrapper(EdgeAtom::Direction::IN, std::move(edges)));
|
||||
}
|
||||
@ -923,7 +1004,7 @@ auto ExpandFromVertex(const VertexAccessor &vertex, EdgeAtom::Direction directio
|
||||
|
||||
if (direction != EdgeAtom::Direction::IN) {
|
||||
db_accessor->PrefetchOutEdges(vertex);
|
||||
auto edges = UnwrapEdgesResult(vertex.OutEdges(view, edge_types));
|
||||
auto edges = UnwrapEdgesResult(vertex.OutEdges(view, edge_types)).edges;
|
||||
if (edges.begin() != edges.end()) {
|
||||
chain_elements.emplace_back(wrapper(EdgeAtom::Direction::OUT, std::move(edges)));
|
||||
}
|
||||
@ -1283,7 +1364,7 @@ class STShortestPathCursor : public query::plan::Cursor {
|
||||
for (const auto &vertex : source_frontier) {
|
||||
if (self_.common_.direction != EdgeAtom::Direction::IN) {
|
||||
context.db_accessor->PrefetchOutEdges(vertex);
|
||||
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
|
||||
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)).edges;
|
||||
for (const auto &edge : out_edges) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (license::global_license_checker.IsEnterpriseValidFast() && context.auth_checker &&
|
||||
@ -1310,7 +1391,7 @@ class STShortestPathCursor : public query::plan::Cursor {
|
||||
}
|
||||
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
|
||||
dba.PrefetchInEdges(vertex);
|
||||
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
|
||||
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types)).edges;
|
||||
for (const auto &edge : in_edges) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (license::global_license_checker.IsEnterpriseValidFast() && context.auth_checker &&
|
||||
@ -1351,7 +1432,7 @@ class STShortestPathCursor : public query::plan::Cursor {
|
||||
for (const auto &vertex : sink_frontier) {
|
||||
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
|
||||
context.db_accessor->PrefetchOutEdges(vertex);
|
||||
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
|
||||
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)).edges;
|
||||
for (const auto &edge : out_edges) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (license::global_license_checker.IsEnterpriseValidFast() && context.auth_checker &&
|
||||
@ -1377,7 +1458,7 @@ class STShortestPathCursor : public query::plan::Cursor {
|
||||
}
|
||||
if (self_.common_.direction != EdgeAtom::Direction::IN) {
|
||||
dba.PrefetchInEdges(vertex);
|
||||
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
|
||||
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types)).edges;
|
||||
for (const auto &edge : in_edges) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (license::global_license_checker.IsEnterpriseValidFast() && context.auth_checker &&
|
||||
@ -1469,12 +1550,12 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
|
||||
auto expand_from_vertex = [this, &expand_pair, &context](const auto &vertex) {
|
||||
if (self_.common_.direction != EdgeAtom::Direction::IN) {
|
||||
context.db_accessor->PrefetchOutEdges(vertex);
|
||||
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
|
||||
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)).edges;
|
||||
for (const auto &edge : out_edges) expand_pair(edge, edge.To());
|
||||
}
|
||||
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
|
||||
context.db_accessor->PrefetchInEdges(vertex);
|
||||
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
|
||||
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types)).edges;
|
||||
for (const auto &edge : in_edges) expand_pair(edge, edge.From());
|
||||
}
|
||||
};
|
||||
@ -1672,14 +1753,14 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
|
||||
int64_t depth) {
|
||||
if (self_.common_.direction != EdgeAtom::Direction::IN) {
|
||||
context.db_accessor->PrefetchOutEdges(vertex);
|
||||
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
|
||||
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)).edges;
|
||||
for (const auto &edge : out_edges) {
|
||||
expand_pair(edge, edge.To(), weight, depth);
|
||||
}
|
||||
}
|
||||
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
|
||||
context.db_accessor->PrefetchInEdges(vertex);
|
||||
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
|
||||
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types)).edges;
|
||||
for (const auto &edge : in_edges) {
|
||||
expand_pair(edge, edge.From(), weight, depth);
|
||||
}
|
||||
@ -1938,7 +2019,7 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
|
||||
int64_t depth) {
|
||||
if (self_.common_.direction != EdgeAtom::Direction::IN) {
|
||||
context.db_accessor->PrefetchOutEdges(vertex);
|
||||
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
|
||||
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)).edges;
|
||||
for (const auto &edge : out_edges) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (license::global_license_checker.IsEnterpriseValidFast() && context.auth_checker &&
|
||||
@ -1953,7 +2034,7 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
|
||||
}
|
||||
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
|
||||
context.db_accessor->PrefetchInEdges(vertex);
|
||||
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
|
||||
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types)).edges;
|
||||
for (const auto &edge : in_edges) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (license::global_license_checker.IsEnterpriseValidFast() && context.auth_checker &&
|
||||
|
@ -764,6 +764,13 @@ struct ExpandCommon {
|
||||
bool existing_node;
|
||||
};
|
||||
|
||||
struct ExpansionInfo {
|
||||
std::optional<VertexAccessor> input_node;
|
||||
EdgeAtom::Direction direction;
|
||||
std::optional<VertexAccessor> existing_node;
|
||||
bool reversed{false};
|
||||
};
|
||||
|
||||
/// Expansion operator. For a node existing in the frame it
|
||||
/// expands one edge and one node and places them on the frame.
|
||||
///
|
||||
@ -806,14 +813,16 @@ class Expand : public memgraph::query::plan::LogicalOperator {
|
||||
class ExpandCursor : public Cursor {
|
||||
public:
|
||||
ExpandCursor(const Expand &, utils::MemoryResource *);
|
||||
ExpandCursor(const Expand &, int64_t input_degree, int64_t existing_node_degree, utils::MemoryResource *);
|
||||
bool Pull(Frame &, ExecutionContext &) override;
|
||||
void Shutdown() override;
|
||||
void Reset() override;
|
||||
ExpansionInfo GetExpansionInfo(Frame &);
|
||||
|
||||
private:
|
||||
using InEdgeT = std::remove_reference_t<decltype(*std::declval<VertexAccessor>().InEdges(storage::View::OLD))>;
|
||||
using InEdgeT = std::vector<EdgeAccessor>;
|
||||
using InEdgeIteratorT = decltype(std::declval<InEdgeT>().begin());
|
||||
using OutEdgeT = std::remove_reference_t<decltype(*std::declval<VertexAccessor>().OutEdges(storage::View::OLD))>;
|
||||
using OutEdgeT = std::vector<EdgeAccessor>;
|
||||
using OutEdgeIteratorT = decltype(std::declval<OutEdgeT>().begin());
|
||||
|
||||
const Expand &self_;
|
||||
@ -826,6 +835,9 @@ class Expand : public memgraph::query::plan::LogicalOperator {
|
||||
std::optional<InEdgeIteratorT> in_edges_it_;
|
||||
std::optional<OutEdgeT> out_edges_;
|
||||
std::optional<OutEdgeIteratorT> out_edges_it_;
|
||||
ExpansionInfo expansion_info_;
|
||||
int64_t prev_input_degree_{-1};
|
||||
int64_t prev_existing_degree_{-1};
|
||||
|
||||
bool InitEdges(Frame &, ExecutionContext &);
|
||||
};
|
||||
|
@ -2120,7 +2120,7 @@ mgp_error mgp_vertex_iter_in_edges(mgp_vertex *v, mgp_memory *memory, mgp_edges_
|
||||
LOG_FATAL("Unexpected error when getting the inbound edges of a vertex.");
|
||||
}
|
||||
}
|
||||
it->in.emplace(std::move(*maybe_edges));
|
||||
it->in.emplace(std::move(maybe_edges->edges));
|
||||
it->in_it.emplace(it->in->begin());
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
@ -2180,7 +2180,7 @@ mgp_error mgp_vertex_iter_out_edges(mgp_vertex *v, mgp_memory *memory, mgp_edges
|
||||
}
|
||||
}
|
||||
|
||||
it->out.emplace(std::move(*maybe_edges));
|
||||
it->out.emplace(std::move(maybe_edges->edges));
|
||||
it->out_it.emplace(it->out->begin());
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
|
@ -687,12 +687,14 @@ struct mgp_edges_iterator {
|
||||
memgraph::utils::MemoryResource *memory;
|
||||
mgp_vertex source_vertex;
|
||||
|
||||
std::optional<std::remove_reference_t<
|
||||
decltype(*std::get<memgraph::query::VertexAccessor>(source_vertex.impl).InEdges(source_vertex.graph->view))>>
|
||||
std::optional<std::remove_reference_t<decltype(std::get<memgraph::query::VertexAccessor>(source_vertex.impl)
|
||||
.InEdges(source_vertex.graph->view)
|
||||
->edges)>>
|
||||
in;
|
||||
std::optional<decltype(in->begin())> in_it;
|
||||
std::optional<std::remove_reference_t<
|
||||
decltype(*std::get<memgraph::query::VertexAccessor>(source_vertex.impl).OutEdges(source_vertex.graph->view))>>
|
||||
std::optional<std::remove_reference_t<decltype(std::get<memgraph::query::VertexAccessor>(source_vertex.impl)
|
||||
.OutEdges(source_vertex.graph->view)
|
||||
->edges)>>
|
||||
out;
|
||||
std::optional<decltype(out->begin())> out_it;
|
||||
std::optional<mgp_edge> current_e;
|
||||
|
@ -306,7 +306,7 @@ void TriggerContext::AdaptForAccessor(DbAccessor *accessor) {
|
||||
auto maybe_out_edges = maybe_from_vertex->OutEdges(storage::View::OLD);
|
||||
MG_ASSERT(maybe_out_edges.HasValue());
|
||||
const auto edge_gid = created_edge.object.Gid();
|
||||
for (const auto &edge : *maybe_out_edges) {
|
||||
for (const auto &edge : maybe_out_edges->edges) {
|
||||
if (edge.Gid() == edge_gid) {
|
||||
*it = detail::CreatedObject{edge};
|
||||
++it;
|
||||
@ -327,7 +327,7 @@ void TriggerContext::AdaptForAccessor(DbAccessor *accessor) {
|
||||
accessor->PrefetchOutEdges(*maybe_vertex);
|
||||
auto maybe_out_edges = maybe_vertex->OutEdges(storage::View::OLD);
|
||||
MG_ASSERT(maybe_out_edges.HasValue());
|
||||
for (const auto &edge : *maybe_out_edges) {
|
||||
for (const auto &edge : maybe_out_edges->edges) {
|
||||
if (edge.Gid() == value.object.Gid()) {
|
||||
*it = std::move(value);
|
||||
it->object = edge;
|
||||
|
@ -1178,10 +1178,10 @@ bool DiskStorage::DiskAccessor::PrefetchEdgeFilter(const std::string_view disk_e
|
||||
}
|
||||
|
||||
MG_ASSERT(edges_res.HasValue());
|
||||
auto edges = edges_res.GetValue();
|
||||
bool isEdgeAlreadyInMemory = std::any_of(edges.begin(), edges.end(), [edge_gid](const auto &edge_acc) {
|
||||
return utils::SerializeIdType(edge_acc.Gid()) == edge_gid;
|
||||
});
|
||||
auto edges_result = edges_res.GetValue();
|
||||
bool isEdgeAlreadyInMemory =
|
||||
std::any_of(edges_result.edges.begin(), edges_result.edges.end(),
|
||||
[edge_gid](const auto &edge_acc) { return utils::SerializeIdType(edge_acc.Gid()) == edge_gid; });
|
||||
|
||||
return !isEdgeAlreadyInMemory;
|
||||
}
|
||||
|
@ -1533,14 +1533,14 @@ void CreateSnapshot(Transaction *transaction, const std::filesystem::path &snaps
|
||||
write_mapping(item.first);
|
||||
snapshot.WritePropertyValue(item.second);
|
||||
}
|
||||
const auto &in_edges = maybe_in_edges.GetValue();
|
||||
const auto &in_edges = maybe_in_edges.GetValue().edges;
|
||||
snapshot.WriteUint(in_edges.size());
|
||||
for (const auto &item : in_edges) {
|
||||
snapshot.WriteUint(item.Gid().AsUint());
|
||||
snapshot.WriteUint(item.FromVertex().Gid().AsUint());
|
||||
write_mapping(item.EdgeType());
|
||||
}
|
||||
const auto &out_edges = maybe_out_edges.GetValue();
|
||||
const auto &out_edges = maybe_out_edges.GetValue().edges;
|
||||
snapshot.WriteUint(out_edges.size());
|
||||
for (const auto &item : out_edges) {
|
||||
snapshot.WriteUint(item.Gid().AsUint());
|
||||
|
@ -388,8 +388,8 @@ uint64_t InMemoryReplicationServer::ReadAndApplyDelta(InMemoryStorage *storage,
|
||||
auto edges = from_vertex->OutEdges(View::NEW, {transaction->NameToEdgeType(delta.edge_create_delete.edge_type)},
|
||||
&*to_vertex);
|
||||
if (edges.HasError()) throw utils::BasicException("Invalid transaction!");
|
||||
if (edges->size() != 1) throw utils::BasicException("Invalid transaction!");
|
||||
auto &edge = (*edges)[0];
|
||||
if (edges->edges.size() != 1) throw utils::BasicException("Invalid transaction!");
|
||||
auto &edge = (*edges).edges[0];
|
||||
auto ret = transaction->DeleteEdge(&edge);
|
||||
if (ret.HasError()) throw utils::BasicException("Invalid transaction!");
|
||||
break;
|
||||
|
@ -423,7 +423,7 @@ Result<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(View view
|
||||
return std::move(properties);
|
||||
}
|
||||
|
||||
Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const std::vector<EdgeTypeId> &edge_types,
|
||||
Result<EdgesVertexAccessorResult> VertexAccessor::InEdges(View view, const std::vector<EdgeTypeId> &edge_types,
|
||||
const VertexAccessor *destination) const {
|
||||
MG_ASSERT(!destination || destination->transaction_ == transaction_, "Invalid accessor!");
|
||||
|
||||
@ -445,9 +445,11 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const std::
|
||||
bool deleted = false;
|
||||
auto in_edges = edge_store{};
|
||||
Delta *delta = nullptr;
|
||||
int64_t expanded_count = 0;
|
||||
{
|
||||
auto guard = std::shared_lock{vertex_->lock};
|
||||
deleted = vertex_->deleted;
|
||||
expanded_count = static_cast<int64_t>(vertex_->in_edges.size());
|
||||
// TODO: a better filter copy
|
||||
if (edge_types.empty() && !destination) {
|
||||
in_edges = vertex_->in_edges;
|
||||
@ -472,7 +474,7 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const std::
|
||||
auto const &cache = transaction_->manyDeltasCache;
|
||||
if (auto resError = HasError(view, cache, vertex_, for_deleted_); resError) return *resError;
|
||||
if (auto resInEdges = cache.GetInEdges(view, vertex_, destination_vertex, edge_types); resInEdges)
|
||||
return {build_result(*resInEdges)};
|
||||
return EdgesVertexAccessorResult{.edges = build_result(*resInEdges), .expanded_count = expanded_count};
|
||||
}
|
||||
|
||||
auto const n_processed = ApplyDeltasForRead(
|
||||
@ -497,10 +499,11 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const std::
|
||||
|
||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
||||
if (deleted) return Error::DELETED_OBJECT;
|
||||
return build_result(in_edges);
|
||||
|
||||
return EdgesVertexAccessorResult{.edges = build_result(in_edges), .expanded_count = expanded_count};
|
||||
}
|
||||
|
||||
Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const std::vector<EdgeTypeId> &edge_types,
|
||||
Result<EdgesVertexAccessorResult> VertexAccessor::OutEdges(View view, const std::vector<EdgeTypeId> &edge_types,
|
||||
const VertexAccessor *destination) const {
|
||||
MG_ASSERT(!destination || destination->transaction_ == transaction_, "Invalid accessor!");
|
||||
|
||||
@ -521,9 +524,11 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const std:
|
||||
bool deleted = false;
|
||||
auto out_edges = edge_store{};
|
||||
Delta *delta = nullptr;
|
||||
int64_t expanded_count = 0;
|
||||
{
|
||||
auto guard = std::shared_lock{vertex_->lock};
|
||||
deleted = vertex_->deleted;
|
||||
expanded_count = static_cast<int64_t>(vertex_->out_edges.size());
|
||||
if (edge_types.empty() && !destination) {
|
||||
out_edges = vertex_->out_edges;
|
||||
} else {
|
||||
@ -547,7 +552,7 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const std:
|
||||
auto const &cache = transaction_->manyDeltasCache;
|
||||
if (auto resError = HasError(view, cache, vertex_, for_deleted_); resError) return *resError;
|
||||
if (auto resOutEdges = cache.GetOutEdges(view, vertex_, dst_vertex, edge_types); resOutEdges)
|
||||
return {build_result(*resOutEdges)};
|
||||
return EdgesVertexAccessorResult{.edges = build_result(*resOutEdges), .expanded_count = expanded_count};
|
||||
}
|
||||
|
||||
auto const n_processed = ApplyDeltasForRead(
|
||||
@ -571,7 +576,8 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const std:
|
||||
|
||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
||||
if (deleted) return Error::DELETED_OBJECT;
|
||||
return build_result(out_edges);
|
||||
|
||||
return EdgesVertexAccessorResult{.edges = build_result(out_edges), .expanded_count = expanded_count};
|
||||
}
|
||||
|
||||
Result<size_t> VertexAccessor::InDegree(View view) const {
|
||||
|
@ -26,6 +26,7 @@ class EdgeAccessor;
|
||||
class Storage;
|
||||
struct Constraints;
|
||||
struct Indices;
|
||||
struct EdgesVertexAccessorResult;
|
||||
|
||||
class VertexAccessor final {
|
||||
private:
|
||||
@ -89,13 +90,13 @@ class VertexAccessor final {
|
||||
/// @throw std::bad_alloc
|
||||
/// @throw std::length_error if the resulting vector exceeds
|
||||
/// std::vector::max_size().
|
||||
Result<std::vector<EdgeAccessor>> InEdges(View view, const std::vector<EdgeTypeId> &edge_types = {},
|
||||
Result<EdgesVertexAccessorResult> InEdges(View view, const std::vector<EdgeTypeId> &edge_types = {},
|
||||
const VertexAccessor *destination = nullptr) const;
|
||||
|
||||
/// @throw std::bad_alloc
|
||||
/// @throw std::length_error if the resulting vector exceeds
|
||||
/// std::vector::max_size().
|
||||
Result<std::vector<EdgeAccessor>> OutEdges(View view, const std::vector<EdgeTypeId> &edge_types = {},
|
||||
Result<EdgesVertexAccessorResult> OutEdges(View view, const std::vector<EdgeTypeId> &edge_types = {},
|
||||
const VertexAccessor *destination = nullptr) const;
|
||||
|
||||
Result<size_t> InDegree(View view) const;
|
||||
@ -125,6 +126,11 @@ class VertexAccessor final {
|
||||
bool for_deleted_{false};
|
||||
};
|
||||
|
||||
struct EdgesVertexAccessorResult {
|
||||
std::vector<EdgeAccessor> edges;
|
||||
int64_t expanded_count;
|
||||
};
|
||||
|
||||
} // namespace memgraph::storage
|
||||
|
||||
namespace std {
|
||||
|
@ -71,7 +71,7 @@ RC_GTEST_PROP(RandomGraph, RandomGraph, (std::vector<std::string> vertex_labels,
|
||||
vertices_num_check++;
|
||||
auto maybe_edges = vertex.OutEdges(memgraph::storage::View::OLD);
|
||||
RC_ASSERT(maybe_edges.HasValue());
|
||||
for (auto &edge : *maybe_edges) {
|
||||
for (auto &edge : maybe_edges->edges) {
|
||||
const auto &type = edge_type_map.at(edge);
|
||||
RC_ASSERT(dba->EdgeTypeToName(edge.EdgeType()) == type);
|
||||
edges_num_check++;
|
||||
|
@ -131,7 +131,7 @@ TEST_F(ClearingOldDiskDataTest, TestNumOfEntriesWithEdgeTimestampUpdate) {
|
||||
|
||||
acc2->PrefetchOutEdges(from_vertex);
|
||||
auto ret = from_vertex.OutEdges(memgraph::storage::View::NEW);
|
||||
auto fetched_edge = ret.GetValue()[0];
|
||||
auto fetched_edge = ret.GetValue().edges[0];
|
||||
|
||||
/// This is the same property as in the first transaction, we just want to test
|
||||
/// the number of entries inside RocksDB when the timestamp changes
|
||||
@ -171,7 +171,7 @@ TEST_F(ClearingOldDiskDataTest, TestNumOfEntriesWithEdgeValueUpdate) {
|
||||
|
||||
acc2->PrefetchOutEdges(from_vertex);
|
||||
auto ret = from_vertex.OutEdges(memgraph::storage::View::NEW);
|
||||
auto fetched_edge = ret.GetValue()[0];
|
||||
auto fetched_edge = ret.GetValue().edges[0];
|
||||
|
||||
auto property2 = acc2->NameToProperty("DiskProperty");
|
||||
ASSERT_TRUE(fetched_edge.SetProperty(property2, memgraph::storage::PropertyValue(15)).HasValue());
|
||||
|
@ -158,7 +158,7 @@ DatabaseState GetState(memgraph::storage::Storage *db) {
|
||||
for (const auto &vertex : dba->Vertices(memgraph::storage::View::NEW)) {
|
||||
auto maybe_edges = vertex.OutEdges(memgraph::storage::View::NEW);
|
||||
MG_ASSERT(maybe_edges.HasValue());
|
||||
for (const auto &edge : *maybe_edges) {
|
||||
for (const auto &edge : maybe_edges->edges) {
|
||||
const auto &edge_type_name = dba->EdgeTypeToName(edge.EdgeType());
|
||||
std::map<std::string, memgraph::storage::PropertyValue> props;
|
||||
auto maybe_properties = edge.Properties(memgraph::storage::View::NEW);
|
||||
|
@ -224,7 +224,7 @@ inline uint64_t CountEdges(memgraph::query::DbAccessor *dba, memgraph::storage::
|
||||
dba->PrefetchOutEdges(vertex);
|
||||
auto maybe_edges = vertex.OutEdges(view);
|
||||
MG_ASSERT(maybe_edges.HasValue());
|
||||
count += CountIterable(*maybe_edges);
|
||||
count += CountIterable(maybe_edges->edges);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ TYPED_TEST(QueryPlanTest, CreateExpand) {
|
||||
dba.PrefetchOutEdges(vertex);
|
||||
auto maybe_edges = vertex.OutEdges(memgraph::storage::View::OLD);
|
||||
MG_ASSERT(maybe_edges.HasValue());
|
||||
for (auto edge : *maybe_edges) {
|
||||
for (auto edge : maybe_edges->edges) {
|
||||
EXPECT_EQ(edge.EdgeType(), edge_type);
|
||||
EXPECT_EQ(edge.GetProperty(memgraph::storage::View::OLD, property.second)->ValueInt(), 3);
|
||||
}
|
||||
@ -1129,7 +1129,7 @@ TYPED_TEST(QueryPlanTest, SetProperty) {
|
||||
dba.PrefetchOutEdges(vertex);
|
||||
auto maybe_edges = vertex.OutEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(maybe_edges.HasValue());
|
||||
for (auto edge : *maybe_edges) {
|
||||
for (auto edge : maybe_edges->edges) {
|
||||
ASSERT_EQ(edge.GetProperty(memgraph::storage::View::OLD, prop1)->type(),
|
||||
memgraph::storage::PropertyValue::Type::Int);
|
||||
EXPECT_EQ(edge.GetProperty(memgraph::storage::View::OLD, prop1)->ValueInt(), 42);
|
||||
@ -1184,7 +1184,7 @@ TYPED_TEST(QueryPlanTest, SetProperties) {
|
||||
dba.PrefetchOutEdges(vertex);
|
||||
auto maybe_edges = vertex.OutEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(maybe_edges.HasValue());
|
||||
for (auto edge : *maybe_edges) {
|
||||
for (auto edge : maybe_edges->edges) {
|
||||
auto from = edge.From();
|
||||
EXPECT_EQ(from.Properties(memgraph::storage::View::OLD)->size(), update ? 2 : 1);
|
||||
if (update) {
|
||||
@ -1365,7 +1365,7 @@ TYPED_TEST(QueryPlanTest, RemoveProperty) {
|
||||
dba.PrefetchOutEdges(vertex);
|
||||
auto maybe_edges = vertex.OutEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(maybe_edges.HasValue());
|
||||
for (auto edge : *maybe_edges) {
|
||||
for (auto edge : maybe_edges->edges) {
|
||||
EXPECT_EQ(edge.GetProperty(memgraph::storage::View::OLD, prop1)->type(),
|
||||
memgraph::storage::PropertyValue::Type::Null);
|
||||
auto from = edge.From();
|
||||
@ -2258,7 +2258,7 @@ TYPED_TEST(UpdatePropertiesWithAuthFixture, SetPropertyExpandWithAuthChecker) {
|
||||
for (auto vertex : this->dba.Vertices(memgraph::storage::View::NEW)) {
|
||||
if (vertex.OutEdges(memgraph::storage::View::NEW).HasValue()) {
|
||||
auto maybe_edges = vertex.OutEdges(memgraph::storage::View::NEW);
|
||||
for (auto edge : *maybe_edges) {
|
||||
for (auto edge : maybe_edges->edges) {
|
||||
EXPECT_EQ(edge.EdgeType(), edge_type_id);
|
||||
auto maybe_properties = edge.Properties(memgraph::storage::View::NEW);
|
||||
ASSERT_TRUE(maybe_properties.HasValue());
|
||||
@ -2276,7 +2276,7 @@ TYPED_TEST(UpdatePropertiesWithAuthFixture, SetPropertyExpandWithAuthChecker) {
|
||||
for (auto vertex : this->dba.Vertices(memgraph::storage::View::NEW)) {
|
||||
if (vertex.OutEdges(memgraph::storage::View::NEW).HasValue()) {
|
||||
auto maybe_edges = vertex.OutEdges(memgraph::storage::View::NEW);
|
||||
for (auto edge : *maybe_edges) {
|
||||
for (auto edge : maybe_edges->edges) {
|
||||
EXPECT_EQ(edge.EdgeType(), edge_type_id);
|
||||
auto maybe_properties = edge.Properties(memgraph::storage::View::NEW);
|
||||
ASSERT_TRUE(maybe_properties.HasValue());
|
||||
@ -2495,3 +2495,112 @@ TYPED_TEST(UpdatePropertiesWithAuthFixture, SetPropertyExpandWithAuthChecker) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename StorageType>
|
||||
class DynamicExpandFixture : public testing::Test {
|
||||
protected:
|
||||
const std::string testSuite = "query_plan_create_set_remove_delete_dynamic_expand";
|
||||
memgraph::storage::Config config = disk_test_utils::GenerateOnDiskConfig(testSuite);
|
||||
std::unique_ptr<memgraph::storage::Storage> db{new StorageType(config)};
|
||||
std::unique_ptr<memgraph::storage::Storage::Accessor> storage_dba{db->Access()};
|
||||
memgraph::query::DbAccessor dba{storage_dba.get()};
|
||||
SymbolTable symbol_table;
|
||||
AstStorage storage;
|
||||
|
||||
// make 2 nodes connected to the third node
|
||||
memgraph::query::VertexAccessor v1{dba.InsertVertex()};
|
||||
memgraph::query::VertexAccessor v2{dba.InsertVertex()};
|
||||
memgraph::query::VertexAccessor v3{dba.InsertVertex()};
|
||||
memgraph::query::VertexAccessor v4{dba.InsertVertex()};
|
||||
memgraph::query::VertexAccessor v5{dba.InsertVertex()};
|
||||
memgraph::storage::EdgeTypeId edge_type{db->NameToEdgeType("Edge")};
|
||||
memgraph::query::EdgeAccessor r1{*dba.InsertEdge(&v1, &v5, edge_type)};
|
||||
memgraph::query::EdgeAccessor r2{*dba.InsertEdge(&v2, &v5, edge_type)};
|
||||
memgraph::query::EdgeAccessor r3{*dba.InsertEdge(&v3, &v5, edge_type)};
|
||||
memgraph::query::EdgeAccessor r4{*dba.InsertEdge(&v4, &v5, edge_type)};
|
||||
|
||||
memgraph::storage::LabelId node_label{dba.NameToLabel("Node")};
|
||||
memgraph::storage::LabelId supernode_label{dba.NameToLabel("Supernode")};
|
||||
|
||||
void SetUp() override {
|
||||
ASSERT_TRUE(v1.AddLabel(node_label).HasValue());
|
||||
ASSERT_TRUE(v2.AddLabel(node_label).HasValue());
|
||||
ASSERT_TRUE(v3.AddLabel(node_label).HasValue());
|
||||
ASSERT_TRUE(v4.AddLabel(node_label).HasValue());
|
||||
ASSERT_TRUE(v5.AddLabel(supernode_label).HasValue());
|
||||
memgraph::license::global_license_checker.EnableTesting();
|
||||
|
||||
dba.AdvanceCommand();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
if (std::is_same<StorageType, memgraph::storage::DiskStorage>::value) {
|
||||
disk_test_utils::RemoveRocksDbDirs(testSuite);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using StorageTypes = ::testing::Types<memgraph::storage::InMemoryStorage, memgraph::storage::DiskStorage>;
|
||||
TYPED_TEST_CASE(DynamicExpandFixture, StorageTypes);
|
||||
|
||||
TYPED_TEST(DynamicExpandFixture, Expand) {
|
||||
using ExpandCursor = memgraph::query::plan::Expand::ExpandCursor;
|
||||
|
||||
auto scan_node_by_label = MakeScanAllByLabel(this->storage, this->symbol_table, "n", this->node_label);
|
||||
auto scan_supernode_by_label =
|
||||
MakeScanAllByLabel(this->storage, this->symbol_table, "s", this->supernode_label, scan_node_by_label.op_);
|
||||
|
||||
auto once = std::make_shared<Once>();
|
||||
|
||||
auto edge_sym = this->symbol_table.CreateSymbol("r", true);
|
||||
auto my_expand = std::make_shared<Expand>(
|
||||
scan_supernode_by_label.op_, scan_supernode_by_label.sym_, scan_node_by_label.sym_, edge_sym,
|
||||
EdgeAtom::Direction::OUT, std::vector<memgraph::storage::EdgeTypeId>{}, true, memgraph::storage::View::OLD);
|
||||
|
||||
auto context = MakeContext(this->storage, this->symbol_table, &this->dba);
|
||||
|
||||
Frame frame{context.symbol_table.max_position()};
|
||||
frame[scan_supernode_by_label.sym_] = this->v4;
|
||||
frame[scan_node_by_label.sym_] = this->v1;
|
||||
|
||||
auto *mem = memgraph::utils::NewDeleteResource();
|
||||
auto initial_cursor_ptr = MakeUniqueCursorPtr<ExpandCursor>(mem, *my_expand, -1, -1, mem);
|
||||
auto *initial_cursor = dynamic_cast<ExpandCursor *>(initial_cursor_ptr.get());
|
||||
auto expansion_info = initial_cursor->GetExpansionInfo(frame);
|
||||
|
||||
ASSERT_EQ(expansion_info.input_node.value(), this->v4);
|
||||
ASSERT_EQ(expansion_info.direction, EdgeAtom::Direction::OUT);
|
||||
ASSERT_EQ(expansion_info.existing_node.value(), this->v1);
|
||||
|
||||
auto expanded_first_cursor_ptr = MakeUniqueCursorPtr<ExpandCursor>(mem, *my_expand, 1, -1, mem);
|
||||
auto *expanded_first_cursor = dynamic_cast<ExpandCursor *>(expanded_first_cursor_ptr.get());
|
||||
expansion_info = expanded_first_cursor->GetExpansionInfo(frame);
|
||||
|
||||
ASSERT_EQ(expansion_info.input_node.value(), this->v1);
|
||||
ASSERT_EQ(expansion_info.direction, EdgeAtom::Direction::IN);
|
||||
ASSERT_EQ(expansion_info.existing_node.value(), this->v4);
|
||||
|
||||
auto expanded_both_take_first_cursor_ptr = MakeUniqueCursorPtr<ExpandCursor>(mem, *my_expand, 1, 100, mem);
|
||||
auto *expanded_both_take_first = dynamic_cast<ExpandCursor *>(expanded_both_take_first_cursor_ptr.get());
|
||||
expansion_info = expanded_both_take_first->GetExpansionInfo(frame);
|
||||
|
||||
ASSERT_EQ(expansion_info.input_node.value(), this->v4);
|
||||
ASSERT_EQ(expansion_info.direction, EdgeAtom::Direction::OUT);
|
||||
ASSERT_EQ(expansion_info.existing_node.value(), this->v1);
|
||||
|
||||
auto expanded_both_take_second_cursor_ptr = MakeUniqueCursorPtr<ExpandCursor>(mem, *my_expand, 100, 1, mem);
|
||||
auto *expanded_both_take_second = dynamic_cast<ExpandCursor *>(expanded_both_take_second_cursor_ptr.get());
|
||||
expansion_info = expanded_both_take_second->GetExpansionInfo(frame);
|
||||
|
||||
ASSERT_EQ(expansion_info.input_node.value(), this->v1);
|
||||
ASSERT_EQ(expansion_info.direction, EdgeAtom::Direction::IN);
|
||||
ASSERT_EQ(expansion_info.existing_node.value(), this->v4);
|
||||
|
||||
auto expanded_equal_take_second_cursror_ptr = MakeUniqueCursorPtr<ExpandCursor>(mem, *my_expand, 5, 5, mem);
|
||||
auto *expanded_equal_take_second = dynamic_cast<ExpandCursor *>(expanded_equal_take_second_cursror_ptr.get());
|
||||
expansion_info = expanded_equal_take_second->GetExpansionInfo(frame);
|
||||
|
||||
ASSERT_EQ(expansion_info.input_node.value(), this->v1);
|
||||
ASSERT_EQ(expansion_info.direction, EdgeAtom::Direction::IN);
|
||||
ASSERT_EQ(expansion_info.existing_node.value(), this->v4);
|
||||
}
|
||||
|
@ -1231,9 +1231,9 @@ TYPED_TEST(QueryPlanExpandVariable, NamedPath) {
|
||||
for (const auto &v : this->dba.Vertices(memgraph::storage::View::OLD)) {
|
||||
if (!*v.HasLabel(memgraph::storage::View::OLD, this->labels[0])) continue;
|
||||
auto maybe_edges1 = v.OutEdges(memgraph::storage::View::OLD);
|
||||
for (const auto &e1 : *maybe_edges1) {
|
||||
for (const auto &e1 : maybe_edges1->edges) {
|
||||
auto maybe_edges2 = e1.To().OutEdges(memgraph::storage::View::OLD);
|
||||
for (const auto &e2 : *maybe_edges2) {
|
||||
for (const auto &e2 : maybe_edges2->edges) {
|
||||
expected_paths.emplace_back(v, e1, e1.To(), e2, e2.To());
|
||||
}
|
||||
}
|
||||
@ -1341,7 +1341,7 @@ TYPED_TEST(QueryPlanExpandVariable, FineGrainedFilterNamedPath) {
|
||||
if (!*v.HasLabel(memgraph::storage::View::OLD, this->labels[0])) continue;
|
||||
expected_paths.emplace_back(v);
|
||||
auto maybe_edges1 = v.OutEdges(memgraph::storage::View::OLD);
|
||||
for (const auto &e1 : *maybe_edges1) {
|
||||
for (const auto &e1 : maybe_edges1->edges) {
|
||||
expected_paths.emplace_back(v, e1, e1.To());
|
||||
}
|
||||
}
|
||||
@ -1378,7 +1378,7 @@ TYPED_TEST(QueryPlanExpandVariable, FineGrainedFilterNamedPath) {
|
||||
if (!*v.HasLabel(memgraph::storage::View::OLD, this->labels[0])) continue;
|
||||
expected_paths.emplace_back(v);
|
||||
auto maybe_edges1 = v.OutEdges(memgraph::storage::View::OLD);
|
||||
for (const auto &e1 : *maybe_edges1) {
|
||||
for (const auto &e1 : maybe_edges1->edges) {
|
||||
expected_paths.emplace_back(v, e1, e1.To());
|
||||
}
|
||||
}
|
||||
|
@ -66,8 +66,8 @@ TYPED_TEST(QueryPlan, CreateNodeWithAttributes) {
|
||||
EXPECT_EQ(v.GetProperty(memgraph::storage::View::NEW, property)->ValueInt(), 42);
|
||||
dba->PrefetchInEdges(v.impl_);
|
||||
dba->PrefetchOutEdges(v.impl_);
|
||||
EXPECT_EQ(CountIterable(*v.InEdges(memgraph::storage::View::NEW)), 0);
|
||||
EXPECT_EQ(CountIterable(*v.OutEdges(memgraph::storage::View::NEW)), 0);
|
||||
EXPECT_EQ(CountIterable(v.InEdges(memgraph::storage::View::NEW)->edges), 0);
|
||||
EXPECT_EQ(CountIterable(v.OutEdges(memgraph::storage::View::NEW)->edges), 0);
|
||||
// Invokes LOG(FATAL) instead of erroring out.
|
||||
// EXPECT_TRUE(v.HasLabel(label, memgraph::storage::View::OLD).IsError());
|
||||
}
|
||||
|
@ -83,13 +83,13 @@ using MgpVertexPtr = std::unique_ptr<mgp_vertex, MgpVertexDeleter>;
|
||||
using MgpVerticesIteratorPtr = std::unique_ptr<mgp_vertices_iterator, MgpVerticesIteratorDeleter>;
|
||||
using MgpValuePtr = std::unique_ptr<mgp_value, MgpValueDeleter>;
|
||||
|
||||
template <typename TMaybeIterable>
|
||||
size_t CountMaybeIterables(TMaybeIterable &&maybe_iterable) {
|
||||
template <typename TMaybeIterable, typename TIterableAccessor>
|
||||
size_t CountMaybeIterables(TMaybeIterable &&maybe_iterable, TIterableAccessor func) {
|
||||
if (maybe_iterable.HasError()) {
|
||||
ADD_FAILURE() << static_cast<std::underlying_type_t<typename TMaybeIterable::ErrorType>>(maybe_iterable.GetError());
|
||||
return 0;
|
||||
}
|
||||
auto &iterable = maybe_iterable.GetValue();
|
||||
auto iterable = func(maybe_iterable.GetValue());
|
||||
return std::distance(iterable.begin(), iterable.end());
|
||||
}
|
||||
|
||||
@ -109,16 +109,20 @@ void CheckEdgeCountBetween(const MgpVertexPtr &from, const MgpVertexPtr &to, con
|
||||
}
|
||||
|
||||
EXPECT_EQ(
|
||||
CountMaybeIterables(std::visit([](auto impl) { return impl.InEdges(memgraph::storage::View::NEW); }, from->impl)),
|
||||
CountMaybeIterables(std::visit([](auto impl) { return impl.InEdges(memgraph::storage::View::NEW); }, from->impl),
|
||||
[](const auto &edge_result) { return edge_result.edges; }),
|
||||
0);
|
||||
EXPECT_EQ(CountMaybeIterables(
|
||||
std::visit([](auto impl) { return impl.OutEdges(memgraph::storage::View::NEW); }, from->impl)),
|
||||
number_of_edges_between);
|
||||
EXPECT_EQ(
|
||||
CountMaybeIterables(std::visit([](auto impl) { return impl.InEdges(memgraph::storage::View::NEW); }, to->impl)),
|
||||
CountMaybeIterables(std::visit([](auto impl) { return impl.OutEdges(memgraph::storage::View::NEW); }, from->impl),
|
||||
[](const auto &edge_result) { return edge_result.edges; }),
|
||||
number_of_edges_between);
|
||||
EXPECT_EQ(
|
||||
CountMaybeIterables(std::visit([](auto impl) { return impl.OutEdges(memgraph::storage::View::NEW); }, to->impl)),
|
||||
CountMaybeIterables(std::visit([](auto impl) { return impl.InEdges(memgraph::storage::View::NEW); }, to->impl),
|
||||
[](const auto &edge_result) { return edge_result.edges; }),
|
||||
number_of_edges_between);
|
||||
EXPECT_EQ(
|
||||
CountMaybeIterables(std::visit([](auto impl) { return impl.OutEdges(memgraph::storage::View::NEW); }, to->impl),
|
||||
[](const auto &edge_result) { return edge_result.edges; }),
|
||||
0);
|
||||
}
|
||||
} // namespace
|
||||
@ -624,7 +628,7 @@ TYPED_TEST(MgpGraphTest, EdgeSetProperty) {
|
||||
memgraph::storage::Gid from_vertex_id{};
|
||||
auto get_edge = [&from_vertex_id](memgraph::storage::Storage::Accessor *accessor) -> memgraph::storage::EdgeAccessor {
|
||||
auto from = accessor->FindVertex(from_vertex_id, memgraph::storage::View::NEW);
|
||||
return std::move(from->OutEdges(memgraph::storage::View::NEW).GetValue().front());
|
||||
return std::move(from->OutEdges(memgraph::storage::View::NEW).GetValue().edges.front());
|
||||
};
|
||||
{
|
||||
const auto vertex_ids = this->CreateEdge();
|
||||
|
@ -208,7 +208,7 @@ TYPED_TEST(TriggerContextTest, ValidObjectsTest) {
|
||||
auto out_edges = vertex.OutEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(out_edges.HasValue());
|
||||
|
||||
for (auto edge : *out_edges) {
|
||||
for (auto edge : out_edges->edges) {
|
||||
trigger_context_collector.RegisterSetObjectProperty(edge, dba.NameToProperty("PROPERTY1"),
|
||||
memgraph::query::TypedValue("Value"),
|
||||
memgraph::query::TypedValue("ValueNew"));
|
||||
|
@ -2278,8 +2278,8 @@ TYPED_TEST(StorageV2Test, VertexNonexistentLabelPropertyEdgeAPI) {
|
||||
ASSERT_EQ(*vertex.HasLabel(label, memgraph::storage::View::NEW), false);
|
||||
ASSERT_EQ(vertex.Properties(memgraph::storage::View::NEW)->size(), 0);
|
||||
ASSERT_EQ(*vertex.GetProperty(property, memgraph::storage::View::NEW), memgraph::storage::PropertyValue());
|
||||
ASSERT_EQ(vertex.InEdges(memgraph::storage::View::NEW)->size(), 0);
|
||||
ASSERT_EQ(vertex.OutEdges(memgraph::storage::View::NEW)->size(), 0);
|
||||
ASSERT_EQ(vertex.InEdges(memgraph::storage::View::NEW)->edges.size(), 0);
|
||||
ASSERT_EQ(vertex.OutEdges(memgraph::storage::View::NEW)->edges.size(), 0);
|
||||
ASSERT_EQ(*vertex.InDegree(memgraph::storage::View::NEW), 0);
|
||||
ASSERT_EQ(*vertex.OutDegree(memgraph::storage::View::NEW), 0);
|
||||
|
||||
@ -2305,8 +2305,8 @@ TYPED_TEST(StorageV2Test, VertexNonexistentLabelPropertyEdgeAPI) {
|
||||
ASSERT_EQ(*vertex.HasLabel(label, memgraph::storage::View::NEW), true);
|
||||
ASSERT_EQ(vertex.Properties(memgraph::storage::View::NEW)->size(), 1);
|
||||
ASSERT_EQ(*vertex.GetProperty(property, memgraph::storage::View::NEW), memgraph::storage::PropertyValue("value"));
|
||||
ASSERT_EQ(vertex.InEdges(memgraph::storage::View::NEW)->size(), 1);
|
||||
ASSERT_EQ(vertex.OutEdges(memgraph::storage::View::NEW)->size(), 1);
|
||||
ASSERT_EQ(vertex.InEdges(memgraph::storage::View::NEW)->edges.size(), 1);
|
||||
ASSERT_EQ(vertex.OutEdges(memgraph::storage::View::NEW)->edges.size(), 1);
|
||||
ASSERT_EQ(*vertex.InDegree(memgraph::storage::View::NEW), 1);
|
||||
ASSERT_EQ(*vertex.OutDegree(memgraph::storage::View::NEW), 1);
|
||||
|
||||
|
@ -322,7 +322,7 @@ class DurabilityTest : public ::testing::TestWithParam<bool> {
|
||||
ASSERT_TRUE(vertex1);
|
||||
auto out_edges = vertex1->OutEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(out_edges.HasValue());
|
||||
auto edge1 = find_edge(*out_edges);
|
||||
auto edge1 = find_edge(out_edges->edges);
|
||||
ASSERT_TRUE(edge1);
|
||||
if (i < kNumBaseEdges / 2) {
|
||||
ASSERT_EQ(edge1->EdgeType(), et1);
|
||||
@ -344,7 +344,7 @@ class DurabilityTest : public ::testing::TestWithParam<bool> {
|
||||
ASSERT_TRUE(vertex2);
|
||||
auto in_edges = vertex2->InEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(in_edges.HasValue());
|
||||
auto edge2 = find_edge(*in_edges);
|
||||
auto edge2 = find_edge(in_edges->edges);
|
||||
ASSERT_TRUE(edge2);
|
||||
if (i < kNumBaseEdges / 2) {
|
||||
ASSERT_EQ(edge2->EdgeType(), et1);
|
||||
@ -457,7 +457,7 @@ class DurabilityTest : public ::testing::TestWithParam<bool> {
|
||||
ASSERT_TRUE(vertex1);
|
||||
auto out_edges = vertex1->OutEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(out_edges.HasValue());
|
||||
auto edge1 = find_edge(*out_edges);
|
||||
auto edge1 = find_edge(out_edges->edges);
|
||||
ASSERT_TRUE(edge1);
|
||||
if (i < kNumExtendedEdges / 4) {
|
||||
ASSERT_EQ(edge1->EdgeType(), et3);
|
||||
@ -475,7 +475,7 @@ class DurabilityTest : public ::testing::TestWithParam<bool> {
|
||||
ASSERT_TRUE(vertex2);
|
||||
auto in_edges = vertex2->InEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(in_edges.HasValue());
|
||||
auto edge2 = find_edge(*in_edges);
|
||||
auto edge2 = find_edge(in_edges->edges);
|
||||
ASSERT_TRUE(edge2);
|
||||
if (i < kNumExtendedEdges / 4) {
|
||||
ASSERT_EQ(edge2->EdgeType(), et3);
|
||||
@ -1128,7 +1128,7 @@ TEST_F(DurabilityTest, SnapshotWithPropertiesOnEdgesButUnusedRecoveryWithoutProp
|
||||
for (auto vertex : acc->Vertices(memgraph::storage::View::OLD)) {
|
||||
auto in_edges = vertex.InEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(in_edges.HasValue());
|
||||
for (auto &edge : *in_edges) {
|
||||
for (auto &edge : in_edges->edges) {
|
||||
// TODO (mferencevic): Replace with `ClearProperties()`
|
||||
auto props = edge.Properties(memgraph::storage::View::NEW);
|
||||
ASSERT_TRUE(props.HasValue());
|
||||
@ -1138,7 +1138,7 @@ TEST_F(DurabilityTest, SnapshotWithPropertiesOnEdgesButUnusedRecoveryWithoutProp
|
||||
}
|
||||
auto out_edges = vertex.InEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(out_edges.HasValue());
|
||||
for (auto &edge : *out_edges) {
|
||||
for (auto &edge : out_edges->edges) {
|
||||
// TODO (mferencevic): Replace with `ClearProperties()`
|
||||
auto props = edge.Properties(memgraph::storage::View::NEW);
|
||||
ASSERT_TRUE(props.HasValue());
|
||||
@ -1377,11 +1377,11 @@ TEST_P(DurabilityTest, WalCreateInSingleTransaction) {
|
||||
ASSERT_EQ(props->size(), 0);
|
||||
auto in_edges = v1->InEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(in_edges.HasValue());
|
||||
ASSERT_EQ(in_edges->size(), 0);
|
||||
ASSERT_EQ(in_edges->edges.size(), 0);
|
||||
auto out_edges = v1->OutEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(out_edges.HasValue());
|
||||
ASSERT_EQ(out_edges->size(), 1);
|
||||
const auto &edge = (*out_edges)[0];
|
||||
ASSERT_EQ(out_edges->edges.size(), 1);
|
||||
const auto &edge = out_edges->edges[0];
|
||||
ASSERT_EQ(edge.Gid(), gid_e1);
|
||||
auto edge_props = edge.Properties(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(edge_props.HasValue());
|
||||
@ -1404,8 +1404,8 @@ TEST_P(DurabilityTest, WalCreateInSingleTransaction) {
|
||||
memgraph::storage::PropertyValue("world"))));
|
||||
auto in_edges = v2->InEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(in_edges.HasValue());
|
||||
ASSERT_EQ(in_edges->size(), 1);
|
||||
const auto &edge = (*in_edges)[0];
|
||||
ASSERT_EQ(in_edges->edges.size(), 1);
|
||||
const auto &edge = in_edges->edges[0];
|
||||
ASSERT_EQ(edge.Gid(), gid_e1);
|
||||
auto edge_props = edge.Properties(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(edge_props.HasValue());
|
||||
@ -1417,7 +1417,7 @@ TEST_P(DurabilityTest, WalCreateInSingleTransaction) {
|
||||
}
|
||||
auto out_edges = v2->OutEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(out_edges.HasValue());
|
||||
ASSERT_EQ(out_edges->size(), 0);
|
||||
ASSERT_EQ(out_edges->edges.size(), 0);
|
||||
}
|
||||
{
|
||||
auto v3 = acc->FindVertex(gid_v3, memgraph::storage::View::OLD);
|
||||
@ -1431,10 +1431,10 @@ TEST_P(DurabilityTest, WalCreateInSingleTransaction) {
|
||||
std::make_pair(store->NameToProperty("v3"), memgraph::storage::PropertyValue(42))));
|
||||
auto in_edges = v3->InEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(in_edges.HasValue());
|
||||
ASSERT_EQ(in_edges->size(), 0);
|
||||
ASSERT_EQ(in_edges->edges.size(), 0);
|
||||
auto out_edges = v3->OutEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(out_edges.HasValue());
|
||||
ASSERT_EQ(out_edges->size(), 0);
|
||||
ASSERT_EQ(out_edges->edges.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -134,22 +134,22 @@ TEST(StorageV2Gc, Sanity) {
|
||||
auto vertex = acc->FindVertex(vertices[i], memgraph::storage::View::NEW);
|
||||
EXPECT_EQ(vertex.has_value(), i % 5 != 0 && i % 3 != 0);
|
||||
if (vertex.has_value()) {
|
||||
auto out_edges = vertex->OutEdges(memgraph::storage::View::NEW);
|
||||
auto out_edges = vertex->OutEdges(memgraph::storage::View::NEW)->edges;
|
||||
if (i % 5 != 4 && i % 3 != 2) {
|
||||
EXPECT_EQ(out_edges.GetValue().size(), 1);
|
||||
EXPECT_EQ(out_edges.size(), 1);
|
||||
EXPECT_EQ(*vertex->OutDegree(memgraph::storage::View::NEW), 1);
|
||||
EXPECT_EQ(out_edges.GetValue().at(0).EdgeType().AsUint(), i);
|
||||
EXPECT_EQ(out_edges.at(0).EdgeType().AsUint(), i);
|
||||
} else {
|
||||
EXPECT_TRUE(out_edges->empty());
|
||||
EXPECT_TRUE(out_edges.empty());
|
||||
}
|
||||
|
||||
auto in_edges = vertex->InEdges(memgraph::storage::View::NEW);
|
||||
auto in_edges = vertex->InEdges(memgraph::storage::View::NEW)->edges;
|
||||
if (i % 5 != 1 && i % 3 != 1) {
|
||||
EXPECT_EQ(in_edges.GetValue().size(), 1);
|
||||
EXPECT_EQ(in_edges.size(), 1);
|
||||
EXPECT_EQ(*vertex->InDegree(memgraph::storage::View::NEW), 1);
|
||||
EXPECT_EQ(in_edges.GetValue().at(0).EdgeType().AsUint(), (i + 999) % 1000);
|
||||
EXPECT_EQ(in_edges.at(0).EdgeType().AsUint(), (i + 999) % 1000);
|
||||
} else {
|
||||
EXPECT_TRUE(in_edges->empty());
|
||||
EXPECT_TRUE(in_edges.empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ TEST_F(ReplicationTest, BasicSynchronousReplicationTest) {
|
||||
ASSERT_TRUE(v);
|
||||
const auto out_edges = v->OutEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(out_edges.HasValue());
|
||||
const auto edge = find_edge(*out_edges, *edge_gid);
|
||||
const auto edge = find_edge(out_edges->edges, *edge_gid);
|
||||
ASSERT_EQ(edge->EdgeType(), replica_store->NameToEdgeType(edge_type));
|
||||
const auto properties = edge->Properties(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(properties.HasValue());
|
||||
@ -197,7 +197,7 @@ TEST_F(ReplicationTest, BasicSynchronousReplicationTest) {
|
||||
auto v = acc->FindVertex(*vertex_gid, memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(v);
|
||||
auto out_edges = v->OutEdges(memgraph::storage::View::OLD);
|
||||
auto edge = find_edge(*out_edges, *edge_gid);
|
||||
auto edge = find_edge(out_edges->edges, *edge_gid);
|
||||
ASSERT_TRUE(edge);
|
||||
ASSERT_TRUE(acc->DeleteEdge(&*edge).HasValue());
|
||||
ASSERT_FALSE(acc->Commit().HasError());
|
||||
@ -209,7 +209,7 @@ TEST_F(ReplicationTest, BasicSynchronousReplicationTest) {
|
||||
ASSERT_TRUE(v);
|
||||
const auto out_edges = v->OutEdges(memgraph::storage::View::OLD);
|
||||
ASSERT_TRUE(out_edges.HasValue());
|
||||
ASSERT_FALSE(find_edge(*out_edges, *edge_gid));
|
||||
ASSERT_FALSE(find_edge(out_edges->edges, *edge_gid));
|
||||
ASSERT_FALSE(acc->Commit().HasError());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user