2017-03-22 23:38:43 +08:00
|
|
|
#pragma once
|
|
|
|
|
2017-06-21 17:29:13 +08:00
|
|
|
#include <gflags/gflags.h>
|
|
|
|
|
2017-09-27 20:02:24 +08:00
|
|
|
#include "data_structures/concurrent/concurrent_map.hpp"
|
2018-03-13 17:35:14 +08:00
|
|
|
#include "database/graph_db.hpp"
|
2017-03-22 23:38:43 +08:00
|
|
|
#include "database/graph_db_accessor.hpp"
|
|
|
|
#include "query/context.hpp"
|
2017-12-22 20:39:31 +08:00
|
|
|
#include "query/frontend/ast/ast.hpp"
|
2017-06-15 00:53:02 +08:00
|
|
|
#include "query/frontend/stripped.hpp"
|
2017-04-13 16:01:16 +08:00
|
|
|
#include "query/interpret/frame.hpp"
|
2018-01-26 23:22:59 +08:00
|
|
|
#include "query/plan/distributed.hpp"
|
2017-09-19 22:58:22 +08:00
|
|
|
#include "query/plan/operator.hpp"
|
2017-08-04 20:12:06 +08:00
|
|
|
#include "threading/sync/spinlock.hpp"
|
2017-07-15 01:33:45 +08:00
|
|
|
#include "utils/timer.hpp"
|
2017-03-22 23:38:43 +08:00
|
|
|
|
Flags cleanup and QueryEngine removal
Summary:
I started with cleaning flags up (removing unused ones, documenting undocumented ones). There were some flags to remove in `QueryEngine`. Seeing how we never use hardcoded queries (AFAIK last Mislav's testing also indicated they aren't faster then interpretation), when removing those unused flags the `QueryEngine` becomes obsolete. That means that a bunch of other stuff becomes obsolete, along with the hardcoded queries. So I removed it all (this has been discussed and approved on the daily).
Some flags that were previously undocumented in `docs/user_technical/installation` are now documented. The following flags are NOT documented and in my opinion should not be displayed when starting `./memgraph --help` (@mferencevic):
```
query_vertex_count_to_expand_existsing (from rule_based_planner.cpp)
query_max_plans (rule_based_planner.cpp)
```
If you think that another organization is needed w.r.t. flag visibility, comment.
@teon.banek: I had to remove some stuff from CMakeLists to make it buildable. Please review what I removed and clean up if necessary if/when this lands. If the needed changes are minor, you can also comment.
Reviewers: buda, mislav.bradac, teon.banek, mferencevic
Reviewed By: buda, mislav.bradac
Subscribers: pullbot, mferencevic, teon.banek
Differential Revision: https://phabricator.memgraph.io/D825
2017-09-22 22:17:09 +08:00
|
|
|
DECLARE_int32(query_plan_cache_ttl);
|
2017-06-15 00:53:02 +08:00
|
|
|
|
2018-03-13 17:35:14 +08:00
|
|
|
namespace distributed {
|
|
|
|
class PlanDispatcher;
|
|
|
|
}
|
|
|
|
|
2017-03-22 23:38:43 +08:00
|
|
|
namespace query {
|
|
|
|
|
2017-06-21 17:29:13 +08:00
|
|
|
class Interpreter {
|
2017-09-19 22:58:22 +08:00
|
|
|
private:
|
2018-03-15 22:00:43 +08:00
|
|
|
/// Encapsulates a plan for caching. Takes care of remote (worker) cache
|
|
|
|
/// updating in distributed memgraph.
|
2017-09-19 22:58:22 +08:00
|
|
|
class CachedPlan {
|
|
|
|
public:
|
2018-03-15 22:00:43 +08:00
|
|
|
/// Creates a cached plan and sends it to all the workers.
|
|
|
|
CachedPlan(plan::DistributedPlan distributed_plan, double cost,
|
|
|
|
distributed::PlanDispatcher *plan_dispatcher);
|
|
|
|
|
|
|
|
/// Removes the cached plan from all the workers.
|
|
|
|
~CachedPlan();
|
2017-09-19 22:58:22 +08:00
|
|
|
|
2018-01-26 23:22:59 +08:00
|
|
|
const auto &plan() const { return *distributed_plan_.master_plan; }
|
|
|
|
const auto &distributed_plan() const { return distributed_plan_; }
|
2017-09-19 22:58:22 +08:00
|
|
|
double cost() const { return cost_; }
|
2018-01-26 23:22:59 +08:00
|
|
|
const auto &symbol_table() const { return distributed_plan_.symbol_table; }
|
2017-09-19 22:58:22 +08:00
|
|
|
|
|
|
|
bool IsExpired() const {
|
2018-03-13 17:35:14 +08:00
|
|
|
return cache_timer_.Elapsed() >
|
Flags cleanup and QueryEngine removal
Summary:
I started with cleaning flags up (removing unused ones, documenting undocumented ones). There were some flags to remove in `QueryEngine`. Seeing how we never use hardcoded queries (AFAIK last Mislav's testing also indicated they aren't faster then interpretation), when removing those unused flags the `QueryEngine` becomes obsolete. That means that a bunch of other stuff becomes obsolete, along with the hardcoded queries. So I removed it all (this has been discussed and approved on the daily).
Some flags that were previously undocumented in `docs/user_technical/installation` are now documented. The following flags are NOT documented and in my opinion should not be displayed when starting `./memgraph --help` (@mferencevic):
```
query_vertex_count_to_expand_existsing (from rule_based_planner.cpp)
query_max_plans (rule_based_planner.cpp)
```
If you think that another organization is needed w.r.t. flag visibility, comment.
@teon.banek: I had to remove some stuff from CMakeLists to make it buildable. Please review what I removed and clean up if necessary if/when this lands. If the needed changes are minor, you can also comment.
Reviewers: buda, mislav.bradac, teon.banek, mferencevic
Reviewed By: buda, mislav.bradac
Subscribers: pullbot, mferencevic, teon.banek
Differential Revision: https://phabricator.memgraph.io/D825
2017-09-22 22:17:09 +08:00
|
|
|
std::chrono::seconds(FLAGS_query_plan_cache_ttl);
|
2017-09-19 22:58:22 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
2018-01-26 23:22:59 +08:00
|
|
|
plan::DistributedPlan distributed_plan_;
|
2017-09-19 22:58:22 +08:00
|
|
|
double cost_;
|
|
|
|
utils::Timer cache_timer_;
|
2018-03-13 17:35:14 +08:00
|
|
|
|
|
|
|
// Optional, only available in a distributed master.
|
|
|
|
distributed::PlanDispatcher *plan_dispatcher_{nullptr};
|
|
|
|
};
|
|
|
|
|
2018-03-15 22:00:43 +08:00
|
|
|
using PlanCacheT = ConcurrentMap<HashType, std::shared_ptr<CachedPlan>>;
|
|
|
|
|
2017-06-08 00:28:31 +08:00
|
|
|
public:
|
2017-12-22 20:39:31 +08:00
|
|
|
/**
|
2018-03-13 17:35:14 +08:00
|
|
|
* Encapsulates all what's necessary for the interpretation of a query
|
|
|
|
* into a single object that can be pulled (into the given Stream).
|
2017-12-22 20:39:31 +08:00
|
|
|
*/
|
|
|
|
class Results {
|
|
|
|
friend Interpreter;
|
2017-12-27 19:11:20 +08:00
|
|
|
Results(Context ctx, std::shared_ptr<CachedPlan> plan,
|
|
|
|
std::unique_ptr<query::plan::Cursor> cursor,
|
2017-12-22 20:39:31 +08:00
|
|
|
std::vector<Symbol> output_symbols, std::vector<std::string> header,
|
2018-03-15 22:00:43 +08:00
|
|
|
std::map<std::string, TypedValue> summary, PlanCacheT &plan_cache)
|
2017-12-22 20:39:31 +08:00
|
|
|
: ctx_(std::move(ctx)),
|
2017-12-27 19:11:20 +08:00
|
|
|
plan_(plan),
|
2017-12-22 20:39:31 +08:00
|
|
|
cursor_(std::move(cursor)),
|
|
|
|
frame_(ctx_.symbol_table_.max_position()),
|
|
|
|
output_symbols_(output_symbols),
|
|
|
|
header_(header),
|
|
|
|
summary_(summary),
|
|
|
|
plan_cache_(plan_cache) {}
|
2017-09-19 22:58:22 +08:00
|
|
|
|
2017-12-22 20:39:31 +08:00
|
|
|
public:
|
|
|
|
Results(const Results &) = delete;
|
|
|
|
Results(Results &&) = default;
|
|
|
|
Results &operator=(const Results &) = delete;
|
|
|
|
Results &operator=(Results &&) = default;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Make the interpreter perform a single Pull. Results (if they exists) are
|
|
|
|
* pushed into the given stream. On first Pull the header is written to the
|
|
|
|
* stream, on last the summary.
|
|
|
|
*
|
|
|
|
* @param stream - The stream to push the header, results and summary into.
|
|
|
|
* @return - If this Results is eligible for another Pull. If Pulling
|
|
|
|
* after `false` has been returned, the behavior is undefined.
|
|
|
|
* @tparam TStream - Stream type.
|
|
|
|
*/
|
|
|
|
template <typename TStream>
|
|
|
|
bool Pull(TStream &stream) {
|
|
|
|
if (!header_written_) {
|
|
|
|
stream.Header(header_);
|
|
|
|
header_written_ = true;
|
2017-10-10 23:57:15 +08:00
|
|
|
}
|
2017-07-20 00:14:59 +08:00
|
|
|
|
2017-12-22 20:39:31 +08:00
|
|
|
bool return_value = cursor_->Pull(frame_, ctx_);
|
2017-06-08 00:28:31 +08:00
|
|
|
|
2017-12-22 20:39:31 +08:00
|
|
|
if (return_value && !output_symbols_.empty()) {
|
|
|
|
std::vector<TypedValue> values;
|
|
|
|
values.reserve(output_symbols_.size());
|
|
|
|
for (const auto &symbol : output_symbols_) {
|
|
|
|
values.emplace_back(frame_[symbol]);
|
|
|
|
}
|
|
|
|
stream.Result(values);
|
|
|
|
}
|
2017-10-10 23:57:15 +08:00
|
|
|
|
2017-12-22 20:39:31 +08:00
|
|
|
if (!return_value) {
|
|
|
|
auto execution_time = execution_timer_.Elapsed();
|
|
|
|
summary_["plan_execution_time"] = execution_time.count();
|
|
|
|
stream.Summary(summary_);
|
|
|
|
|
|
|
|
if (ctx_.is_index_created_) {
|
2018-03-15 22:00:43 +08:00
|
|
|
auto access = plan_cache_.access();
|
|
|
|
for (auto &kv : access) {
|
|
|
|
access.remove(kv.first);
|
|
|
|
}
|
2017-12-22 20:39:31 +08:00
|
|
|
}
|
2017-06-05 18:44:18 +08:00
|
|
|
}
|
2017-12-22 20:39:31 +08:00
|
|
|
|
|
|
|
return return_value;
|
2017-06-05 18:44:18 +08:00
|
|
|
}
|
2017-05-23 17:28:41 +08:00
|
|
|
|
2017-12-22 20:39:31 +08:00
|
|
|
/** Calls Pull() until exhausted. */
|
|
|
|
template <typename TStream>
|
|
|
|
void PullAll(TStream &stream) {
|
|
|
|
while (Pull(stream)) continue;
|
|
|
|
}
|
2017-06-08 00:28:31 +08:00
|
|
|
|
2017-12-22 20:39:31 +08:00
|
|
|
private:
|
|
|
|
Context ctx_;
|
2017-12-27 19:11:20 +08:00
|
|
|
std::shared_ptr<CachedPlan> plan_;
|
2017-12-22 20:39:31 +08:00
|
|
|
std::unique_ptr<query::plan::Cursor> cursor_;
|
|
|
|
Frame frame_;
|
|
|
|
std::vector<Symbol> output_symbols_;
|
|
|
|
|
|
|
|
bool header_written_{false};
|
|
|
|
std::vector<std::string> header_;
|
|
|
|
std::map<std::string, TypedValue> summary_;
|
|
|
|
|
|
|
|
utils::Timer execution_timer_;
|
|
|
|
// Gets invalidated after if an index has been built.
|
2018-03-15 22:00:43 +08:00
|
|
|
PlanCacheT &plan_cache_;
|
2017-12-22 20:39:31 +08:00
|
|
|
};
|
2017-06-08 00:28:31 +08:00
|
|
|
|
2018-03-13 17:35:14 +08:00
|
|
|
explicit Interpreter(database::GraphDb &db);
|
2017-12-22 20:39:31 +08:00
|
|
|
Interpreter(const Interpreter &) = delete;
|
|
|
|
Interpreter &operator=(const Interpreter &) = delete;
|
|
|
|
Interpreter(Interpreter &&) = delete;
|
|
|
|
Interpreter &operator=(Interpreter &&) = delete;
|
2017-10-10 00:09:28 +08:00
|
|
|
|
2017-12-22 20:39:31 +08:00
|
|
|
/**
|
|
|
|
* Generates an Results object for the parameters. The resulting object
|
|
|
|
* can the be Pulled with it's results written to an arbitrary stream.
|
|
|
|
*/
|
2018-01-12 22:17:04 +08:00
|
|
|
Results operator()(const std::string &query,
|
|
|
|
database::GraphDbAccessor &db_accessor,
|
2017-12-22 20:39:31 +08:00
|
|
|
const std::map<std::string, TypedValue> ¶ms,
|
|
|
|
bool in_explicit_transaction);
|
2017-03-22 23:38:43 +08:00
|
|
|
|
2017-06-08 00:28:31 +08:00
|
|
|
private:
|
2018-03-15 22:00:43 +08:00
|
|
|
ConcurrentMap<HashType, AstTreeStorage> ast_cache_;
|
|
|
|
PlanCacheT plan_cache_;
|
|
|
|
std::atomic<int64_t> next_plan_id_{0};
|
|
|
|
// Antlr has singleton instance that is shared between threads. It is
|
|
|
|
// protected by locks inside of antlr. Unfortunately, they are not protected
|
|
|
|
// in a very good way. Once we have antlr version without race conditions we
|
|
|
|
// can remove this lock. This will probably never happen since antlr
|
|
|
|
// developers introduce more bugs in each version. Fortunately, we have cache
|
|
|
|
// so this lock probably won't impact performance much...
|
|
|
|
SpinLock antlr_lock_;
|
|
|
|
|
|
|
|
// Optional, not null only in a distributed master.
|
|
|
|
distributed::PlanDispatcher *plan_dispatcher_{nullptr};
|
|
|
|
|
2018-03-13 17:35:14 +08:00
|
|
|
// stripped query -> CachedPlan
|
|
|
|
std::shared_ptr<CachedPlan> QueryToPlan(const StrippedQuery &stripped,
|
|
|
|
Context &ctx);
|
2017-09-19 22:58:22 +08:00
|
|
|
// stripped query -> high level tree
|
|
|
|
AstTreeStorage QueryToAst(const StrippedQuery &stripped, Context &ctx);
|
|
|
|
|
|
|
|
// high level tree -> (logical plan, plan cost)
|
|
|
|
// AstTreeStorage and SymbolTable may be modified during planning.
|
|
|
|
std::pair<std::unique_ptr<plan::LogicalOperator>, double> MakeLogicalPlan(
|
2018-03-13 17:35:14 +08:00
|
|
|
AstTreeStorage &, Context &);
|
2017-06-08 00:28:31 +08:00
|
|
|
};
|
2017-04-26 22:12:39 +08:00
|
|
|
|
|
|
|
} // namespace query
|