Extract pretty printing for distributed
Summary: Knowledge of distributed operators is now removed from PlanPrinter class. The DistributedOperatorVisitor and PlanPrinter are modified so that they may be multiple inherited. This is done using virtual inheritance of HierarchicalLogicalOperatorVisitor. Multiple inheritance is used to derived a DistributedPlanPrinter which knows how to print distributed in operators. This removes the dependency of single node pretty printing on distributed. Reviewers: msantl, mtomic Reviewed By: mtomic Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1606
This commit is contained in:
parent
c3d8ff4ebf
commit
e67fc40743
@ -58,6 +58,7 @@ set(memgraph_src_files
|
||||
query/interpreter.cpp
|
||||
query/plan/distributed.cpp
|
||||
query/plan/distributed_ops.cpp
|
||||
query/plan/distributed_pretty_print.cpp
|
||||
query/plan/operator.cpp
|
||||
query/plan/preprocess.cpp
|
||||
query/plan/pretty_print.cpp
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <capnp/message.h>
|
||||
|
||||
#include "query/plan/distributed_ops.hpp"
|
||||
#include "query/plan/distributed_pretty_print.hpp"
|
||||
#include "query/plan/operator.hpp"
|
||||
#include "query/plan/preprocess.hpp"
|
||||
#include "utils/exceptions.hpp"
|
||||
@ -1119,10 +1120,14 @@ class DistributedPlanner : public HierarchicalLogicalOperatorVisitor {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Treat Explain as if the query is planned without it
|
||||
// Change the pretty printer for Explain, but otherwise treat it as if the
|
||||
// query is planned without it
|
||||
bool PreVisit(Explain &explain) override {
|
||||
CHECK(prev_ops_.empty());
|
||||
prev_ops_.push_back(&explain);
|
||||
explain.pretty_print_ = [](const auto &dba, auto *root, auto *out) {
|
||||
return DistributedPrettyPrint(dba, root, out);
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -26,11 +26,22 @@ using DistributedOperatorCompositeVisitor =
|
||||
DistributedCreateNode, DistributedCreateExpand>;
|
||||
|
||||
/// Base class for visiting regular and distributed LogicalOperator instances.
|
||||
class DistributedOperatorVisitor : public HierarchicalLogicalOperatorVisitor,
|
||||
///
|
||||
/// HierarchicalLogicalOperatorVisitor is inherited virtually, so that potential
|
||||
/// multiple inheritance of DistributedOperatorVisitor and other
|
||||
/// HierarchicalLogicalOperatorVisitor derived types is possible. Note that
|
||||
/// virtual inheritance resolves the diamond problem, but this still carries a
|
||||
/// cost. For example, you can no longer use static_cast to downcast a type even
|
||||
/// though you are 100% sure downcast would be correct. dynamic_cast should work
|
||||
/// as usual.
|
||||
class DistributedOperatorVisitor : public virtual HierarchicalLogicalOperatorVisitor,
|
||||
public DistributedOperatorCompositeVisitor {
|
||||
public:
|
||||
using DistributedOperatorCompositeVisitor::PostVisit;
|
||||
using DistributedOperatorCompositeVisitor::PreVisit;
|
||||
using HierarchicalLogicalOperatorVisitor::PostVisit;
|
||||
using HierarchicalLogicalOperatorVisitor::PreVisit;
|
||||
using HierarchicalLogicalOperatorVisitor::Visit;
|
||||
};
|
||||
cpp<#
|
||||
|
||||
|
77
src/query/plan/distributed_pretty_print.cpp
Normal file
77
src/query/plan/distributed_pretty_print.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include "query/plan/distributed_pretty_print.hpp"
|
||||
|
||||
namespace query::plan {
|
||||
|
||||
bool DistributedPlanPrinter::PreVisit(query::plan::DistributedExpand &op) {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* DistributedExpand";
|
||||
PrintExpand(op);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DistributedPlanPrinter::PreVisit(query::plan::DistributedExpandBfs &op) {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* DistributedExpandBfs";
|
||||
PrintExpand(op);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DistributedPlanPrinter::PreVisit(query::plan::PullRemote &op) {
|
||||
WithPrintLn([&op](auto &out) {
|
||||
out << "* PullRemote [" << op.plan_id() << "] {";
|
||||
utils::PrintIterable(out, op.symbols(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << "}";
|
||||
});
|
||||
WithPrintLn([](auto &out) { out << "|\\"; });
|
||||
++depth_;
|
||||
WithPrintLn([](auto &out) { out << "* workers"; });
|
||||
--depth_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DistributedPlanPrinter::PreVisit(query::plan::PullRemoteOrderBy &op) {
|
||||
WithPrintLn([&op](auto &out) {
|
||||
out << "* PullRemoteOrderBy {";
|
||||
utils::PrintIterable(out, op.symbols(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << "}";
|
||||
});
|
||||
|
||||
WithPrintLn([](auto &out) { out << "|\\"; });
|
||||
++depth_;
|
||||
WithPrintLn([](auto &out) { out << "* workers"; });
|
||||
--depth_;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define PRE_VISIT(TOp) \
|
||||
bool DistributedPlanPrinter::PreVisit(TOp &) { \
|
||||
WithPrintLn([](auto &out) { out << "* " << #TOp; }); \
|
||||
return true; \
|
||||
}
|
||||
|
||||
PRE_VISIT(DistributedCreateNode);
|
||||
PRE_VISIT(DistributedCreateExpand);
|
||||
|
||||
#undef PRE_VISIT
|
||||
|
||||
bool DistributedPlanPrinter::PreVisit(query::plan::Synchronize &op) {
|
||||
WithPrintLn([&op](auto &out) {
|
||||
out << "* Synchronize";
|
||||
if (op.advance_command()) out << " (ADV CMD)";
|
||||
});
|
||||
if (op.pull_remote()) Branch(*op.pull_remote());
|
||||
op.input()->Accept(*this);
|
||||
return false;
|
||||
}
|
||||
|
||||
void DistributedPrettyPrint(const database::GraphDbAccessor &dba,
|
||||
LogicalOperator *plan_root, std::ostream *out) {
|
||||
DistributedPlanPrinter printer(&dba, out);
|
||||
plan_root->Accept(printer);
|
||||
}
|
||||
|
||||
} // namespace query::plan
|
39
src/query/plan/distributed_pretty_print.hpp
Normal file
39
src/query/plan/distributed_pretty_print.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
/// @file
|
||||
#pragma once
|
||||
|
||||
#include "query/plan/distributed_ops.hpp"
|
||||
#include "query/plan/pretty_print.hpp"
|
||||
|
||||
namespace query::plan {
|
||||
|
||||
void DistributedPrettyPrint(const database::GraphDbAccessor &dba,
|
||||
LogicalOperator *plan_root, std::ostream *out);
|
||||
|
||||
inline void DistributedPrettyPrint(const database::GraphDbAccessor &dba,
|
||||
LogicalOperator *plan_root) {
|
||||
DistributedPrettyPrint(dba, plan_root, &std::cout);
|
||||
}
|
||||
|
||||
class DistributedPlanPrinter : public PlanPrinter,
|
||||
public DistributedOperatorVisitor {
|
||||
public:
|
||||
using DistributedOperatorVisitor::PostVisit;
|
||||
using DistributedOperatorVisitor::PreVisit;
|
||||
using DistributedOperatorVisitor::Visit;
|
||||
using PlanPrinter::PlanPrinter;
|
||||
using PlanPrinter::PostVisit;
|
||||
using PlanPrinter::PreVisit;
|
||||
using PlanPrinter::Visit;
|
||||
|
||||
bool PreVisit(DistributedExpand &) override;
|
||||
bool PreVisit(DistributedExpandBfs &) override;
|
||||
|
||||
bool PreVisit(PullRemote &) override;
|
||||
bool PreVisit(PullRemoteOrderBy &) override;
|
||||
|
||||
bool PreVisit(DistributedCreateNode &) override;
|
||||
bool PreVisit(DistributedCreateExpand &) override;
|
||||
bool PreVisit(Synchronize &) override;
|
||||
};
|
||||
|
||||
} // namespace query::plan
|
@ -26,7 +26,6 @@
|
||||
#include "query/frontend/semantic/symbol_table.hpp"
|
||||
#include "query/interpret/eval.hpp"
|
||||
#include "query/path.hpp"
|
||||
#include "query/plan/pretty_print.hpp"
|
||||
#include "utils/algorithm.hpp"
|
||||
#include "utils/exceptions.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
@ -3863,9 +3862,13 @@ std::unique_ptr<Cursor> TestStream::MakeCursor(
|
||||
return std::make_unique<TestStreamCursor>(*this, db);
|
||||
}
|
||||
|
||||
Explain::Explain(const std::shared_ptr<LogicalOperator> &input,
|
||||
const Symbol &output_symbol)
|
||||
: input_(input), output_symbol_(output_symbol) {}
|
||||
Explain::Explain(
|
||||
const std::shared_ptr<LogicalOperator> &input, const Symbol &output_symbol,
|
||||
const std::function<void(const database::GraphDbAccessor &,
|
||||
LogicalOperator *, std::ostream *)> &pretty_print)
|
||||
: pretty_print_(pretty_print),
|
||||
input_(input),
|
||||
output_symbol_(output_symbol) {}
|
||||
|
||||
ACCEPT_WITH_INPUT(Explain);
|
||||
|
||||
@ -3883,7 +3886,7 @@ class ExplainCursor : public Cursor {
|
||||
const Symbol &output_symbol)
|
||||
: printed_plan_rows_([&dba, &self]() {
|
||||
std::stringstream stream;
|
||||
PrettyPrint(dba, self.input().get(), &stream);
|
||||
self.pretty_print_(dba, self.input().get(), &stream);
|
||||
return utils::Split(stream.str(), "\n");
|
||||
}()),
|
||||
print_it_(printed_plan_rows_.begin()),
|
||||
|
@ -2510,12 +2510,18 @@ in the db.")
|
||||
((input "std::shared_ptr<LogicalOperator>"
|
||||
:capnp-save #'save-operator-pointer
|
||||
:capnp-load #'load-operator-pointer)
|
||||
(output-symbol "Symbol" :reader t))
|
||||
(output-symbol "Symbol" :reader t)
|
||||
(pretty-print
|
||||
"std::function<void(const database::GraphDbAccessor &, LogicalOperator *, std::ostream *)>"
|
||||
:scope :public :documentation "Pretty printer function"
|
||||
:capnp-save :dont-save))
|
||||
(:documentation "Pretty print a LogicalOperator plan")
|
||||
(:public
|
||||
#>cpp
|
||||
Explain(const std::shared_ptr<LogicalOperator> &input,
|
||||
const Symbol &output_symbol);
|
||||
Explain(
|
||||
const std::shared_ptr<LogicalOperator> &input, const Symbol &output_symbol,
|
||||
const std::function<void(const database::GraphDbAccessor &,
|
||||
LogicalOperator *, std::ostream *)> &pretty_print);
|
||||
|
||||
bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override;
|
||||
std::unique_ptr<Cursor> MakeCursor(
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "query/plan/cost_estimator.hpp"
|
||||
#include "query/plan/operator.hpp"
|
||||
#include "query/plan/preprocess.hpp"
|
||||
#include "query/plan/pretty_print.hpp"
|
||||
#include "query/plan/rule_based_planner.hpp"
|
||||
#include "query/plan/variable_start_planner.hpp"
|
||||
#include "query/plan/vertex_count_cache.hpp"
|
||||
@ -101,7 +102,10 @@ auto MakeLogicalPlan(TPlanningContext &context, const Parameters ¶meters,
|
||||
if (context.ast_storage.query()->explain_) {
|
||||
last_op = std::make_unique<Explain>(
|
||||
std::move(last_op),
|
||||
context.symbol_table.CreateSymbol("QUERY PLAN", false));
|
||||
context.symbol_table.CreateSymbol("QUERY PLAN", false),
|
||||
[](const auto &dba, auto *root, auto *stream) {
|
||||
return PrettyPrint(dba, root, stream);
|
||||
});
|
||||
}
|
||||
|
||||
return std::make_pair(std::move(last_op), total_cost);
|
||||
|
@ -1,326 +1,232 @@
|
||||
#include "query/plan/pretty_print.hpp"
|
||||
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "query/plan/distributed_ops.hpp"
|
||||
#include "query/plan/operator.hpp"
|
||||
|
||||
namespace query::plan {
|
||||
|
||||
namespace {
|
||||
|
||||
class PlanPrinter final : public DistributedOperatorVisitor {
|
||||
public:
|
||||
using HierarchicalLogicalOperatorVisitor::PostVisit;
|
||||
using HierarchicalLogicalOperatorVisitor::PreVisit;
|
||||
using HierarchicalLogicalOperatorVisitor::Visit;
|
||||
|
||||
explicit PlanPrinter(const database::GraphDbAccessor *dba, std::ostream *out)
|
||||
: dba_(dba), out_(out) {}
|
||||
PlanPrinter::PlanPrinter(const database::GraphDbAccessor *dba,
|
||||
std::ostream *out)
|
||||
: dba_(dba), out_(out) {}
|
||||
|
||||
#define PRE_VISIT(TOp) \
|
||||
bool PreVisit(query::plan::TOp &) override { \
|
||||
bool PlanPrinter::PreVisit(TOp &) { \
|
||||
WithPrintLn([](auto &out) { out << "* " << #TOp; }); \
|
||||
return true; \
|
||||
}
|
||||
|
||||
PRE_VISIT(CreateNode);
|
||||
PRE_VISIT(CreateExpand);
|
||||
PRE_VISIT(Delete);
|
||||
PRE_VISIT(CreateNode);
|
||||
PRE_VISIT(CreateExpand);
|
||||
PRE_VISIT(Delete);
|
||||
|
||||
bool PreVisit(query::plan::ScanAll &op) override {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* ScanAll"
|
||||
<< " (" << op.output_symbol().name() << ")";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::ScanAll &op) {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* ScanAll"
|
||||
<< " (" << op.output_symbol().name() << ")";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::ScanAllByLabel &op) override {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* ScanAllByLabel"
|
||||
<< " (" << op.output_symbol().name() << " :"
|
||||
<< dba_->LabelName(op.label()) << ")";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::ScanAllByLabel &op) {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* ScanAllByLabel"
|
||||
<< " (" << op.output_symbol().name() << " :"
|
||||
<< dba_->LabelName(op.label()) << ")";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::ScanAllByLabelPropertyValue &op) override {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* ScanAllByLabelPropertyValue"
|
||||
<< " (" << op.output_symbol().name() << " :"
|
||||
<< dba_->LabelName(op.label()) << " {"
|
||||
<< dba_->PropertyName(op.property()) << "})";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::ScanAllByLabelPropertyValue &op) {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* ScanAllByLabelPropertyValue"
|
||||
<< " (" << op.output_symbol().name() << " :"
|
||||
<< dba_->LabelName(op.label()) << " {"
|
||||
<< dba_->PropertyName(op.property()) << "})";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::ScanAllByLabelPropertyRange &op) override {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* ScanAllByLabelPropertyRange"
|
||||
<< " (" << op.output_symbol().name() << " :"
|
||||
<< dba_->LabelName(op.label()) << " {"
|
||||
<< dba_->PropertyName(op.property()) << "})";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::ScanAllByLabelPropertyRange &op) {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* ScanAllByLabelPropertyRange"
|
||||
<< " (" << op.output_symbol().name() << " :"
|
||||
<< dba_->LabelName(op.label()) << " {"
|
||||
<< dba_->PropertyName(op.property()) << "})";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::Expand &op) override {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* Expand";
|
||||
PrintExpand(out, op);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::Expand &op) {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* Expand";
|
||||
PrintExpand(op);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::ExpandVariable &op) override {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* ExpandVariable";
|
||||
PrintExpand(out, op);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::ExpandVariable &op) {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* ExpandVariable";
|
||||
PrintExpand(op);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::DistributedExpand &op) override {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* DistributedExpand";
|
||||
PrintExpand(out, op);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::Produce &op) {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* Produce {";
|
||||
utils::PrintIterable(
|
||||
out, op.named_expressions(), ", ",
|
||||
[](auto &out, const auto &nexpr) { out << nexpr->name_; });
|
||||
out << "}";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::DistributedExpandBfs &op) override {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* DistributedExpandBfs";
|
||||
PrintExpand(out, op);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
PRE_VISIT(ConstructNamedPath);
|
||||
PRE_VISIT(Filter);
|
||||
PRE_VISIT(SetProperty);
|
||||
PRE_VISIT(SetProperties);
|
||||
PRE_VISIT(SetLabels);
|
||||
PRE_VISIT(RemoveProperty);
|
||||
PRE_VISIT(RemoveLabels);
|
||||
PRE_VISIT(ExpandUniquenessFilter<VertexAccessor>);
|
||||
PRE_VISIT(ExpandUniquenessFilter<EdgeAccessor>);
|
||||
PRE_VISIT(Accumulate);
|
||||
|
||||
bool PreVisit(query::plan::Produce &op) override {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* Produce {";
|
||||
utils::PrintIterable(
|
||||
out, op.named_expressions(), ", ",
|
||||
[](auto &out, const auto &nexpr) { out << nexpr->name_; });
|
||||
out << "}";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::Aggregate &op) {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* Aggregate {";
|
||||
utils::PrintIterable(
|
||||
out, op.aggregations(), ", ",
|
||||
[](auto &out, const auto &aggr) { out << aggr.output_sym.name(); });
|
||||
out << "} {";
|
||||
utils::PrintIterable(out, op.remember(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << "}";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
PRE_VISIT(ConstructNamedPath);
|
||||
PRE_VISIT(Filter);
|
||||
PRE_VISIT(SetProperty);
|
||||
PRE_VISIT(SetProperties);
|
||||
PRE_VISIT(SetLabels);
|
||||
PRE_VISIT(RemoveProperty);
|
||||
PRE_VISIT(RemoveLabels);
|
||||
PRE_VISIT(ExpandUniquenessFilter<VertexAccessor>);
|
||||
PRE_VISIT(ExpandUniquenessFilter<EdgeAccessor>);
|
||||
PRE_VISIT(Accumulate);
|
||||
PRE_VISIT(Skip);
|
||||
PRE_VISIT(Limit);
|
||||
|
||||
bool PreVisit(query::plan::Aggregate &op) override {
|
||||
WithPrintLn([&](auto &out) {
|
||||
out << "* Aggregate {";
|
||||
utils::PrintIterable(
|
||||
out, op.aggregations(), ", ",
|
||||
[](auto &out, const auto &aggr) { out << aggr.output_sym.name(); });
|
||||
out << "} {";
|
||||
utils::PrintIterable(
|
||||
out, op.remember(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << "}";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::OrderBy &op) {
|
||||
WithPrintLn([&op](auto &out) {
|
||||
out << "* OrderBy {";
|
||||
utils::PrintIterable(out, op.output_symbols(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << "}";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
PRE_VISIT(Skip);
|
||||
PRE_VISIT(Limit);
|
||||
bool PlanPrinter::PreVisit(query::plan::Merge &op) {
|
||||
WithPrintLn([](auto &out) { out << "* Merge"; });
|
||||
Branch(*op.merge_match(), "On Match");
|
||||
Branch(*op.merge_create(), "On Create");
|
||||
op.input()->Accept(*this);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::OrderBy &op) override {
|
||||
WithPrintLn([&op](auto &out) {
|
||||
out << "* OrderBy {";
|
||||
utils::PrintIterable(
|
||||
out, op.output_symbols(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << "}";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::Optional &op) {
|
||||
WithPrintLn([](auto &out) { out << "* Optional"; });
|
||||
Branch(*op.optional());
|
||||
op.input()->Accept(*this);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::Merge &op) override {
|
||||
WithPrintLn([](auto &out) { out << "* Merge"; });
|
||||
Branch(*op.merge_match(), "On Match");
|
||||
Branch(*op.merge_create(), "On Create");
|
||||
op.input()->Accept(*this);
|
||||
return false;
|
||||
}
|
||||
PRE_VISIT(Unwind);
|
||||
PRE_VISIT(Distinct);
|
||||
|
||||
bool PreVisit(query::plan::Optional &op) override {
|
||||
WithPrintLn([](auto &out) { out << "* Optional"; });
|
||||
Branch(*op.optional());
|
||||
op.input()->Accept(*this);
|
||||
return false;
|
||||
}
|
||||
bool PlanPrinter::Visit(query::plan::Once &op) {
|
||||
// Ignore checking Once, it is implicitly at the end.
|
||||
return true;
|
||||
}
|
||||
|
||||
PRE_VISIT(Unwind);
|
||||
PRE_VISIT(Distinct);
|
||||
bool PlanPrinter::Visit(query::plan::CreateIndex &op) {
|
||||
WithPrintLn([](auto &out) { out << "* CreateIndex"; });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Visit(query::plan::Once &op) override {
|
||||
// Ignore checking Once, it is implicitly at the end.
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::Visit(query::plan::AuthHandler &op) {
|
||||
WithPrintLn([](auto &out) { out << "* AuthHandler"; });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Visit(query::plan::CreateIndex &op) override {
|
||||
WithPrintLn([](auto &out) { out << "* CreateIndex"; });
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::Visit(query::plan::CreateStream &op) {
|
||||
WithPrintLn([](auto &out) { out << "* CreateStream"; });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Visit(query::plan::AuthHandler &op) override {
|
||||
WithPrintLn([](auto &out) { out << "* AuthHandler"; });
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::Visit(query::plan::DropStream &op) {
|
||||
WithPrintLn([](auto &out) { out << "* DropStream"; });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Visit(query::plan::CreateStream &op) override {
|
||||
WithPrintLn([](auto &out) { out << "* CreateStream"; });
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::Visit(query::plan::ShowStreams &op) {
|
||||
WithPrintLn([](auto &out) { out << "* ShowStreams"; });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Visit(query::plan::DropStream &op) override {
|
||||
WithPrintLn([](auto &out) { out << "* DropStream"; });
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::Visit(query::plan::StartStopStream &op) {
|
||||
WithPrintLn([](auto &out) { out << "* StartStopStream"; });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Visit(query::plan::ShowStreams &op) override {
|
||||
WithPrintLn([](auto &out) { out << "* ShowStreams"; });
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::Visit(query::plan::StartStopAllStreams &op) {
|
||||
WithPrintLn([](auto &out) { out << "* StartStopAllStreams"; });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Visit(query::plan::StartStopStream &op) override {
|
||||
WithPrintLn([](auto &out) { out << "* StartStopStream"; });
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::Visit(query::plan::TestStream &op) {
|
||||
WithPrintLn([](auto &out) { out << "* TestStream"; });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Visit(query::plan::StartStopAllStreams &op) override {
|
||||
WithPrintLn([](auto &out) { out << "* StartStopAllStreams"; });
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::Explain &explain) {
|
||||
WithPrintLn([&explain](auto &out) {
|
||||
out << "* Explain {" << explain.output_symbol().name() << "}";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Visit(query::plan::TestStream &op) override {
|
||||
WithPrintLn([](auto &out) { out << "* TestStream"; });
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::PreVisit(query::plan::Cartesian &op) {
|
||||
WithPrintLn([&op](auto &out) {
|
||||
out << "* Cartesian {";
|
||||
utils::PrintIterable(out, op.left_symbols(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << " : ";
|
||||
utils::PrintIterable(out, op.right_symbols(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << "}";
|
||||
});
|
||||
Branch(*op.right_op());
|
||||
op.left_op()->Accept(*this);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::Explain &explain) override {
|
||||
WithPrintLn([&explain](auto &out) {
|
||||
out << "* Explain {" << explain.output_symbol().name() << "}";
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::PullRemote &op) override {
|
||||
WithPrintLn([&op](auto &out) {
|
||||
out << "* PullRemote [" << op.plan_id() << "] {";
|
||||
utils::PrintIterable(
|
||||
out, op.symbols(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << "}";
|
||||
});
|
||||
WithPrintLn([](auto &out) { out << "|\\"; });
|
||||
++depth_;
|
||||
WithPrintLn([](auto &out) { out << "* workers"; });
|
||||
--depth_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::Synchronize &op) override {
|
||||
WithPrintLn([&op](auto &out) {
|
||||
out << "* Synchronize";
|
||||
if (op.advance_command()) out << " (ADV CMD)";
|
||||
});
|
||||
if (op.pull_remote()) Branch(*op.pull_remote());
|
||||
op.input()->Accept(*this);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::Cartesian &op) override {
|
||||
WithPrintLn([&op](auto &out) {
|
||||
out << "* Cartesian {";
|
||||
utils::PrintIterable(
|
||||
out, op.left_symbols(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << " : ";
|
||||
utils::PrintIterable(
|
||||
out, op.right_symbols(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << "}";
|
||||
});
|
||||
Branch(*op.right_op());
|
||||
op.left_op()->Accept(*this);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PreVisit(query::plan::PullRemoteOrderBy &op) override {
|
||||
WithPrintLn([&op](auto &out) {
|
||||
out << "* PullRemoteOrderBy {";
|
||||
utils::PrintIterable(
|
||||
out, op.symbols(), ", ",
|
||||
[](auto &out, const auto &sym) { out << sym.name(); });
|
||||
out << "}";
|
||||
});
|
||||
|
||||
WithPrintLn([](auto &out) { out << "|\\"; });
|
||||
++depth_;
|
||||
WithPrintLn([](auto &out) { out << "* workers"; });
|
||||
--depth_;
|
||||
return true;
|
||||
}
|
||||
|
||||
PRE_VISIT(DistributedCreateNode);
|
||||
PRE_VISIT(DistributedCreateExpand);
|
||||
#undef PRE_VISIT
|
||||
|
||||
private:
|
||||
bool DefaultPreVisit() override {
|
||||
WithPrintLn([](auto &out) { out << "* Unknown operator!"; });
|
||||
return true;
|
||||
}
|
||||
bool PlanPrinter::DefaultPreVisit() {
|
||||
WithPrintLn([](auto &out) { out << "* Unknown operator!"; });
|
||||
return true;
|
||||
}
|
||||
|
||||
// Call fun with output stream. The stream is prefixed with amount of spaces
|
||||
// corresponding to the current depth_.
|
||||
template <class TFun>
|
||||
void WithPrintLn(TFun fun) {
|
||||
*out_ << " ";
|
||||
for (int i = 0; i < depth_; ++i) {
|
||||
*out_ << "| ";
|
||||
}
|
||||
fun(*out_);
|
||||
*out_ << std::endl;
|
||||
}
|
||||
void PlanPrinter::Branch(query::plan::LogicalOperator &op,
|
||||
const std::string &branch_name) {
|
||||
WithPrintLn([&](auto &out) { out << "|\\ " << branch_name; });
|
||||
++depth_;
|
||||
op.Accept(*this);
|
||||
--depth_;
|
||||
}
|
||||
|
||||
// Forward this printer to another operator branch by incrementing the depth
|
||||
// and printing the branch name.
|
||||
void Branch(query::plan::LogicalOperator &op,
|
||||
const std::string &branch_name = "") {
|
||||
WithPrintLn([&](auto &out) { out << "|\\ " << branch_name; });
|
||||
++depth_;
|
||||
op.Accept(*this);
|
||||
--depth_;
|
||||
}
|
||||
|
||||
void PrintExpand(std::ostream &out, const query::plan::ExpandCommon &op) {
|
||||
out << " (" << op.input_symbol().name() << ")"
|
||||
void PlanPrinter::PrintExpand(const query::plan::ExpandCommon &op) {
|
||||
*out_ << " (" << op.input_symbol().name() << ")"
|
||||
<< (op.direction() == query::EdgeAtom::Direction::IN ? "<-" : "-")
|
||||
<< "[" << op.edge_symbol().name() << "]"
|
||||
<< (op.direction() == query::EdgeAtom::Direction::OUT ? "->" : "-")
|
||||
<< "(" << op.node_symbol().name() << ")";
|
||||
}
|
||||
|
||||
int depth_ = 0;
|
||||
const database::GraphDbAccessor *dba_{nullptr};
|
||||
std::ostream *out_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace
|
||||
}
|
||||
|
||||
void PrettyPrint(const database::GraphDbAccessor &dba,
|
||||
LogicalOperator *plan_root, std::ostream *out) {
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "query/plan/operator.hpp"
|
||||
|
||||
namespace database {
|
||||
class GraphDbAccessor;
|
||||
}
|
||||
@ -24,4 +26,91 @@ inline void PrettyPrint(const database::GraphDbAccessor &dba,
|
||||
PrettyPrint(dba, plan_root, &std::cout);
|
||||
}
|
||||
|
||||
class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor {
|
||||
public:
|
||||
using HierarchicalLogicalOperatorVisitor::PostVisit;
|
||||
using HierarchicalLogicalOperatorVisitor::PreVisit;
|
||||
using HierarchicalLogicalOperatorVisitor::Visit;
|
||||
|
||||
PlanPrinter(const database::GraphDbAccessor *dba, std::ostream *out);
|
||||
|
||||
bool DefaultPreVisit() override;
|
||||
|
||||
bool PreVisit(CreateNode &) override;
|
||||
bool PreVisit(CreateExpand &) override;
|
||||
bool PreVisit(Delete &) override;
|
||||
|
||||
bool PreVisit(SetProperty &) override;
|
||||
bool PreVisit(SetProperties &) override;
|
||||
bool PreVisit(SetLabels &) override;
|
||||
|
||||
bool PreVisit(RemoveProperty &) override;
|
||||
bool PreVisit(RemoveLabels &) override;
|
||||
|
||||
bool PreVisit(ScanAll &) override;
|
||||
bool PreVisit(ScanAllByLabel &) override;
|
||||
bool PreVisit(ScanAllByLabelPropertyValue &) override;
|
||||
bool PreVisit(ScanAllByLabelPropertyRange &) override;
|
||||
|
||||
bool PreVisit(Expand &) override;
|
||||
bool PreVisit(ExpandVariable &) override;
|
||||
|
||||
bool PreVisit(ConstructNamedPath &) override;
|
||||
|
||||
bool PreVisit(Filter &) override;
|
||||
bool PreVisit(ExpandUniquenessFilter<VertexAccessor> &) override;
|
||||
bool PreVisit(ExpandUniquenessFilter<EdgeAccessor> &) override;
|
||||
|
||||
bool PreVisit(Merge &) override;
|
||||
bool PreVisit(Optional &) override;
|
||||
bool PreVisit(Cartesian &) override;
|
||||
|
||||
bool PreVisit(Produce &) override;
|
||||
bool PreVisit(Accumulate &) override;
|
||||
bool PreVisit(Aggregate &) override;
|
||||
bool PreVisit(Skip &) override;
|
||||
bool PreVisit(Limit &) override;
|
||||
bool PreVisit(OrderBy &) override;
|
||||
bool PreVisit(Distinct &) override;
|
||||
|
||||
bool PreVisit(Unwind &) override;
|
||||
bool PreVisit(Explain &) override;
|
||||
|
||||
bool Visit(Once &) override;
|
||||
bool Visit(CreateIndex &) override;
|
||||
|
||||
bool Visit(AuthHandler &) override;
|
||||
|
||||
bool Visit(CreateStream &) override;
|
||||
bool Visit(DropStream &) override;
|
||||
bool Visit(ShowStreams &) override;
|
||||
bool Visit(StartStopStream &) override;
|
||||
bool Visit(StartStopAllStreams &) override;
|
||||
bool Visit(TestStream &) override;
|
||||
|
||||
/// Call fun with output stream. The stream is prefixed with amount of spaces
|
||||
/// corresponding to the current depth_.
|
||||
template <class TFun>
|
||||
void WithPrintLn(TFun fun) {
|
||||
*out_ << " ";
|
||||
for (int i = 0; i < depth_; ++i) {
|
||||
*out_ << "| ";
|
||||
}
|
||||
fun(*out_);
|
||||
*out_ << std::endl;
|
||||
}
|
||||
|
||||
/// Forward this printer to another operator branch by incrementing the depth
|
||||
/// and printing the branch name.
|
||||
void Branch(LogicalOperator &op, const std::string &branch_name = "");
|
||||
|
||||
void PrintExpand(const query::plan::ExpandCommon &op);
|
||||
|
||||
int64_t depth_{0};
|
||||
|
||||
private:
|
||||
const database::GraphDbAccessor *dba_{nullptr};
|
||||
std::ostream *out_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace query::plan
|
||||
|
@ -20,8 +20,8 @@
|
||||
#include "query/frontend/stripped.hpp"
|
||||
#include "query/plan/cost_estimator.hpp"
|
||||
#include "query/plan/distributed.hpp"
|
||||
#include "query/plan/distributed_pretty_print.hpp"
|
||||
#include "query/plan/planner.hpp"
|
||||
#include "query/plan/pretty_print.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
#include "utils/string.hpp"
|
||||
@ -398,7 +398,7 @@ DEFCOMMAND(Top) {
|
||||
auto &plan_pair = plans[i];
|
||||
std::cout << "---- Plan #" << i << " ---- " << std::endl;
|
||||
std::cout << "cost: " << plan_pair.second << std::endl;
|
||||
query::plan::PrettyPrint(dba, plan_pair.first.get());
|
||||
query::plan::DistributedPrettyPrint(dba, plan_pair.first.get());
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
@ -411,7 +411,7 @@ DEFCOMMAND(Show) {
|
||||
const auto &plan = plans[plan_ix].first;
|
||||
auto cost = plans[plan_ix].second;
|
||||
std::cout << "Plan cost: " << cost << std::endl;
|
||||
query::plan::PrettyPrint(dba, plan.get());
|
||||
query::plan::DistributedPrettyPrint(dba, plan.get());
|
||||
}
|
||||
|
||||
DEFCOMMAND(ShowDistributed) {
|
||||
@ -424,7 +424,7 @@ DEFCOMMAND(ShowDistributed) {
|
||||
auto distributed_plan = MakeDistributedPlan(*plan, symbol_table, plan_id);
|
||||
{
|
||||
std::cout << "---- Master Plan ---- " << std::endl;
|
||||
query::plan::PrettyPrint(dba, distributed_plan.master_plan.get());
|
||||
query::plan::DistributedPrettyPrint(dba, distributed_plan.master_plan.get());
|
||||
std::cout << std::endl;
|
||||
}
|
||||
for (size_t i = 0; i < distributed_plan.worker_plans.size(); ++i) {
|
||||
@ -432,7 +432,7 @@ DEFCOMMAND(ShowDistributed) {
|
||||
std::shared_ptr<query::plan::LogicalOperator> worker_plan;
|
||||
std::tie(id, worker_plan) = distributed_plan.worker_plans[i];
|
||||
std::cout << "---- Worker Plan #" << id << " ---- " << std::endl;
|
||||
query::plan::PrettyPrint(dba, worker_plan.get());
|
||||
query::plan::DistributedPrettyPrint(dba, worker_plan.get());
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user