| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| **/ |
| |
| #ifndef QUICKSTEP_QUERY_OPTIMIZER_QUERY_PLAN_HPP_ |
| #define QUICKSTEP_QUERY_OPTIMIZER_QUERY_PLAN_HPP_ |
| |
| #include <unordered_map> |
| #include <utility> |
| |
| #include "relational_operators/RelationalOperator.hpp" |
| #include "utility/DAG.hpp" |
| #include "utility/Macros.hpp" |
| |
| namespace quickstep { |
| |
| /** \addtogroup QueryOptimizer |
| * @{ |
| */ |
| |
| /** |
| * @brief A plan to execute a query. |
| **/ |
| class QueryPlan { |
| public: |
| typedef DAG<RelationalOperator, bool>::size_type_nodes DAGNodeIndex; |
| |
| /** |
| * @brief Constructor. |
| */ |
| QueryPlan() {} |
| |
| /** |
| * @brief Create a relational operator node in the plan, and set its node |
| * index. |
| * |
| * @param relational_operator The relational operator to be added to the plan. |
| * @return The node index in the exeuciton plan. |
| */ |
| inline DAGNodeIndex addRelationalOperator(RelationalOperator *relational_operator) { |
| const DAGNodeIndex node_index = dag_operators_.createNode(relational_operator); |
| relational_operator->setOperatorIndex(node_index); |
| return node_index; |
| } |
| |
| /** |
| * @brief Creates a link from \p producer_operator_index to \p consumer_operator_index |
| * in the DAG. |
| * |
| * @param consumer_operator_index The index of the consumer operator. |
| * @param producer_operator_index The index of the producer operator. |
| * @param is_pipeline_breaker True if the result from the producer cannot be |
| * pipelined to the consumer, otherwise false. |
| */ |
| inline void addDirectDependency(DAGNodeIndex consumer_operator_index, |
| DAGNodeIndex producer_operator_index, |
| bool is_pipeline_breaker) { |
| dag_operators_.createLink(producer_operator_index, consumer_operator_index, is_pipeline_breaker); |
| } |
| |
| /** |
| * @brief Creates a link or upgrades the existing link from \p producer_operator_index |
| * to \p consumer_operator_index in the DAG. |
| * |
| * Depending on whether there is an existing link from \p producer_operator_index |
| * to \p consumer_operator_index: |
| * - Case 1, no existing link: |
| * Creates a link with metadata set to is_pipeline_breaker. |
| * - Case 2, existing link with metadata \p m: |
| * Set m = (m | is_pipeline_break). |
| * |
| * @param consumer_operator_index The index of the consumer operator. |
| * @param producer_operator_index The index of the producer operator. |
| * @param is_pipeline_breaker True if the result from the producer cannot be |
| * pipelined to the consumer, otherwise false. |
| */ |
| inline void addOrUpgradeDirectDependency(DAGNodeIndex consumer_operator_index, |
| DAGNodeIndex producer_operator_index, |
| bool is_pipeline_breaker) { |
| const auto &dependents = dag_operators_.getDependents(producer_operator_index); |
| const auto consumer_it = dependents.find(consumer_operator_index); |
| if (consumer_it == dependents.end()) { |
| dag_operators_.createLink(producer_operator_index, |
| consumer_operator_index, |
| is_pipeline_breaker); |
| } else { |
| dag_operators_.setLinkMetadata(producer_operator_index, |
| consumer_operator_index, |
| consumer_it->second | is_pipeline_breaker); |
| } |
| } |
| |
| /** |
| * @brief Creates dependencies for a DropTable operator with index |
| * \p drop_operator_index. If \p producer_operator_index |
| * has any dependent, creates a link from \p drop_operator_index |
| * to each dependent of \p producer_operator_index in the DAG; |
| * otherwise, create a direct link between \p drop_operator_index |
| * and \p producer_operator_index. |
| * |
| * @param dependent_operator_index The index of the DropTable operator node. |
| * @param dependency_operator_index The index of the operator node that outputs |
| * the relation to be dropped by the operator |
| * at \p dependent_operator_index. |
| */ |
| inline void addDependenciesForDropOperator(DAGNodeIndex drop_operator_index, |
| DAGNodeIndex producer_operator_index) { |
| const std::unordered_map<DAGNodeIndex, bool> &direct_dependents = |
| dag_operators_.getDependents(producer_operator_index); |
| if (!direct_dependents.empty()) { |
| for (const std::pair<const DAGNodeIndex, bool> &direct_dependent : direct_dependents) { |
| dag_operators_.createLink(direct_dependent.first, |
| drop_operator_index, |
| true /* is_pipeline_breaker */); |
| } |
| } else { |
| dag_operators_.createLink(producer_operator_index, |
| drop_operator_index, |
| true /* is_pipeline_breaker */); |
| } |
| } |
| |
| /** |
| * @return The DAG query plan. |
| */ |
| const DAG<RelationalOperator, bool>& getQueryPlanDAG() const { |
| return dag_operators_; |
| } |
| |
| /** |
| * @return The DAG query plan. |
| */ |
| DAG<RelationalOperator, bool>* getQueryPlanDAGMutable() { |
| return &dag_operators_; |
| } |
| |
| private: |
| // A false value of the second template argument indicates that the |
| // link between two RelationalOperators is not a pipeline breaker. |
| // while a true value indicates that the link is a pipeline |
| // breaker. Streamed data won't move through pipeline breaker links. |
| DAG<RelationalOperator, bool> dag_operators_; |
| |
| DISALLOW_COPY_AND_ASSIGN(QueryPlan); |
| }; |
| |
| /** @} */ |
| |
| } // namespace quickstep |
| |
| #endif // QUICKSTEP_QUERY_OPTIMIZER_QUERY_PLAN_HPP_ |