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:
parent
4f2a69b973
commit
e4b661fe4a
@ -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(
|
||||||
|
@ -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 ¶meters, database::GraphDbAccessor *db_accessor);
|
const Parameters ¶meters, 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
|
||||||
|
Loading…
Reference in New Issue
Block a user