2017-03-22 23:38:43 +08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <ctime>
|
2017-06-05 18:44:18 +08:00
|
|
|
#include <limits>
|
2017-03-22 23:38:43 +08:00
|
|
|
|
2017-06-21 17:29:13 +08:00
|
|
|
#include <gflags/gflags.h>
|
|
|
|
#include <glog/logging.h>
|
|
|
|
|
2017-09-27 20:02:24 +08:00
|
|
|
#include "data_structures/concurrent/concurrent_map.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"
|
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
|
|
|
|
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:
|
|
|
|
class CachedPlan {
|
|
|
|
public:
|
|
|
|
CachedPlan(std::unique_ptr<plan::LogicalOperator> plan, double cost,
|
|
|
|
SymbolTable symbol_table, AstTreeStorage storage)
|
|
|
|
: plan_(std::move(plan)),
|
|
|
|
cost_(cost),
|
|
|
|
symbol_table_(symbol_table),
|
|
|
|
ast_storage_(std::move(storage)) {}
|
|
|
|
|
|
|
|
const auto &plan() const { return *plan_; }
|
|
|
|
double cost() const { return cost_; }
|
|
|
|
const auto &symbol_table() const { return symbol_table_; }
|
|
|
|
|
|
|
|
bool IsExpired() const {
|
|
|
|
auto elapsed = cache_timer_.Elapsed();
|
|
|
|
return std::chrono::duration_cast<std::chrono::seconds>(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:
|
|
|
|
std::unique_ptr<plan::LogicalOperator> plan_;
|
|
|
|
double cost_;
|
|
|
|
SymbolTable symbol_table_;
|
|
|
|
AstTreeStorage ast_storage_;
|
|
|
|
utils::Timer cache_timer_;
|
|
|
|
};
|
|
|
|
|
2017-06-08 00:28:31 +08:00
|
|
|
public:
|
2017-12-22 20:39:31 +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).
|
|
|
|
*/
|
|
|
|
class Results {
|
|
|
|
friend Interpreter;
|
|
|
|
Results(Context ctx, std::unique_ptr<query::plan::Cursor> cursor,
|
|
|
|
std::vector<Symbol> output_symbols, std::vector<std::string> header,
|
|
|
|
std::map<std::string, TypedValue> summary,
|
|
|
|
ConcurrentMap<HashType, std::shared_ptr<CachedPlan>> &plan_cache)
|
|
|
|
: ctx_(std::move(ctx)),
|
|
|
|
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_) {
|
|
|
|
// If index is created we invalidate cache so that we can try to
|
|
|
|
// generate better plan with that cache.
|
|
|
|
auto accessor = plan_cache_.access();
|
|
|
|
for (const auto &cached_plan : accessor) {
|
|
|
|
accessor.remove(cached_plan.first);
|
|
|
|
}
|
|
|
|
}
|
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_;
|
|
|
|
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.
|
|
|
|
ConcurrentMap<HashType, std::shared_ptr<CachedPlan>> &plan_cache_;
|
|
|
|
};
|
2017-06-08 00:28:31 +08:00
|
|
|
|
2017-12-22 20:39:31 +08:00
|
|
|
Interpreter() = default;
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
Results operator()(const std::string &query, GraphDbAccessor &db_accessor,
|
|
|
|
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:
|
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(
|
|
|
|
AstTreeStorage &, const GraphDbAccessor &, Context &);
|
|
|
|
|
2017-09-13 22:48:46 +08:00
|
|
|
ConcurrentMap<HashType, AstTreeStorage> ast_cache_;
|
2017-09-19 22:58:22 +08:00
|
|
|
ConcurrentMap<HashType, std::shared_ptr<CachedPlan>> plan_cache_;
|
2017-08-03 19:28:50 +08:00
|
|
|
// 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_;
|
2017-06-08 00:28:31 +08:00
|
|
|
};
|
2017-04-26 22:12:39 +08:00
|
|
|
|
|
|
|
} // namespace query
|