blob: ef6dff4756ee49873cd3d9b82e253b14f515a3a2 [file] [log] [blame]
/**
* 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_