diff --git a/src/exec/CMakeLists.txt b/src/exec/CMakeLists.txt index ab8ca5069f3c4a6c63ebf7f8fb63669fd1437d69..46a2d78bfedd7e72d7fbb34784f32681d9400693 100644 --- a/src/exec/CMakeLists.txt +++ b/src/exec/CMakeLists.txt @@ -27,6 +27,7 @@ nebula_add_library( query/DataCollectExecutor.cpp query/DataJoinExecutor.cpp admin/SwitchSpaceExecutor.cpp + admin/ShowHostsExecutor.cpp admin/SpaceExecutor.cpp admin/SnapshotExecutor.cpp maintain/TagExecutor.cpp diff --git a/src/exec/Executor.cpp b/src/exec/Executor.cpp index d7c4cc120568da08e18895761e3e3e820002fb93..d1f1a2af5dfd44098cb7262fa23aeb97e293a703 100644 --- a/src/exec/Executor.cpp +++ b/src/exec/Executor.cpp @@ -13,6 +13,7 @@ #include "context/ExecutionContext.h" #include "context/QueryContext.h" #include "exec/ExecutionError.h" +#include "exec/admin/ShowHostsExecutor.h" #include "exec/admin/SnapshotExecutor.h" #include "exec/admin/SpaceExecutor.h" #include "exec/admin/SwitchSpaceExecutor.h" @@ -399,6 +400,13 @@ Executor *Executor::makeExecutor(const PlanNode *node, exec->dependsOn(input); break; } + case PlanNode::Kind::kShowHosts: { + auto showHosts = asNode<ShowHosts>(node); + auto input = makeExecutor(showHosts->dep(), qctx, visited); + exec = new ShowHostsExecutor(showHosts, qctx); + exec->dependsOn(input); + break; + } case PlanNode::Kind::kUnknown: default: LOG(FATAL) << "Unknown plan node kind " << static_cast<int32_t>(node->kind()); @@ -453,6 +461,15 @@ Status Executor::finish(Result &&result) { return Status::OK(); } +Status Executor::finish(Value &&value) { + ectx_->setResult(node()->varName(), + ResultBuilder() + .value(std::move(value)) + .iter(Iterator::Kind::kDefault) + .finish()); + return Status::OK(); +} + folly::Executor *Executor::runner() const { if (!qctx() || !qctx()->rctx() || !qctx()->rctx()->runner()) { // This is just for test diff --git a/src/exec/Executor.h b/src/exec/Executor.h index 241ccb77079d1a7542c1e5a4c233deec0d89d8e0..86045d293a5b4efa5124660ee254f6a327c9d06c 100644 --- a/src/exec/Executor.h +++ b/src/exec/Executor.h @@ -98,6 +98,8 @@ protected: // Store the result of this executor to execution context Status finish(Result &&result); + // Store the default result which not used for later executor + Status finish(Value &&value); int64_t id_; diff --git a/src/exec/admin/ShowHostsExecutor.cpp b/src/exec/admin/ShowHostsExecutor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b3917d8ece03b721b7f12d8370070bd9149579b --- /dev/null +++ b/src/exec/admin/ShowHostsExecutor.cpp @@ -0,0 +1,76 @@ +/* Copyright (c) 2020 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#include "exec/admin/ShowHostsExecutor.h" +#include "planner/Admin.h" +#include "context/QueryContext.h" + +namespace nebula { +namespace graph { + +folly::Future<Status> ShowHostsExecutor::execute() { + SCOPED_TIMER(&execTime_); + return showHosts().ensure([this]() { UNUSED(this); }); +} + +folly::Future<Status> ShowHostsExecutor::showHosts() { + static constexpr char kNoPartition[] = "No valid partition"; + static constexpr char kPartitionDelimeter[] = ", "; + return qctx() + ->getMetaClient() + ->listHosts() + .via(runner()) + .then([this](auto &&resp) { + if (!resp.ok()) { + LOG(ERROR) << resp.status(); + return resp.status(); + } + auto value = std::move(resp).value(); + DataSet v({"Host", + "Port", + "Status", + "Leader count", + "Leader distribution", + "Partition distribution"}); + for (const auto &host : value) { + nebula::Row r({host.get_hostAddr().host, + host.get_hostAddr().port, + meta::cpp2::_HostStatus_VALUES_TO_NAMES.at(host.get_status()), + static_cast<int64_t>(host.get_leader_parts().size())}); + std::stringstream leaders; + std::stringstream parts; + std::size_t i = 0; + for (const auto &l : host.get_leader_parts()) { + leaders << l.first << ":" << l.second.size(); + if (i < host.get_leader_parts().size() - 1) { + leaders << kPartitionDelimeter; + } + ++i; + } + if (host.get_leader_parts().empty()) { + leaders << kNoPartition; + } + i = 0; + for (const auto &p : host.get_all_parts()) { + parts << p.first << ":" << p.second.size(); + if (i < host.get_leader_parts().size() - 1) { + parts << kPartitionDelimeter; + } + ++i; + } + if (host.get_all_parts().empty()) { + parts << kNoPartition; + } + r.emplace_back(leaders.str()); + r.emplace_back(parts.str()); + v.emplace_back(std::move(r)); + } // row loop + return finish(std::move(v)); + }); +} + +} // namespace graph +} // namespace nebula diff --git a/src/exec/admin/ShowHostsExecutor.h b/src/exec/admin/ShowHostsExecutor.h new file mode 100644 index 0000000000000000000000000000000000000000..dd5a9cf8d919e38ee60cc448e26093abf3a03d8f --- /dev/null +++ b/src/exec/admin/ShowHostsExecutor.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2020 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#ifndef EXEC_ADMIN_SHOW_HOSTS_EXECUTOR_H_ +#define EXEC_ADMIN_SHOW_HOSTS_EXECUTOR_H_ + +#include "exec/Executor.h" + +namespace nebula { +namespace graph { + +class ShowHostsExecutor final : public Executor { +public: + ShowHostsExecutor(const PlanNode *node, QueryContext *qctx) + : Executor("ShowHostsExecutor", node, qctx) {} + + folly::Future<Status> execute() override; + +private: + folly::Future<Status> showHosts(); +}; + +} // namespace graph +} // namespace nebula + +#endif diff --git a/src/planner/Admin.h b/src/planner/Admin.h index b17f70921e95fc1ced08669b95770103d8aeb678..25e1a59b4760eccfc23aa8d647956d1debf77094 100644 --- a/src/planner/Admin.h +++ b/src/planner/Admin.h @@ -19,6 +19,25 @@ */ namespace nebula { namespace graph { +// TODO: All DDLs, DMLs and DQLs could be used in a single query +// which would make them in a single and big execution plan + +class ShowHosts final : public SingleDependencyNode { + // TODO(shylock) meta/storage/graph enumerate +public: + static ShowHosts* make(ExecutionPlan* plan, PlanNode* dep) { + return new ShowHosts(plan, dep); + } + + std::string explain() const override { + return "ShowHosts"; + } + +private: + explicit ShowHosts(ExecutionPlan* plan, PlanNode* dep) + : SingleDependencyNode(plan, Kind::kShowHosts, dep) {} +}; + class CreateSpace final : public SingleInputNode { public: static CreateSpace* make(ExecutionPlan* plan, diff --git a/src/planner/PlanNode.cpp b/src/planner/PlanNode.cpp index f7319b26ddf602b24107064c7dc9c8db8093bb37..ad8870f399ec5bbdb0a6c704649a70af8e669aa4 100644 --- a/src/planner/PlanNode.cpp +++ b/src/planner/PlanNode.cpp @@ -112,6 +112,8 @@ const char* PlanNode::toString(PlanNode::Kind kind) { return "UpdateVertex"; case Kind::kUpdateEdge: return "UpdateEdge"; + case Kind::kShowHosts: + return "ShowHosts"; } LOG(FATAL) << "Impossible kind plan node " << static_cast<int>(kind); } diff --git a/src/planner/PlanNode.h b/src/planner/PlanNode.h index b4e6241e5f2624062f4110045c06bb40fa2e58c9..4ddd9808f946a43f007937d2a463e30dbbac225f 100644 --- a/src/planner/PlanNode.h +++ b/src/planner/PlanNode.h @@ -61,6 +61,7 @@ public: kDropEdge, kInsertVertices, kInsertEdges, + kShowHosts, kDataCollect, kCreateSnapshot, kDropSnapshot, diff --git a/src/validator/Validator.cpp b/src/validator/Validator.cpp index 4a8a2c7a50be591f912e3ef6dfc19c8138f9df3f..4409c266eb305705a6785c6bfcb882e0d8b5f705 100644 --- a/src/validator/Validator.cpp +++ b/src/validator/Validator.cpp @@ -125,6 +125,7 @@ std::unique_ptr<Validator> Validator::makeValidator(Sentence* sentence, QueryCon Status Validator::appendPlan(PlanNode* node, PlanNode* appended) { switch (DCHECK_NOTNULL(node)->kind()) { + case PlanNode::Kind::kShowHosts: case PlanNode::Kind::kFilter: case PlanNode::Kind::kProject: case PlanNode::Kind::kSort: diff --git a/src/validator/test/ValidatorTestBase.cpp b/src/validator/test/ValidatorTestBase.cpp index 5330ae5169e3208fdd3677f5aeae20b60e8c2ee7..55fb6b236eeb6f5dd814e6ad47265dc651a6a5b4 100644 --- a/src/validator/test/ValidatorTestBase.cpp +++ b/src/validator/test/ValidatorTestBase.cpp @@ -43,6 +43,7 @@ namespace graph { case PlanNode::Kind::kStart: case PlanNode::Kind::kDedup: return Status::OK(); + case PlanNode::Kind::kShowHosts: case PlanNode::Kind::kDeleteEdges: case PlanNode::Kind::kDeleteVertices: case PlanNode::Kind::kIndexScan: