Serialize query plan operators
Summary: With the added support for serialization, we should be able to transfer plans across distributed workers. The planner tests has been extended to test serialization. Operators should be mostly tested, but the expression they contain aren't completely. The quick solution is to use typeid for rudimentary expression equality testing. The more involved solution of comparing the expression tree for equality is the correct choice. It should be done in the near future. Reviewers: florijan, msantl Reviewed By: florijan Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1122
This commit is contained in:
parent
2a8c64882f
commit
252018ab22
@ -7,6 +7,18 @@
|
||||
|
||||
namespace query {
|
||||
|
||||
// Id for boost's archive get_helper needs to be unique among all ids. If it
|
||||
// isn't unique, then different instances (even across different types!) will
|
||||
// replace the previous helper. The documentation recommends to take an address
|
||||
// of a function, which should be unique in the produced binary.
|
||||
// It might seem logical to take an address of a AstTreeStorage constructor, but
|
||||
// according to c++ standard, the constructor function need not have an address.
|
||||
// Additionally, pointers to member functions are not required to contain the
|
||||
// address of the function
|
||||
// (https://isocpp.org/wiki/faq/pointers-to-members#addr-of-memfn). So, to be
|
||||
// safe, use a regular top-level function.
|
||||
void *const AstTreeStorage::kHelperId = (void *)CloneReturnBody;
|
||||
|
||||
AstTreeStorage::AstTreeStorage() {
|
||||
storage_.emplace_back(new Query(next_uid_++));
|
||||
}
|
||||
@ -15,14 +27,6 @@ Query *AstTreeStorage::query() const {
|
||||
return dynamic_cast<Query *>(storage_[0].get());
|
||||
}
|
||||
|
||||
int AstTreeStorage::MaximumStorageUid() const {
|
||||
int max_uid = -1;
|
||||
for (const auto &tree : storage_) {
|
||||
max_uid = std::max(max_uid, tree->uid());
|
||||
}
|
||||
return max_uid;
|
||||
}
|
||||
|
||||
ReturnBody CloneReturnBody(AstTreeStorage &storage, const ReturnBody &body) {
|
||||
ReturnBody new_body;
|
||||
new_body.distinct = body.distinct;
|
||||
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@ -9,13 +8,10 @@
|
||||
#include "boost/serialization/split_member.hpp"
|
||||
#include "boost/serialization/string.hpp"
|
||||
#include "boost/serialization/vector.hpp"
|
||||
#include "glog/logging.h"
|
||||
|
||||
#include "database/graph_db.hpp"
|
||||
#include "query/frontend/ast/ast_visitor.hpp"
|
||||
#include "query/frontend/semantic/symbol.hpp"
|
||||
#include "query/interpret/awesome_memgraph_functions.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
#include "storage/types.hpp"
|
||||
#include "utils/serialization.hpp"
|
||||
@ -35,6 +31,10 @@ struct hash<std::pair<std::string, storage::Property>> {
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace database {
|
||||
class GraphDbAccessor;
|
||||
}
|
||||
|
||||
namespace query {
|
||||
|
||||
#define CLONE_BINARY_EXPRESSION \
|
||||
@ -60,6 +60,7 @@ namespace query {
|
||||
|
||||
class Tree;
|
||||
|
||||
|
||||
// It would be better to call this AstTree, but we already have a class Tree,
|
||||
// which could be renamed to Node or AstTreeNode, but we also have a class
|
||||
// called NodeAtom...
|
||||
@ -82,14 +83,16 @@ class AstTreeStorage {
|
||||
|
||||
Query *query() const;
|
||||
|
||||
/// Id for using get_helper<AstTreeStorage> in boost archives.
|
||||
static void * const kHelperId;
|
||||
|
||||
/// Load an Ast Node into this storage.
|
||||
template <class TArchive, class TNode>
|
||||
void Load(TArchive &ar, TNode &node) {
|
||||
auto &tmp_ast = ar.template get_helper<AstTreeStorage>();
|
||||
tmp_ast.storage_ = std::move(storage_);
|
||||
auto &tmp_ast = ar.template get_helper<AstTreeStorage>(kHelperId);
|
||||
std::swap(*this, tmp_ast);
|
||||
ar >> node;
|
||||
storage_ = std::move(tmp_ast.storage_);
|
||||
next_uid_ = MaximumStorageUid() + 1;
|
||||
std::swap(*this, tmp_ast);
|
||||
}
|
||||
|
||||
/// Load a Query into this storage.
|
||||
@ -102,8 +105,6 @@ class AstTreeStorage {
|
||||
int next_uid_ = 0;
|
||||
std::vector<std::unique_ptr<Tree>> storage_;
|
||||
|
||||
int MaximumStorageUid() const;
|
||||
|
||||
template <class TArchive, class TNode>
|
||||
friend void LoadPointer(TArchive &ar, TNode *&node);
|
||||
};
|
||||
@ -117,7 +118,8 @@ template <class TArchive, class TNode>
|
||||
void LoadPointer(TArchive &ar, TNode *&node) {
|
||||
ar >> node;
|
||||
if (node) {
|
||||
auto &ast_storage = ar.template get_helper<AstTreeStorage>();
|
||||
auto &ast_storage =
|
||||
ar.template get_helper<AstTreeStorage>(AstTreeStorage::kHelperId);
|
||||
auto found =
|
||||
std::find_if(ast_storage.storage_.begin(), ast_storage.storage_.end(),
|
||||
[&](const auto &n) { return n->uid() == node->uid(); });
|
||||
@ -127,6 +129,7 @@ void LoadPointer(TArchive &ar, TNode *&node) {
|
||||
dynamic_cast<TNode *>(found->get()) == node);
|
||||
if (ast_storage.storage_.end() == found) {
|
||||
ast_storage.storage_.emplace_back(node);
|
||||
ast_storage.next_uid_ = std::max(ast_storage.next_uid_, node->uid() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "boost/serialization/serialization.hpp"
|
||||
#include "boost/serialization/string.hpp"
|
||||
|
||||
namespace query {
|
||||
|
||||
class Symbol {
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
#include "query/frontend/semantic/symbol_table.hpp"
|
||||
#include "query/interpret/frame.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
#include "utils/exceptions.hpp"
|
||||
|
||||
|
@ -1,16 +1,23 @@
|
||||
#include "query/plan/operator.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "boost/archive/binary_iarchive.hpp"
|
||||
#include "boost/archive/binary_oarchive.hpp"
|
||||
#include "boost/serialization/export.hpp"
|
||||
#include "glog/logging.h"
|
||||
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "query/context.hpp"
|
||||
#include "query/exceptions.hpp"
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
#include "query/frontend/semantic/symbol_table.hpp"
|
||||
#include "query/interpret/eval.hpp"
|
||||
|
||||
#include "query/plan/operator.hpp"
|
||||
#include "query/path.hpp"
|
||||
|
||||
// macro for the default implementation of LogicalOperator::Accept
|
||||
// that accepts the visitor and visits it's input_ operator
|
||||
@ -79,7 +86,7 @@ std::unique_ptr<Cursor> Once::MakeCursor(database::GraphDbAccessor &) const {
|
||||
|
||||
void Once::OnceCursor::Reset() { did_pull_ = false; }
|
||||
|
||||
CreateNode::CreateNode(const NodeAtom *node_atom,
|
||||
CreateNode::CreateNode(NodeAtom *node_atom,
|
||||
const std::shared_ptr<LogicalOperator> &input)
|
||||
: node_atom_(node_atom), input_(input ? input : std::make_shared<Once>()) {}
|
||||
|
||||
@ -117,7 +124,7 @@ void CreateNode::CreateNodeCursor::Create(Frame &frame, Context &context) {
|
||||
frame[context.symbol_table_.at(*self_.node_atom_->identifier_)] = new_node;
|
||||
}
|
||||
|
||||
CreateExpand::CreateExpand(const NodeAtom *node_atom, const EdgeAtom *edge_atom,
|
||||
CreateExpand::CreateExpand(NodeAtom *node_atom, EdgeAtom *edge_atom,
|
||||
const std::shared_ptr<LogicalOperator> &input,
|
||||
Symbol input_symbol, bool existing_node)
|
||||
: node_atom_(node_atom),
|
||||
@ -2546,3 +2553,35 @@ void Union::UnionCursor::Reset() {
|
||||
}
|
||||
|
||||
} // namespace query::plan
|
||||
|
||||
BOOST_CLASS_EXPORT(query::plan::Once);
|
||||
BOOST_CLASS_EXPORT(query::plan::CreateNode);
|
||||
BOOST_CLASS_EXPORT(query::plan::CreateExpand);
|
||||
BOOST_CLASS_EXPORT(query::plan::ScanAll);
|
||||
BOOST_CLASS_EXPORT(query::plan::ScanAllByLabel);
|
||||
BOOST_CLASS_EXPORT(query::plan::ScanAllByLabelPropertyRange);
|
||||
BOOST_CLASS_EXPORT(query::plan::ScanAllByLabelPropertyValue);
|
||||
BOOST_CLASS_EXPORT(query::plan::Expand);
|
||||
BOOST_CLASS_EXPORT(query::plan::ExpandVariable);
|
||||
BOOST_CLASS_EXPORT(query::plan::Filter);
|
||||
BOOST_CLASS_EXPORT(query::plan::Produce);
|
||||
BOOST_CLASS_EXPORT(query::plan::ConstructNamedPath);
|
||||
BOOST_CLASS_EXPORT(query::plan::Delete);
|
||||
BOOST_CLASS_EXPORT(query::plan::SetProperty);
|
||||
BOOST_CLASS_EXPORT(query::plan::SetProperties);
|
||||
BOOST_CLASS_EXPORT(query::plan::SetLabels);
|
||||
BOOST_CLASS_EXPORT(query::plan::RemoveProperty);
|
||||
BOOST_CLASS_EXPORT(query::plan::RemoveLabels);
|
||||
BOOST_CLASS_EXPORT(query::plan::ExpandUniquenessFilter<EdgeAccessor>);
|
||||
BOOST_CLASS_EXPORT(query::plan::ExpandUniquenessFilter<VertexAccessor>);
|
||||
BOOST_CLASS_EXPORT(query::plan::Accumulate);
|
||||
BOOST_CLASS_EXPORT(query::plan::Aggregate);
|
||||
BOOST_CLASS_EXPORT(query::plan::Skip);
|
||||
BOOST_CLASS_EXPORT(query::plan::Limit);
|
||||
BOOST_CLASS_EXPORT(query::plan::OrderBy);
|
||||
BOOST_CLASS_EXPORT(query::plan::Merge);
|
||||
BOOST_CLASS_EXPORT(query::plan::Optional);
|
||||
BOOST_CLASS_EXPORT(query::plan::Unwind);
|
||||
BOOST_CLASS_EXPORT(query::plan::Distinct);
|
||||
BOOST_CLASS_EXPORT(query::plan::CreateIndex);
|
||||
BOOST_CLASS_EXPORT(query::plan::Union);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user