From 99e27cb7e9b915aeefa3a85a2e7e8e052b834964 Mon Sep 17 00:00:00 2001 From: Teon Banek Date: Thu, 13 Jul 2017 12:57:55 +0200 Subject: [PATCH] Add limiting number of generated plans for a query Reviewers: florijan, mislav.bradac Reviewed By: mislav.bradac Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D548 --- src/query/plan/variable_start_planner.cpp | 44 +++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/query/plan/variable_start_planner.cpp b/src/query/plan/variable_start_planner.cpp index 5481cbc86..7b582980c 100644 --- a/src/query/plan/variable_start_planner.cpp +++ b/src/query/plan/variable_start_planner.cpp @@ -1,5 +1,16 @@ #include "query/plan/planner.hpp" +#include + +#include +#include + +#include "utils/flag_validation.hpp" + +DEFINE_VALIDATED_uint64( + query_max_plans, 1000U, "Maximum number of generated plans for a query", + FLAG_IN_RANGE(1, std::numeric_limits::max())); + namespace query::plan { namespace { @@ -153,6 +164,37 @@ std::vector> CartesianProduct( return products; } +template +std::uint64_t CartesianProductSize(const std::vector> &sets) { + std::uint64_t n = 1U; + for (const auto &set : sets) { + if (set.empty()) { + return 0U; + } + std::uint64_t new_n = n * set.size(); + if (new_n < n || new_n < set.size()) { + DLOG(WARNING) << "Unsigned wrap-around when calculating expected size of " + "Cartesian product."; + return std::numeric_limits::max(); + } + n = new_n; + } + return n; +} + +// Shortens variants if their Cartesian product exceeds the query_max_plans +// flag. +template +void LimitPlans(std::vector> &variants) { + size_t to_shorten = 0U; + while (CartesianProductSize(variants) > FLAGS_query_max_plans) { + if (variants[to_shorten].size() > 1U) { + variants[to_shorten].pop_back(); + } + to_shorten = (to_shorten + 1U) % variants.size(); + } +} + // Similar to VaryMatchingStart, but varies the starting nodes for all given // matchings. After all matchings produce multiple alternative starts, the // Cartesian product of all of them is returned. @@ -162,6 +204,7 @@ std::vector> VaryMultiMatchingStarts( for (const auto &matching : matchings) { variants.emplace_back(VaryMatchingStart(matching, symbol_table)); } + LimitPlans(variants); return CartesianProduct(variants.cbegin(), variants.cend()); } @@ -232,6 +275,7 @@ std::vector> VaryQueryMatching( alternative_query_parts.emplace_back( VaryQuertPartMatching(query_part, symbol_table)); } + LimitPlans(alternative_query_parts); return CartesianProduct(alternative_query_parts.cbegin(), alternative_query_parts.cend()); }