blob: bd9aac277dffd7a05f7db8ea5a6a22dadcad9423 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// 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.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
#ifndef REQGEN_H
#define REQGEN_H
/* -*-C++-*-
*****************************************************************************
*
* File: ReqGen.h
* Description: Class to generate required physical properties for a
* child of a RelExpr node. Something like an intelligent
* constructor for class ReqdPhysicalProperties.
*
* Created: 2/5/98
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "PhyProp.h"
// -----------------------------------------------------------------------
// The following classes are defined in this file.
// -----------------------------------------------------------------------
class RequirementGenerator;
// -----------------------------------------------------------------------
// forward references
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// class RequirementGenerator
//
// This class is used to generate a new ReqdPhysicalProperty object
// for a particular group from existing and new requirements.
// The RequirementGenerator provides intelligent methods for adding
// and removing requirements. The methods are also easy to use, making
// the code implementations of RelExpr::createContextForAChild easier. The
// RequirementGenerator performs all necessary checks that are needed
// to provide consistent and feasible requirements to a child group.
// Typically, a piece of code that needs to form a requirement will
// do this in three steps:
// - create an object of class RequirementGenerator (may be on the stack)
// and possibly pass in some starting requirements
// - add or remove requirements
// - generate a ReqdPhysicalProperty object, if requirements are feasible
// Example: GroupByAggr::createContextForAChild
// {
// RequirementGenerator rg(child(0),<my Reqirements from context>);
//
// if (<this is not a partial grby>)
// rg.addPartitioningKey(<myGroupingCols>);
//
// if (<this is a sort groupby>)
// rg.addArrangement(<myGroupingCols>);
//
// if (<this operator runs optimally in parallel>)
// rg.addNumOfPartitions(<optimal # of parts>);
//
// if (rg.isFeasible())
// {
// ReqdPhysicalProperty rppForChild = rg.produceRequirement();
// <add cost limit and share context>
// }
// }
// -----------------------------------------------------------------------
class RequirementGenerator
{
public:
// ---------------------------------------------------------------------
// constructor: it takes a child of a RelExpr to get the child's
// group attributes, and it takes an optional ReqdPhysicalProperty
// object with starting requirements (which can be selectively
// removed before adding other ones)
// ---------------------------------------------------------------------
RequirementGenerator(
const ExprGroupId &groupForRequirement,
const ReqdPhysicalProperty *startRequirements = NULL);
// ---------------------------------------------------------------------
// accessor methods
// ---------------------------------------------------------------------
inline Lng32 getCountOfPipelines() const
{ return availableCPUs_ * pipelinesPerCPU_; }
inline Lng32 getCountOfAvailableCPUs() const { return availableCPUs_; }
inline const ReqdPhysicalProperty* getStartRequirements() const
{ return startRequirements_; }
// ---------------------------------------------------------------------
// Methods to add new requirements to the RequirementGenerator.
// The methods may be called multiple times, and the requirements
// get added to the start requirements passed in the constructor
// and the requirements. Use the checkFeasibility() method to
// find out whether the different requirements contradict each other.
// ---------------------------------------------------------------------
void addSortKey(const ValueIdList &additionalSortKey,
SortOrderTypeEnum sortOrderTypeReq = INCOMPATIBLE_SOT,
PartitioningRequirement* dp2SortOrderPartReq = NULL);
void addArrangement(const ValueIdSet &additionalArrangementParam,
SortOrderTypeEnum sortOrderTypeReq = INCOMPATIBLE_SOT,
PartitioningRequirement* dp2SortOrderPartReq = NULL);
void addSortOrderTypeReq(SortOrderTypeEnum sortOrderTypeReq,
PartitioningRequirement* dp2SortOrderPartReq = NULL);
void addPartitioningKey(const ValueIdSet &partKey);
void addNumOfPartitions(Lng32 newNumberOfPartitions,
float newNumOfPartsAllowedDeviation =
CURRSTMT_OPTDEFAULTS->numberOfPartitionsDeviation());
void addPartRequirement(PartitioningRequirement *pr);
void addLocationRequirement(PlanExecutionEnum loc);
void addLogicalPartRequirement(LogicalPartitioningRequirement *pr);
void addPushDownRequirement(const PushDownRequirement* pdr)
{ pushDownRequirement_ = pdr; };
void addNoEspExchangeRequirement();
void addOcbCostingRequirement();
// ---------------------------------------------------------------------
// Methods to completely remove certain parts of the requirement.
// These methods remove both the requirements that came from the
// start requirements and those that were added.
// ---------------------------------------------------------------------
void removeSortKey();
void removeExtraSortKeys();
void removeArrangement();
void removeSortOrderTypeReq();
void removeAllPartitioningRequirements();
void removePushDownRequirement() { pushDownRequirement_ = 0; };
// ---------------------------------------------------------------------
// Methods to replace or modify requirements.
// ---------------------------------------------------------------------
void replaceLocationRequirement(PlanExecutionEnum loc);
void setLogicalOrderOrArrangementFlag(NABoolean newValue)
{ logicalOrderOrArrangement_ = newValue; }
// ---------------------------------------------------------------------
// Methods that help in generating "good" requirements in cases where
// the RelExpr generating them has some freedom (e.g. by removing some
// equi-join columns from a required arrangement or partitioning key).
// These methods side-effect their parameters and remove some
// parts of them that are in conflict with existing requirements.
// ---------------------------------------------------------------------
// makeSortKeyFeasible can be used to make an sort key feasible
void makeSortKeyFeasible(ValueIdList &proposedSortKey);
// makeArrangementFeasible can be used to make an arrangement feasible
void makeArrangementFeasible(ValueIdSet &proposedArrangement);
// modify the number of required partitions such that it doesn't conflict
void makeNumOfPartsFeasible(Lng32 &proposedNumOfParts,
float *proposedNumOfPartsAllowedDeviation = NULL);
// ---------------------------------------------------------------------
// Methods to do consistency checking and to get information about
// how the requirements look so far
// ---------------------------------------------------------------------
NABoolean checkFeasibility();
// ---------------------------------------------------------------------
// The final method to produce a ReqdPhysicalProperty object or a NULL
// pointer if the requirements are not feasible (contradictory).
// ---------------------------------------------------------------------
ReqdPhysicalProperty *produceRequirement();
static void initSortOrderTypeReqCompTab();
SortOrderTypeEnum determineCompatibleSortOrderTypeReq(
SortOrderTypeEnum otherSortOrderTypeReq) const;
// Add the skew data handling requirement. If a fully specified partition
// rquirement is to be added, it must be added earlier than the skew
// requirement and any skewness property specified in that partition
// requirement is overwritten by this skew requirement.
void addSkewRequirement(skewProperty::skewDataHandlingEnum,
SkewedValueList* skList,
NABoolean broadcastOneRow);
void removeSkewRequirement() { skewPropertyAdded_ = FALSE; };
// Check that the added skew requirement can be made compatible with
// what exists in the partR, and if so, modify partR so that the skew
// requirement is properly represented in partR.
void makeSkewReqFeasible(PartitioningRequirement* partR);
private:
// private methods
void processStartRequirements();
void producePartitioningRequirements();
void checkCompatibilityWithGroupAttributes();
ValueIdSet combinePartKeysHeuristically(
const ValueIdSet& partKey1,
const ValueIdSet& partKey2);
// private data members
static THREAD_P LookupTable<SortOrderTypeEnum>* sortOrderTypeReqCompTab_;
const ReqdPhysicalProperty *startRequirements_;
const GroupAttributes *ga_;
// data members that store the overall state of requirement generation
NABoolean stillFeasible_;
NABoolean startRequirementsHaveBeenProcessed_;
ReqdPhysicalProperty *generatedRequirement_;
PartitioningRequirement *generatedPartitioningRequirement_;
NABoolean generatedPartitioningReqIsValid_;
// Things that got added to the requirements (either through the add
// methods above or through the start requirements in the constructor)
// Also there are some flags that remember things still to be done,
// such as adding start requirements and checking.
// order
ValueIdList *addedSortKey_;
NABoolean sortKeyIsUnique_;
NABoolean removeStartSortKey_;
// simplified columns from required orders
ValueIdList simpleSortCols_;
// arrangement
ValueIdSet *addedArrangement_;
NABoolean removeStartArrangement_;
// simplified columns from required arrangements
ValueIdSet simpleArrangedCols_;
// order or arrangement
NABoolean logicalOrderOrArrangement_;
// partitioning
// "fuzzy" requirements
ValueIdSet addedPartKey_;
NABoolean partKeyHasBeenAdded_;
Lng32 addedNumberOfPartitions_;
float addedNumOfPartsAllowedDeviation_;
// fully specified partitioning requirement
PartitioningRequirement *addedPartitioningRequirement_;
NABoolean removeStartPartitioningRequirements_;
// location
PlanExecutionEnum addedLocation_;
NABoolean locationHasBeenAdded_;
NABoolean removeStartLocation_;
// sort order type
SortOrderTypeEnum addedSortOrderTypeReq_;
PartitioningRequirement* addedDp2SortOrderPartReq_;
// the other requirements that we don't check
Lng32 availableCPUs_;
Lng32 pipelinesPerCPU_;
const CostWeight *costWeight_;
const PerformanceGoal *perfGoal_;
LogicalPartitioningRequirement *logicalPartReq_;
const PushDownRequirement* pushDownRequirement_;
skewProperty addedSkewProperty_;
NABoolean skewPropertyAdded_;
NABoolean requireNoESPExchange_;
NABoolean requireOcbEnabledCosting_;
NABoolean requireHash2Only_;
}; // RequirementGenerator
#endif