Cache required privileges for query execution

Summary: this should reduce parsing time for very simple queries.

Reviewers: teon.banek, mferencevic

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D1698
This commit is contained in:
Marin Tomic 2018-10-24 17:44:53 +02:00
parent 4f2a69b973
commit e4b661fe4a
2 changed files with 36 additions and 27 deletions

View File

@ -577,12 +577,9 @@ Interpreter::Results Interpreter::operator()(
ParsingContext parsing_context; ParsingContext parsing_context;
parsing_context.is_query_cached = true; parsing_context.is_query_cached = true;
AstStorage ast_storage; AstStorage ast_storage;
Query *ast_root = ParseQuery(stripped_query.query(), query_string,
parsing_context, &ast_storage, &db_accessor);
// TODO: Maybe cache required privileges to improve performance on very auto parsed_query = ParseQuery(stripped_query.query(), query_string,
// simple queries. parsing_context, &ast_storage, &db_accessor);
auto required_privileges = query::GetRequiredPrivileges(ast_root);
auto frontend_time = frontend_timer.Elapsed(); auto frontend_time = frontend_timer.Elapsed();
// Build summary. // Build summary.
@ -601,7 +598,7 @@ Interpreter::Results Interpreter::operator()(
// we must ensure it lives during the whole interpretation. // we must ensure it lives during the whole interpretation.
std::shared_ptr<CachedPlan> plan{nullptr}; std::shared_ptr<CachedPlan> plan{nullptr};
if (auto *cypher_query = dynamic_cast<CypherQuery *>(ast_root)) { if (auto *cypher_query = dynamic_cast<CypherQuery *>(parsed_query.query)) {
plan = CypherQueryToPlan(stripped_query.hash(), cypher_query, plan = CypherQueryToPlan(stripped_query.hash(), cypher_query,
std::move(ast_storage), std::move(ast_storage),
evaluation_context.parameters, &db_accessor); evaluation_context.parameters, &db_accessor);
@ -626,10 +623,11 @@ Interpreter::Results Interpreter::operator()(
auto cursor = plan->plan().MakeCursor(db_accessor); auto cursor = plan->plan().MakeCursor(db_accessor);
return Results(std::move(execution_context), plan, std::move(cursor), return Results(std::move(execution_context), plan, std::move(cursor),
output_symbols, header, summary, required_privileges); output_symbols, header, summary,
parsed_query.required_privileges);
} }
if (auto *explain_query = dynamic_cast<ExplainQuery *>(ast_root)) { if (auto *explain_query = dynamic_cast<ExplainQuery *>(parsed_query.query)) {
const std::string kExplainQueryStart = "explain "; const std::string kExplainQueryStart = "explain ";
CHECK(utils::StartsWith(stripped_query.query(), kExplainQueryStart)) CHECK(utils::StartsWith(stripped_query.query(), kExplainQueryStart))
<< "Expected stripped query to start with '" << kExplainQueryStart << "Expected stripped query to start with '" << kExplainQueryStart
@ -670,11 +668,12 @@ Interpreter::Results Interpreter::operator()(
auto cursor = plan->plan().MakeCursor(db_accessor); auto cursor = plan->plan().MakeCursor(db_accessor);
return Results(std::move(execution_context), plan, std::move(cursor), return Results(std::move(execution_context), plan, std::move(cursor),
output_symbols, header, summary, required_privileges); output_symbols, header, summary,
parsed_query.required_privileges);
} }
Callback callback; Callback callback;
if (auto *index_query = dynamic_cast<IndexQuery *>(ast_root)) { if (auto *index_query = dynamic_cast<IndexQuery *>(parsed_query.query)) {
if (in_explicit_transaction) { if (in_explicit_transaction) {
throw IndexInMulticommandTxException(); throw IndexInMulticommandTxException();
} }
@ -687,13 +686,14 @@ Interpreter::Results Interpreter::operator()(
}; };
callback = callback =
HandleIndexQuery(index_query, invalidate_plan_cache, &db_accessor); HandleIndexQuery(index_query, invalidate_plan_cache, &db_accessor);
} else if (auto *auth_query = dynamic_cast<AuthQuery *>(ast_root)) { } else if (auto *auth_query = dynamic_cast<AuthQuery *>(parsed_query.query)) {
if (in_explicit_transaction) { if (in_explicit_transaction) {
throw UserModificationInMulticommandTxException(); throw UserModificationInMulticommandTxException();
} }
callback = callback =
HandleAuthQuery(auth_query, auth_, evaluation_context, &db_accessor); HandleAuthQuery(auth_query, auth_, evaluation_context, &db_accessor);
} else if (auto *stream_query = dynamic_cast<StreamQuery *>(ast_root)) { } else if (auto *stream_query =
dynamic_cast<StreamQuery *>(parsed_query.query)) {
if (in_explicit_transaction) { if (in_explicit_transaction) {
throw StreamClauseInMulticommandTxException(); throw StreamClauseInMulticommandTxException();
} }
@ -720,7 +720,8 @@ Interpreter::Results Interpreter::operator()(
auto cursor = plan->plan().MakeCursor(db_accessor); auto cursor = plan->plan().MakeCursor(db_accessor);
return Results(std::move(execution_context), plan, std::move(cursor), return Results(std::move(execution_context), plan, std::move(cursor),
output_symbols, callback.header, summary, required_privileges); output_symbols, callback.header, summary,
parsed_query.required_privileges);
} }
std::shared_ptr<Interpreter::CachedPlan> Interpreter::CypherQueryToPlan( std::shared_ptr<Interpreter::CachedPlan> Interpreter::CypherQueryToPlan(
@ -742,11 +743,10 @@ std::shared_ptr<Interpreter::CachedPlan> Interpreter::CypherQueryToPlan(
.first->second; .first->second;
} }
Query *Interpreter::ParseQuery(const std::string &stripped_query, Interpreter::ParsedQuery Interpreter::ParseQuery(
const std::string &original_query, const std::string &stripped_query, const std::string &original_query,
const ParsingContext &context, const ParsingContext &context, AstStorage *ast_storage,
AstStorage *ast_storage, database::GraphDbAccessor *db_accessor) {
database::GraphDbAccessor *db_accessor) {
if (!context.is_query_cached) { if (!context.is_query_cached) {
// Parse original query into antlr4 AST. // Parse original query into antlr4 AST.
auto parser = [&] { auto parser = [&] {
@ -757,7 +757,8 @@ Query *Interpreter::ParseQuery(const std::string &stripped_query,
// Convert antlr4 AST into Memgraph AST. // Convert antlr4 AST into Memgraph AST.
frontend::CypherMainVisitor visitor(context, ast_storage, db_accessor); frontend::CypherMainVisitor visitor(context, ast_storage, db_accessor);
visitor.visit(parser->tree()); visitor.visit(parser->tree());
return visitor.query(); return ParsedQuery{visitor.query(),
query::GetRequiredPrivileges(visitor.query())};
} }
auto stripped_query_hash = fnv(stripped_query); auto stripped_query_hash = fnv(stripped_query);
@ -783,17 +784,19 @@ Query *Interpreter::ParseQuery(const std::string &stripped_query,
} }
}(); }();
// Convert antlr4 AST into Memgraph AST. // Convert antlr4 AST into Memgraph AST.
CachedQuery cached_query; AstStorage cached_ast_storage;
frontend::CypherMainVisitor visitor(context, &cached_query.ast_storage, frontend::CypherMainVisitor visitor(context, &cached_ast_storage,
db_accessor); db_accessor);
visitor.visit(parser->tree()); visitor.visit(parser->tree());
cached_query.query = visitor.query(); CachedQuery cached_query{std::move(cached_ast_storage), visitor.query(),
query::GetRequiredPrivileges(visitor.query())};
// Cache it. // Cache it.
ast_it = ast_it =
ast_cache_accessor.insert(stripped_query_hash, std::move(cached_query)) ast_cache_accessor.insert(stripped_query_hash, std::move(cached_query))
.first; .first;
} }
return ast_it->second.query->Clone(*ast_storage); return ParsedQuery{ast_it->second.query->Clone(*ast_storage),
ast_it->second.required_privileges};
} }
std::unique_ptr<LogicalPlan> Interpreter::MakeLogicalPlan( std::unique_ptr<LogicalPlan> Interpreter::MakeLogicalPlan(

View File

@ -60,6 +60,12 @@ class Interpreter {
struct CachedQuery { struct CachedQuery {
AstStorage ast_storage; AstStorage ast_storage;
Query *query; Query *query;
std::vector<AuthQuery::Privilege> required_privileges;
};
struct ParsedQuery {
Query *query;
std::vector<AuthQuery::Privilege> required_privileges;
}; };
using PlanCacheT = ConcurrentMap<HashType, std::shared_ptr<CachedPlan>>; using PlanCacheT = ConcurrentMap<HashType, std::shared_ptr<CachedPlan>>;
@ -199,10 +205,10 @@ class Interpreter {
const Parameters &parameters, database::GraphDbAccessor *db_accessor); const Parameters &parameters, database::GraphDbAccessor *db_accessor);
// stripped query -> high level tree // stripped query -> high level tree
Query *ParseQuery(const std::string &stripped_query, ParsedQuery ParseQuery(const std::string &stripped_query,
const std::string &original_query, const std::string &original_query,
const ParsingContext &context, AstStorage *ast_storage, const ParsingContext &context, AstStorage *ast_storage,
database::GraphDbAccessor *db_accessor); database::GraphDbAccessor *db_accessor);
}; };
} // namespace query } // namespace query