Skip to content

Commit e61078b

Browse files
committed
create a trait for blocking operators
1 parent dc2dfa5 commit e61078b

3 files changed

Lines changed: 29 additions & 32 deletions

File tree

sql/core/src/main/scala/org/apache/spark/sql/execution/SortExec.scala

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ case class SortExec(
3939
global: Boolean,
4040
child: SparkPlan,
4141
testSpillFrequency: Int = 0)
42-
extends UnaryExecNode with CodegenSupport {
42+
extends UnaryExecNode with BlockingOperatorWithCodegen {
4343

4444
override def output: Seq[Attribute] = child.output
4545

@@ -124,21 +124,6 @@ case class SortExec(
124124
// Name of sorter variable used in codegen.
125125
private var sorterVariable: String = _
126126

127-
// The result rows come from the sort buffer, so this operator doesn't need to copy its result
128-
// even if its child does.
129-
override def needCopyResult: Boolean = false
130-
131-
// Sort operator always consumes all the input rows before outputting any result, so we don't need
132-
// a stop check before sorting.
133-
override def needStopCheck: Boolean = false
134-
135-
// Sort is a blocking operator. It needs to consume all the inputs before producing any output.
136-
// This means, Limit operator after Sort will never reach its limit during the execution of Sort's
137-
// upstream operators. Here we override this method to return Nil, so that upstream operators will
138-
// not generate useless conditions (which are always evaluated to false) for the Limit operators
139-
// after Sort.
140-
override def limitNotReachedChecks: Seq[String] = Nil
141-
142127
override protected def doProduce(ctx: CodegenContext): String = {
143128
val needToSort =
144129
ctx.addMutableState(CodeGenerator.JAVA_BOOLEAN, "needToSort", v => s"$v = true;")

sql/core/src/main/scala/org/apache/spark/sql/execution/WholeStageCodegenExec.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,10 @@ trait CodegenSupport extends SparkPlan {
360360
* limit-not-reached checks.
361361
*/
362362
final def limitNotReachedCond: String = {
363+
// InputAdapter is also a leaf node.
364+
val isLeafNode = children.isEmpty || this.isInstanceOf[InputAdapter]
365+
assert(isLeafNode || this.isInstanceOf[BlockingOperatorWithCodegen],
366+
"only leaf nodes and blocking nodes need to call this method in its data producing loop.")
363367
if (parent.limitNotReachedChecks.isEmpty) {
364368
""
365369
} else {
@@ -368,6 +372,29 @@ trait CodegenSupport extends SparkPlan {
368372
}
369373
}
370374

375+
/**
376+
* A special kind of operators which support whole stage codegen. Blocking means these operators
377+
* will consume all the inputs first, before producing output. Typical blocking operators are
378+
* sort and aggregate.
379+
*/
380+
trait BlockingOperatorWithCodegen extends CodegenSupport {
381+
382+
// Blocking operators usually have some kind of buffer to keep the data before producing them, so
383+
// then don't to copy its result even if its child does.
384+
override def needCopyResult: Boolean = false
385+
386+
// Blocking operators always consume all the input first, so its upstream operators don't need a
387+
// stop check.
388+
override def needStopCheck: Boolean = false
389+
390+
// Blocking operators need to consume all the inputs before producing any output. This means,
391+
// Limit operator after this blocking operator will never reach its limit during the execution of
392+
// this blocking operator's upstream operators. Here we override this method to return Nil, so
393+
// that upstream operators will not generate useless conditions (which are always evaluated to
394+
// false) for the Limit operators after this blocking operator.
395+
override def limitNotReachedChecks: Seq[String] = Nil
396+
}
397+
371398

372399
/**
373400
* InputAdapter is used to hide a SparkPlan from a subtree that supports codegen.

sql/core/src/main/scala/org/apache/spark/sql/execution/aggregate/HashAggregateExec.scala

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ case class HashAggregateExec(
4545
initialInputBufferOffset: Int,
4646
resultExpressions: Seq[NamedExpression],
4747
child: SparkPlan)
48-
extends UnaryExecNode with CodegenSupport {
48+
extends UnaryExecNode with BlockingOperatorWithCodegen {
4949

5050
private[this] val aggregateBufferAttributes = {
5151
aggregateExpressions.flatMap(_.aggregateFunction.aggBufferAttributes)
@@ -151,21 +151,6 @@ case class HashAggregateExec(
151151
child.asInstanceOf[CodegenSupport].inputRDDs()
152152
}
153153

154-
// The result rows come from the aggregate buffer, or a single row(no grouping keys), so this
155-
// operator doesn't need to copy its result even if its child does.
156-
override def needCopyResult: Boolean = false
157-
158-
// Aggregate operator always consumes all the input rows before outputting any result, so we
159-
// don't need a stop check before aggregating.
160-
override def needStopCheck: Boolean = false
161-
162-
// Aggregate is a blocking operator. It needs to consume all the inputs before producing any
163-
// output. This means, Limit operator after Aggregate will never reach its limit during the
164-
// execution of Aggregate's upstream operators. Here we override this method to return Nil, so
165-
// that upstream operators will not generate useless conditions (which are always evaluated to
166-
// true) for the Limit operators after Aggregate.
167-
override def limitNotReachedChecks: Seq[String] = Nil
168-
169154
protected override def doProduce(ctx: CodegenContext): String = {
170155
if (groupingExpressions.isEmpty) {
171156
doProduceWithoutKeys(ctx)

0 commit comments

Comments
 (0)