/*##############################################################################
Copyright (C) 2011 HPCC Systems.
All rights reserved. This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
############################################################################## */
#ifndef __HQLRESOURCE_IPP_
#define __HQLRESOURCE_IPP_
#include "hqlresource.hpp"
enum ResourceType {
//Slave specific
RESslavememory,
RESslavesocket,
//Master specific
RESmastermemory,
RESmastersocket,
//General
REShashdist,
RESheavy,
RESactivities,
RESmax
};
class CResourceOptions
{
public:
CResourceOptions() { state.updateSequence = 0; }
IHqlExpression * createSpillName(bool isGraphResult);
void noteGraphsChanged() { state.updateSequence++; }
public:
unsigned filteredSpillThreshold;
unsigned minimizeSpillSize;
bool allowThroughSpill;
bool allowThroughResult;
bool cloneFilteredIndex;
bool spillSharedConditionals;
bool shareDontExpand;
bool useGraphResults;
bool noConditionalLinks;
bool minimiseSpills;
bool hoistResourced;
bool isChildQuery;
bool groupedChildIterators;
bool allowSplitBetweenSubGraphs;
bool supportsChildQueries;
bool preventKeyedSplit;
bool preventSteppedSplit;
bool mangleSpillNameWithWuid;
bool minimizeSkewBeforeSpill;
bool useMpForDistribute;
bool expandSingleConstRow;
bool createSpillAsDataset;
bool useLinkedRawIterator;
bool optimizeSharedInputs;
bool combineSiblings;
IHqlExpression * graphIdExpr;
unsigned nextResult;
unsigned clusterSize;
StringAttr filenameMangler;
ClusterType targetClusterType;
//Used
struct
{
unsigned updateSequence;
} state;
inline bool canSplit() const { return targetClusterType != HThorCluster; }
inline bool checkResources() const { return isThorCluster(targetClusterType) && !isChildQuery; }
inline bool targetRoxie() const { return targetClusterType == RoxieCluster; }
inline bool targetThor() const { return targetClusterType == ThorCluster || targetClusterType == ThorLCRCluster; }
};
struct CResources : public CInterface
{
public:
CResources(unsigned _clusterSize) { clusterSize = _clusterSize; _clear(resource); }
CResources(const CResources & other) { clusterSize = other.clusterSize; set(other); }
void add(const CResources & other);
bool addExceeds(const CResources & other, const CResources & limit) const;
void clear() { _clear(resource); }
bool exceeds(const CResources & limit) const;
StringBuffer & getExceedsReason(StringBuffer & reasonText, const CResources & other, const CResources & limit) const;
void maximize(const CResources & other);
CResources & set(ResourceType kind, unsigned value) { resource[kind] = value; return *this; }
CResources & set(const CResources & other) { memcpy(&resource, &other.resource, sizeof(resource)); return *this; }
CResources & setLightweight();
CResources & setHeavyweight();
CResources & setManyToManySockets(unsigned num);
CResources & setManyToMasterSockets(unsigned num);
void sub(const CResources & other);
public:
unsigned resource[RESmax];
unsigned clusterSize;
};
enum LinkKind { UnconditionalLink, ConditionalLink, SequenceLink };
class ResourceGraphInfo;
class ResourceGraphLink : public CInterface
{
public:
ResourceGraphLink(ResourceGraphInfo * _sourceGraph, IHqlExpression * _sourceNode, ResourceGraphInfo * _sinkGraph, IHqlExpression * _sinkNode, LinkKind _kind);
~ResourceGraphLink();
virtual void changeSourceGraph(ResourceGraphInfo * newGraph);
virtual void changeSinkGraph(ResourceGraphInfo * newGraph);
virtual bool isRedundantLink();
virtual bool isDependency() { return false; }
protected:
void trace(const char * name);
public:
Owned sourceGraph;
Owned sinkGraph;
OwnedHqlExpr sourceNode;
OwnedHqlExpr sinkNode;
byte linkKind;
};
class ResourceGraphDependencyLink : public ResourceGraphLink
{
public:
ResourceGraphDependencyLink(ResourceGraphInfo * _sourceGraph, IHqlExpression * _sourceNode, ResourceGraphInfo * _sinkGraph, IHqlExpression * _sinkNode);
virtual void changeSourceGraph(ResourceGraphInfo * newGraph);
virtual void changeSinkGraph(ResourceGraphInfo * newGraph);
virtual bool isRedundantLink() { return false; }
virtual bool isDependency() { return true; }
};
typedef CIArrayOf ResourceGraphArray;
typedef CopyCIArrayOf GraphLinkArray;
class ResourceGraphInfo : public CInterface
{
public:
ResourceGraphInfo(CResourceOptions * _options);
~ResourceGraphInfo();
bool addCondition(IHqlExpression * condition);
bool allocateResources(const CResources & value, const CResources & limit);
bool containsActiveSinks();
unsigned getDepth();
void getMergeFailReason(StringBuffer & reasonText, ResourceGraphInfo * otherGraph, const CResources & limit);
bool hasSameConditions(ResourceGraphInfo & other);
bool isDependentOn(ResourceGraphInfo & other, bool allowDirect);
bool isVeryCheap();
bool mergeInSibling(ResourceGraphInfo & other, const CResources & limit);
bool mergeInSource(ResourceGraphInfo & other, const CResources & limit, bool isConditionalLink);
void removeResources(const CResources & value);
bool isSharedInput(IHqlExpression * expr);
void addSharedInput(IHqlExpression * expr, IHqlExpression * mapped);
IHqlExpression * queryMappedSharedInput(IHqlExpression * expr);
protected:
void display();
void mergeGraph(ResourceGraphInfo & other, bool isConditionalLink, bool mergeConditions);
bool evalDependentOn(ResourceGraphInfo & other, bool ignoreSources);
public:
OwnedHqlExpr createdGraph;
CResourceOptions * options;
GraphLinkArray dependsOn; // NB: These do no link....
GraphLinkArray sources;
GraphLinkArray sinks;
HqlExprArray conditions;
HqlExprArray sharedInputs;
HqlExprArray unbalancedExternalSources;
HqlExprArray balancedExternalSources;
CResources resources;
unsigned depth;
unsigned depthSequence;
bool beenResourced;
bool isUnconditional;
bool mergedConditionSource;
bool hasConditionSource;
bool isDead;
bool startedGeneratingResourced;
bool inheritedExpandedDependencies;
struct
{
ResourceGraphInfo * other;
unsigned updateSequence;
bool ignoreSources;
bool value;
} cachedDependent;
};
class ResourcerInfo : public CInterface, public IInterface
{
public:
enum { PathUnknown, PathConditional, PathUnconditional };
ResourcerInfo(IHqlExpression * _original, CResourceOptions * _options);
IMPLEMENT_IINTERFACE
IHqlExpression * createSpilledRead(IHqlExpression * spillReason);
IHqlExpression * createTransformedExpr(IHqlExpression * expr);
bool addCondition(IHqlExpression * condition);
bool alwaysExpand();
unsigned calcNumConditionalUses();
bool expandRatherThanSpill(bool noteOtherSpills);
bool expandRatherThanSplit();
bool isExternalSpill();
bool neverCommonUp();
bool isSplit();
bool isSpilledWrite();
bool okToSpillThrough();
void noteUsedFromChild() { linkedFromChild = true; outputToUseForSpill = NULL; }
unsigned numInternalUses() { return numUses - numExternalUses - aggregates.ordinality(); }
unsigned numSplitPaths();
void setConditionSource(IHqlExpression * condition, bool isFirst);
//hthor - don't merge anything to a global result because we don't allow splitters.
inline bool preventMerge() { return !options->canSplit() && useGlobalResult(); }
inline bool isUnconditional() { return (pathToExpr == ResourcerInfo::PathUnconditional); }
inline bool isConditionExpr()
{
switch (original->getOperator())
{
case no_if:
return true;
case no_output:
case no_buildindex:
return isUpdatedConditionally(original);
}
return false;
}
protected:
bool spillSharesSplitter();
bool useGraphResult();
bool useGlobalResult();
IHqlExpression * createAggregation(IHqlExpression * expr);
IHqlExpression * createSpilledWrite(IHqlExpression * transformed);
IHqlExpression * createSpiller(IHqlExpression * transformed, bool reuseSplitter);
IHqlExpression * createSplitter(IHqlExpression * transformed);
protected:
void addSpillFlags(HqlExprArray & args, bool isRead);
IHqlExpression * createSpillName();
IHqlExpression * wrapRowOwn(IHqlExpression * expr);
public:
HqlExprAttr original;
Owned graph;
HqlExprAttr spillName;
IHqlExpression * transformed;
IHqlExpression * outputToUseForSpill;
CResourceOptions * options;
HqlExprAttr pathToSplitter;
HqlExprArray aggregates;
HqlExprArray conditions;
HqlExprArray childDependents;
HqlExprCopyArray originalChildDependents;
BoolArray childSingleNode;
HqlExprAttr spilledDataset;
HqlExprAttr splitterOutput;
unsigned numUses;
unsigned numExternalUses;
unsigned conditionSourceCount;
unsigned currentSource;
bool containsActivity;
bool isActivity;
bool gatheredDependencies;
bool isSpillPoint;
bool balanced;
bool isAlreadyInScope;
bool linkedFromChild;
bool neverSplit;
byte pathToExpr;
};
struct DependencySourceInfo
{
HqlExprArray search;
CIArrayOf graphs;
HqlExprArray exprs;
};
class EclResourcer
{
friend class SelectHoistTransformer;
public:
EclResourcer(IErrorReceiver * _errors, IConstWorkUnit * _wu, ClusterType _targetClusterType, unsigned _clusterSize, const HqlCppOptions & _translatorOptions);
~EclResourcer();
void resourceGraph(HqlExprArray & exprs, HqlExprArray & transformed);
void resourceRemoteGraph(HqlExprArray & exprs, HqlExprArray & transformed);
void setChildQuery(bool value);
void setNewChildQuery(IHqlExpression * graphIdExpr, unsigned numResults);
void setUseGraphResults(bool _useGraphResults)
{
options.useGraphResults = _useGraphResults;
if (_useGraphResults)
options.createSpillAsDataset = false;
}
void tagActiveCursors(HqlExprCopyArray & activeRows);
inline unsigned numGraphResults() { return options.nextResult; }
protected:
void changeGraph(IHqlExpression * expr, ResourceGraphInfo * newGraph);
void connectGraphs(ResourceGraphInfo * sourceGraph, IHqlExpression * sourceNode, ResourceGraphInfo * sinkGraph, IHqlExpression * sinkNode, LinkKind linkKind);
ResourceGraphInfo * createGraph();
ResourcerInfo * queryCreateResourceInfo(IHqlExpression * expr);
void removeLink(ResourceGraphLink & link, bool keepExternalUses);
void replaceGraphReferences(IHqlExpression * expr, ResourceGraphInfo * oldGraph, ResourceGraphInfo * newGraph);
void replaceGraphReferences(ResourceGraphInfo * oldGraph, ResourceGraphInfo * newGraph);
//Pass 1
void gatherChildSplitPoints(IHqlExpression * expr, BoolArray & alwaysHoistChild, ResourcerInfo * info, unsigned first, unsigned last);
bool findSplitPoints(IHqlExpression * expr);
void findSplitPoints(HqlExprArray & exprs);
void noteConditionalChildren(BoolArray & alwaysHoistChild);
void extendSplitPoints();
//Pass 2
void createInitialGraph(IHqlExpression * expr, IHqlExpression * owner, ResourceGraphInfo * ownerGraph, LinkKind linkKind, bool forceNewGraph);
void createInitialGraphs(HqlExprArray & exprs);
void createInitialRemoteGraph(IHqlExpression * expr, IHqlExpression * owner, ResourceGraphInfo * ownerGraph, bool forceNewGraph);
void createInitialRemoteGraphs(HqlExprArray & exprs);
//Pass 3
void markAsUnconditional(IHqlExpression * expr, ResourceGraphInfo * ownerGraph, IHqlExpression * condition);
void markCondition(IHqlExpression * expr, IHqlExpression * condition, bool wasConditional);
void markConditionBranch(unsigned childIndex, IHqlExpression * expr, IHqlExpression * condition, bool wasConditional);
void markConditions(HqlExprArray & exprs);
void markChildDependentsAsUnconditional(ResourcerInfo * info, IHqlExpression * condition);
//Pass 4
void createResourceSplit(IHqlExpression * expr, IHqlExpression * owner, ResourceGraphInfo * ownerNewGraph, ResourceGraphInfo * originalGraph);
void getResources(IHqlExpression * expr, CResources & exprResources);
bool calculateResourceSpillPoints(IHqlExpression * expr, ResourceGraphInfo * graph, CResources & resourcesSoFar, bool hasGoodSpillPoint, bool canSpill);
void insertResourceSpillPoints(IHqlExpression * expr, IHqlExpression * owner, ResourceGraphInfo * ownerOriginalGraph, ResourceGraphInfo * ownerNewGraph);
void resourceSubGraph(ResourceGraphInfo * graph);
void resourceSubGraphs(HqlExprArray & exprs);
//Pass 5
void addDependencySource(IHqlExpression * search, ResourceGraphInfo * curGraph, IHqlExpression * expr);
void addDependencyUse(IHqlExpression * search, ResourceGraphInfo * curGraph, IHqlExpression * expr);
bool addExprDependency(IHqlExpression * expr, ResourceGraphInfo * curGraph, IHqlExpression * activityExpr);
void addRefExprDependency(IHqlExpression * expr, ResourceGraphInfo * curGraph, IHqlExpression * activityExpr);
void doAddChildDependencies(IHqlExpression * expr, ResourceGraphInfo * graph, IHqlExpression * activityExpr);
void addChildDependencies(IHqlExpression * expr, ResourceGraphInfo * graph, IHqlExpression * activityExpr);
void addDependencies(IHqlExpression * expr, ResourceGraphInfo * graph, IHqlExpression * activityExpr);
void addDependencies(HqlExprArray & exprs);
//Pass 6
bool queryMergeGraphLink(ResourceGraphLink & link);
void mergeSubGraphs();
void mergeSubGraphs(unsigned pass);
void mergeSiblings();
//Pass 6b
void spotUnbalancedSplitters(IHqlExpression * expr, unsigned whichSource, IHqlExpression * path, ResourceGraphInfo * graph);
void spotUnbalancedSplitters(HqlExprArray & exprs);
//Pass 6c
void spotSharedInputs(IHqlExpression * expr, ResourceGraphInfo * graph);
void spotSharedInputs();
//Pass 7
bool optimizeAggregate(IHqlExpression * expr);
void optimizeAggregates();
//Pass 8
IHqlExpression * findPredecessor(IHqlExpression * expr, IHqlExpression * search, IHqlExpression * prev);
IHqlExpression * findPredecessor(ResourcerInfo * search);
void moveExternalSpillPoints();
//Pass 9
IHqlExpression * replaceResourcedReferences(ResourcerInfo * info, IHqlExpression * expr);
IHqlExpression * doCreateResourced(IHqlExpression * expr, ResourceGraphInfo * graph, bool expandInParent, bool defineSideEffect);
IHqlExpression * createResourced(IHqlExpression * expr, ResourceGraphInfo * graph, bool expandInParent, bool defineSideEffect);
void createResourced(HqlExprArray & transformed);
void createResourced(ResourceGraphInfo * graph, HqlExprArray & transformed);
void inheritRedundantDependencies(ResourceGraphInfo * thisGraph);
void display(StringBuffer & out);
void trace();
void doCheckRecursion(ResourceGraphInfo * graph, PointerArray & visited);
void checkRecursion(ResourceGraphInfo * graph, PointerArray & visited);
void checkRecursion(ResourceGraphInfo * graph);
unsigned getMaxDepth() const;
protected:
Owned wu;
CIArrayOf graphs;
CIArrayOf links;
ClusterType targetClusterType;
DependencySourceInfo dependencySource;
unsigned clusterSize;
CResources * resourceLimit;
IErrorReceiver * errors;
bool spilled;
bool spillMultiCondition;
bool spotThroughAggregate;
bool insideNeverSplit;
CResourceOptions options;
HqlExprArray rootConditions;
HqlExprCopyArray activeSelectors;
HqlExprCopyArray conditionalChildren;
};
#endif