Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
PlanNode.java
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.cloudera.impala.planner;
16 
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Set;
20 
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23 
33 import com.cloudera.impala.common.TreeNode;
34 import com.cloudera.impala.thrift.TExecStats;
35 import com.cloudera.impala.thrift.TExplainLevel;
36 import com.cloudera.impala.thrift.TPlan;
37 import com.cloudera.impala.thrift.TPlanNode;
38 import com.cloudera.impala.thrift.TQueryOptions;
39 import com.google.common.base.Preconditions;
40 import com.google.common.collect.Lists;
41 import com.google.common.collect.Sets;
42 import com.google.common.math.LongMath;
43 
59 abstract public class PlanNode extends TreeNode<PlanNode> {
60  private final static Logger LOG = LoggerFactory.getLogger(PlanNode.class);
61 
62  // TODO: Retrieve from the query options instead of using a default.
63  protected final static int DEFAULT_BATCH_SIZE = 1024;
64 
65  // String used for this node in getExplainString().
66  protected String displayName_;
67 
68  // unique w/in plan tree; assigned by planner, and not necessarily in c'tor
69  protected PlanNodeId id_;
70 
71  protected long limit_; // max. # of rows to be returned; 0: no limit_
72 
73  // ids materialized by the tree rooted at this node
74  protected ArrayList<TupleId> tupleIds_;
75 
76  // ids of the TblRefs "materialized" by this node; identical with tupleIds_
77  // if the tree rooted at this node only materializes BaseTblRefs;
78  // useful during plan generation
79  protected ArrayList<TupleId> tblRefIds_;
80 
81  // A set of nullable TupleId produced by this node. It is a subset of tupleIds_.
82  // A tuple is nullable within a particular plan tree if it's the "nullable" side of
83  // an outer join, which has nothing to do with the schema.
84  protected Set<TupleId> nullableTupleIds_ = Sets.newHashSet();
85 
86  protected List<Expr> conjuncts_ = Lists.newArrayList();
87 
88  // Fragment that this PlanNode is executed in. Valid only after this PlanNode has been
89  // assigned to a fragment. Set and maintained by enclosing PlanFragment.
91 
92  // if set, needs to be applied by parent node to reference this node's output
94 
95  // global state of planning wrt conjunct assignment; used by planner as a shortcut
96  // to avoid having to pass assigned conjuncts back and forth
97  // (the planner uses this to save and reset the global state in between join tree
98  // alternatives)
99  protected Set<ExprId> assignedConjuncts_;
100 
101  // estimate of the output cardinality of this node; set in computeStats();
102  // invalid: -1
103  protected long cardinality_;
104 
105  // number of nodes on which the plan tree rooted at this node would execute;
106  // set in computeStats(); invalid: -1
107  protected int numNodes_;
108 
109  // sum of tupleIds_' avgSerializedSizes; set in computeStats()
110  protected float avgRowSize_;
111 
112  // estimated per-host memory requirement for this node;
113  // set in computeCosts(); invalid: -1
114  protected long perHostMemCost_ = -1;
115 
116  protected PlanNode(PlanNodeId id, ArrayList<TupleId> tupleIds, String displayName) {
117  id_ = id;
118  limit_ = -1;
119  // make a copy, just to be on the safe side
120  tupleIds_ = Lists.newArrayList(tupleIds);
121  tblRefIds_ = Lists.newArrayList(tupleIds);
122  cardinality_ = -1;
123  numNodes_ = -1;
124  displayName_ = displayName;
125  }
126 
130  protected PlanNode(String displayName) {
131  limit_ = -1;
132  tupleIds_ = Lists.newArrayList();
133  tblRefIds_ = Lists.newArrayList();
134  cardinality_ = -1;
135  numNodes_ = -1;
136  displayName_ = displayName;
137  }
138 
139  protected PlanNode(PlanNodeId id, String displayName) {
140  id_ = id;
141  limit_ = -1;
142  tupleIds_ = Lists.newArrayList();
143  tblRefIds_ = Lists.newArrayList();
144  cardinality_ = -1;
145  numNodes_ = -1;
146  displayName_ = displayName;
147  }
148 
152  protected PlanNode(PlanNodeId id, PlanNode node, String displayName) {
153  id_ = id;
154  limit_ = node.limit_;
155  tupleIds_ = Lists.newArrayList(node.tupleIds_);
156  tblRefIds_ = Lists.newArrayList(node.tblRefIds_);
157  nullableTupleIds_ = Sets.newHashSet(node.nullableTupleIds_);
158  conjuncts_ = Expr.cloneList(node.conjuncts_);
159  cardinality_ = -1;
160  numNodes_ = -1;
161  displayName_ = displayName;
162  }
163 
164  public PlanNodeId getId() { return id_; }
165  public void setId(PlanNodeId id) {
166  Preconditions.checkState(id_ == null);
167  id_ = id;
168  }
169  public long getLimit() { return limit_; }
170  public boolean hasLimit() { return limit_ > -1; }
171  public long getPerHostMemCost() { return perHostMemCost_; }
172  public long getCardinality() { return cardinality_; }
173  public int getNumNodes() { return numNodes_; }
174  public float getAvgRowSize() { return avgRowSize_; }
175  public void setFragment(PlanFragment fragment) { fragment_ = fragment; }
176  public PlanFragment getFragment() { return fragment_; }
177  public List<Expr> getConjuncts() { return conjuncts_; }
179  public void setOutputSmap(ExprSubstitutionMap smap) { outputSmap_ = smap; }
180  public Set<ExprId> getAssignedConjuncts() { return assignedConjuncts_; }
181  public void setAssignedConjuncts(Set<ExprId> conjuncts) {
182  assignedConjuncts_ = conjuncts;
183  }
184 
190  public void setLimit(long limit) {
191  if (limit_ == -1 || (limit != -1 && limit_ > limit)) limit_ = limit;
192  }
193 
194  public void unsetLimit() { limit_ = -1; }
195 
196  public ArrayList<TupleId> getTupleIds() {
197  Preconditions.checkState(tupleIds_ != null);
198  return tupleIds_;
199  }
200 
201  public ArrayList<TupleId> getTblRefIds() { return tblRefIds_; }
202  public void setTblRefIds(ArrayList<TupleId> ids) { tblRefIds_ = ids; }
203 
204  public Set<TupleId> getNullableTupleIds() {
205  Preconditions.checkState(nullableTupleIds_ != null);
206  return nullableTupleIds_;
207  }
208 
209  public void addConjuncts(List<Expr> conjuncts) {
210  if (conjuncts == null) return;
211  conjuncts_.addAll(conjuncts);
212  }
213 
214  public void transferConjuncts(PlanNode recipient) {
215  recipient.conjuncts_.addAll(conjuncts_);
216  conjuncts_.clear();
217  }
218 
219  public String getExplainString() {
220  return getExplainString("", "", TExplainLevel.VERBOSE);
221  }
222 
223  protected void setDisplayName(String s) { displayName_ = s; }
224 
225  final protected String getDisplayLabel() {
226  return String.format("%s:%s", id_.toString(), displayName_);
227  }
228 
234  protected String getDisplayLabelDetail() { return ""; }
235 
252  protected final String getExplainString(String rootPrefix, String prefix,
253  TExplainLevel detailLevel) {
254  StringBuilder expBuilder = new StringBuilder();
255  String detailPrefix = prefix;
256  String filler;
257  boolean printFiller = (detailLevel.ordinal() >= TExplainLevel.STANDARD.ordinal());
258 
259  // Do not traverse into the children of an Exchange node to avoid crossing
260  // fragment boundaries.
261  boolean traverseChildren = !children_.isEmpty() &&
262  !(this instanceof ExchangeNode && detailLevel == TExplainLevel.VERBOSE);
263 
264  if (traverseChildren) {
265  detailPrefix += "| ";
266  filler = prefix + "|";
267  } else {
268  detailPrefix += " ";
269  filler = prefix;
270  }
271 
272  // Print the current node
273  // The plan node header line will be prefixed by rootPrefix and the remaining details
274  // will be prefixed by detailPrefix.
275  expBuilder.append(getNodeExplainString(rootPrefix, detailPrefix, detailLevel));
276 
277  if (detailLevel.ordinal() >= TExplainLevel.STANDARD.ordinal() &&
278  !(this instanceof SortNode)) {
279  if (limit_ != -1) expBuilder.append(detailPrefix + "limit: " + limit_ + "\n");
280  expBuilder.append(getOffsetExplainString(detailPrefix));
281  }
282 
283  // Output cardinality, cost estimates and tuple Ids only when explain plan level
284  // is extended or above.
285  if (detailLevel.ordinal() >= TExplainLevel.EXTENDED.ordinal()) {
286  // Print estimated output cardinality and memory cost.
287  expBuilder.append(PrintUtils.printHosts(detailPrefix, numNodes_));
288  expBuilder.append(PrintUtils.printMemCost(" ", perHostMemCost_) + "\n");
289 
290  // Print tuple ids and row size.
291  expBuilder.append(detailPrefix + "tuple-ids=");
292  for (int i = 0; i < tupleIds_.size(); ++i) {
293  TupleId tupleId = tupleIds_.get(i);
294  String nullIndicator = nullableTupleIds_.contains(tupleId) ? "N" : "";
295  expBuilder.append(tupleId.asInt() + nullIndicator);
296  if (i + 1 != tupleIds_.size()) expBuilder.append(",");
297  }
298  expBuilder.append(" row-size=" + PrintUtils.printBytes(Math.round(avgRowSize_)));
299  expBuilder.append(PrintUtils.printCardinality(" ", cardinality_));
300  expBuilder.append("\n");
301  }
302 
303  // Print the children. Do not traverse into the children of an Exchange node to
304  // avoid crossing fragment boundaries.
305  if (traverseChildren) {
306  if (printFiller) expBuilder.append(filler + "\n");
307  String childHeadlinePrefix = prefix + "|--";
308  String childDetailPrefix = prefix + "| ";
309  for (int i = children_.size() - 1; i >= 1; --i) {
310  expBuilder.append(
311  children_.get(i).getExplainString(childHeadlinePrefix, childDetailPrefix,
312  detailLevel));
313  if (printFiller) expBuilder.append(filler + "\n");
314  }
315  expBuilder.append(children_.get(0).getExplainString(prefix, prefix, detailLevel));
316  }
317  return expBuilder.toString();
318  }
319 
325  protected String getNodeExplainString(String rootPrefix, String detailPrefix,
326  TExplainLevel detailLevel) {
327  return "";
328  }
329 
336  protected String getOffsetExplainString(String prefix) {
337  return "";
338  }
339 
340  // Convert this plan node, including all children, to its Thrift representation.
341  public TPlan treeToThrift() {
342  TPlan result = new TPlan();
343  treeToThriftHelper(result);
344  return result;
345  }
346 
347  // Append a flattened version of this plan node, including all children, to 'container'.
348  private void treeToThriftHelper(TPlan container) {
349  TPlanNode msg = new TPlanNode();
350  msg.node_id = id_.asInt();
351  msg.limit = limit_;
352 
353  TExecStats estimatedStats = new TExecStats();
354  estimatedStats.setCardinality(cardinality_);
355  estimatedStats.setMemory_used(perHostMemCost_);
356  msg.setLabel(getDisplayLabel());
357  msg.setLabel_detail(getDisplayLabelDetail());
358  msg.setEstimated_stats(estimatedStats);
359 
360  msg.setRow_tuples(Lists.<Integer>newArrayListWithCapacity(tupleIds_.size()));
361  msg.setNullable_tuples(Lists.<Boolean>newArrayListWithCapacity(tupleIds_.size()));
362  for (TupleId tid: tupleIds_) {
363  msg.addToRow_tuples(tid.asInt());
364  msg.addToNullable_tuples(nullableTupleIds_.contains(tid));
365  }
366  for (Expr e: conjuncts_) {
367  msg.addToConjuncts(e.treeToThrift());
368  }
369  toThrift(msg);
370  container.addToNodes(msg);
371  // For the purpose of the BE consider ExchangeNodes to have no children.
372  if (this instanceof ExchangeNode) {
373  msg.num_children = 0;
374  return;
375  } else {
376  msg.num_children = children_.size();
377  for (PlanNode child: children_) {
378  child.treeToThriftHelper(container);
379  }
380  }
381  }
382 
392  public void init(Analyzer analyzer) throws InternalException {
393  assignConjuncts(analyzer);
394  computeStats(analyzer);
395  createDefaultSmap(analyzer);
396  }
397 
401  protected void assignConjuncts(Analyzer analyzer) {
402  List<Expr> unassigned = analyzer.getUnassignedConjuncts(this);
403  conjuncts_.addAll(unassigned);
404  analyzer.markConjunctsAssigned(unassigned);
405  }
406 
411  if (getChildren().size() == 0) return new ExprSubstitutionMap();
412  if (getChildren().size() == 1) return getChild(0).getOutputSmap();
413  ExprSubstitutionMap result = ExprSubstitutionMap.combine(
414  getChild(0).getOutputSmap(), getChild(1).getOutputSmap());
415  for (int i = 2; i < getChildren().size(); ++i) {
416  result = ExprSubstitutionMap.combine(result, getChild(i).getOutputSmap());
417  }
418  return result;
419  }
420 
425  protected void createDefaultSmap(Analyzer analyzer) {
426  ExprSubstitutionMap combinedChildSmap = getCombinedChildSmap();
427  outputSmap_ =
428  ExprSubstitutionMap.compose(outputSmap_, combinedChildSmap, analyzer);
429  conjuncts_ = Expr.substituteList(conjuncts_, outputSmap_, analyzer, false);
430  }
431 
441  protected void computeStats(Analyzer analyzer) {
442  avgRowSize_ = 0.0F;
443  for (TupleId tid: tupleIds_) {
444  TupleDescriptor desc = analyzer.getTupleDesc(tid);
445  avgRowSize_ += desc.getAvgSerializedSize();
446  }
447  if (!children_.isEmpty()) numNodes_ = getChild(0).numNodes_;
448  }
449 
450  protected long capAtLimit(long cardinality) {
451  if (hasLimit()) {
452  if (cardinality == -1) {
453  return limit_;
454  } else {
455  return Math.min(cardinality, limit_);
456  }
457  }
458  return cardinality;
459  }
460 
464  protected void markSlotsMaterialized(Analyzer analyzer, List<Expr> exprs) {
465  List<SlotId> refdIdList = Lists.newArrayList();
466  for (Expr expr: exprs) {
467  expr.getIds(null, refdIdList);
468  }
469  analyzer.getDescTbl().markSlotsMaterialized(refdIdList);
470  }
471 
475  protected void computeMemLayout(Analyzer analyzer) {
476  for (TupleId id: tupleIds_) {
477  analyzer.getDescTbl().getTupleDesc(id).computeMemLayout();
478  }
479  }
480 
484  protected double computeSelectivity() {
485  double prod = 1.0;
486  for (Expr e: conjuncts_) {
487  if (e.getSelectivity() < 0) continue;
488  prod *= e.getSelectivity();
489  }
490  return prod;
491  }
492 
493  // Convert this plan node into msg (excluding children), which requires setting
494  // the node type and the node-specific field.
495  protected abstract void toThrift(TPlanNode msg);
496 
497  protected String debugString() {
498  // not using Objects.toStrHelper because
499  // PlanNode.debugString() is embedded by debug strings of the subclasses
500  StringBuilder output = new StringBuilder();
501  output.append("preds=" + Expr.debugString(conjuncts_));
502  output.append(" limit=" + Long.toString(limit_));
503  return output.toString();
504  }
505 
506  protected String getExplainString(List<? extends Expr> exprs) {
507  if (exprs == null) return "";
508  StringBuilder output = new StringBuilder();
509  for (int i = 0; i < exprs.size(); ++i) {
510  if (i > 0) output.append(", ");
511  output.append(exprs.get(i).toSql());
512  }
513  return output.toString();
514  }
515 
519  protected boolean hasValidStats() {
520  return (numNodes_ == -1 || numNodes_ >= 0) &&
521  (cardinality_ == -1 || cardinality_ >= 0);
522  }
523 
528  public static long addCardinalities(long a, long b) {
529  try {
530  return LongMath.checkedAdd(a, b);
531  } catch (ArithmeticException e) {
532  LOG.warn("overflow when adding cardinalities: " + a + ", " + b);
533  return Long.MAX_VALUE;
534  }
535  }
536 
541  public static long multiplyCardinalities(long a, long b) {
542  try {
543  return LongMath.checkedMultiply(a, b);
544  } catch (ArithmeticException e) {
545  LOG.warn("overflow when multiplying cardinalities: " + a + ", " + b);
546  return Long.MAX_VALUE;
547  }
548  }
549 
555  public boolean isBlockingNode() { return false; }
556 
562  public void computeCosts(TQueryOptions queryOptions) {
563  perHostMemCost_ = 0;
564  }
565 
570  public long getInputCardinality() {
571  long sum = 0;
572  for(PlanNode p : children_) {
573  long tmp = p.getCardinality();
574  if (tmp == -1) return -1;
575  sum = addCardinalities(sum, tmp);
576  }
577  return sum;
578  }
579 }
PlanNode(PlanNodeId id, String displayName)
Definition: PlanNode.java:139
void assignConjuncts(Analyzer analyzer)
Definition: PlanNode.java:401
ArrayList< TupleId > tupleIds_
Definition: PlanNode.java:74
ArrayList< TupleId > getTblRefIds()
Definition: PlanNode.java:201
ExprSubstitutionMap getCombinedChildSmap()
Definition: PlanNode.java:410
void setTblRefIds(ArrayList< TupleId > ids)
Definition: PlanNode.java:202
int TupleId
Definition: global-types.h:23
ArrayList< TupleId > getTupleIds()
Definition: PlanNode.java:196
void markSlotsMaterialized(Analyzer analyzer, List< Expr > exprs)
Definition: PlanNode.java:464
int SlotId
Definition: global-types.h:24
static long multiplyCardinalities(long a, long b)
Definition: PlanNode.java:541
PlanNode(PlanNodeId id, ArrayList< TupleId > tupleIds, String displayName)
Definition: PlanNode.java:116
void setFragment(PlanFragment fragment)
Definition: PlanNode.java:175
void transferConjuncts(PlanNode recipient)
Definition: PlanNode.java:214
abstract void toThrift(TPlanNode msg)
String getExplainString(List<?extends Expr > exprs)
Definition: PlanNode.java:506
String getNodeExplainString(String rootPrefix, String detailPrefix, TExplainLevel detailLevel)
Definition: PlanNode.java:325
PlanNode(PlanNodeId id, PlanNode node, String displayName)
Definition: PlanNode.java:152
void createDefaultSmap(Analyzer analyzer)
Definition: PlanNode.java:425
final String getExplainString(String rootPrefix, String prefix, TExplainLevel detailLevel)
Definition: PlanNode.java:252
void computeMemLayout(Analyzer analyzer)
Definition: PlanNode.java:475
ExprSubstitutionMap getOutputSmap()
Definition: PlanNode.java:178
long capAtLimit(long cardinality)
Definition: PlanNode.java:450
void computeCosts(TQueryOptions queryOptions)
Definition: PlanNode.java:562
void computeStats(Analyzer analyzer)
Definition: PlanNode.java:441
void init(Analyzer analyzer)
Definition: PlanNode.java:392
void setAssignedConjuncts(Set< ExprId > conjuncts)
Definition: PlanNode.java:181
void treeToThriftHelper(TPlan container)
Definition: PlanNode.java:348
String getOffsetExplainString(String prefix)
Definition: PlanNode.java:336
void setOutputSmap(ExprSubstitutionMap smap)
Definition: PlanNode.java:179
void addConjuncts(List< Expr > conjuncts)
Definition: PlanNode.java:209
ArrayList< TupleId > tblRefIds_
Definition: PlanNode.java:79
ExprSubstitutionMap outputSmap_
Definition: PlanNode.java:93
static long addCardinalities(long a, long b)
Definition: PlanNode.java:528