Class ParallelTopNOperator
- All Implemented Interfaces:
Closeable,AutoCloseable,org.apache.lucene.util.Accountable,Operator,Releasable
TopNOperator that dispatches incoming pages to multiple
worker TopNOperators running on esql_worker threads. The driver thread
is never blocked waiting for workers; it uses ExchangeBuffer as a bounded FIFO
between the driver and the workers, relying on isBlocked() to back-pressure the
upstream operator when the buffer is full.
Lifecycle
- Collecting – pages arrive via
addInput(org.elasticsearch.compute.data.Page); they are enqueued ininand background workers drain that buffer concurrently. - Finishing –
finish()marks the buffer as complete; workers drain the remaining pages and build their local top-K queues. - Merging – once all workers have signalled completion via
allWorkersDone, the driver thread pops each worker's priority-queue directly intomergeTarget's queue (no page encode/decode), callsTopNOperator.finish()on it, and delegates subsequentgetOutput()calls to it.
Memory accounting and LC ownership transfer
mergeTarget charges allocations directly to the driver's circuit breaker. Each
background worker has its own LocalCircuitBreaker
(LC) via DriverContext.createChildBlockFactory().
The LC backs every allocation the worker makes: the TopNQueue struct, the spare
TopNRow, and the bytes inside each row (each TopNRow holds a direct
reference to its creator's breaker).
Aborting workers clean up on the worker thread: TopNOperator.close()
closes all rows and the queue struct, returning their bytes to the LC;
DriverContext.releaseChildBlockFactory(org.elasticsearch.compute.data.BlockFactory) then closes the LC and returns its reserved bytes
to the driver's breaker.
Non-aborting workers transfer ownership of their operator — including their LC — to the driver thread by signalling done without calling either method. The driver then:
- Pops the worker's queue into
mergeTarget's queue ingetOutput().PriorityQueue.pop()nulls each heap slot, so the worker queue is empty after the drain; transferred rows still reference their worker LC.allWorkersDoneguarantees the driver sees each LC's fully-updated state. - Calls
TopNOperator.close()on the worker. The queue is empty so no rows are closed; only the queue's struct bytes are returned to the LC. - Calls
DriverContext.releaseChildBlockFactory(org.elasticsearch.compute.data.BlockFactory)for all workers inclose(), aftermergeTarget.close()— which closes any surviving rows, each returning its bytes to its worker LC — so every LC is fully drained before being released to the driver's breaker.
Input pages have Page.allowPassingToDifferentDriver() called on the driver
thread in addInput(org.elasticsearch.compute.data.Page) before being enqueued.
-
Nested Class Summary
Nested classes/interfaces inherited from interface org.elasticsearch.compute.operator.Operator
Operator.OperatorFactory, Operator.Status -
Field Summary
Fields inherited from interface org.apache.lucene.util.Accountable
NULL_ACCOUNTABLEFields inherited from interface org.elasticsearch.compute.operator.Operator
MIN_TARGET_PAGE_SIZE, NOT_BLOCKED, TARGET_PAGE_SIZE -
Constructor Summary
ConstructorsConstructorDescriptionParallelTopNOperator(TopNOperator.ParallelWorkerConfig config, DriverContext driverContext, TopNOperator initialWorker) -
Method Summary
Modifier and TypeMethodDescriptionvoidadds an input page to the operator.booleanReturns true if the operator can produce more output pages without requiring additional input pages.voidclose()notifies the operator that it won't be used anymore (i.e.voidfinish()notifies the operator that it won't receive any more input pagesreturns non-null if output page available.An operator can be blocked on some action (e.g.booleanwhether the operator has finished processing all input pages and made the corresponding output pages availablebooleanwhether the given operator can accept more input pageslongtoString()Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, waitMethods inherited from interface org.apache.lucene.util.Accountable
getChildResourcesMethods inherited from interface org.elasticsearch.compute.operator.Operator
status, tryPromote
-
Constructor Details
-
ParallelTopNOperator
public ParallelTopNOperator(TopNOperator.ParallelWorkerConfig config, DriverContext driverContext, TopNOperator initialWorker) - Parameters:
config- parallel worker configuration (executor, worker count, etc.)driverContext- driver context for block-factory and async-action trackinginitialWorker- the promotedTopNOperatorthat holds pre-promotion rows; becomesmergeTargetand is never sent to a background thread
-
-
Method Details
-
needsInput
public boolean needsInput()Description copied from interface:Operatorwhether the given operator can accept more input pages- Specified by:
needsInputin interfaceOperator
-
addInput
Description copied from interface:Operatoradds an input page to the operator. only called when needsInput() == true and isFinished() == false -
finish
public void finish()Description copied from interface:Operatornotifies the operator that it won't receive any more input pages -
isFinished
public boolean isFinished()Description copied from interface:Operatorwhether the operator has finished processing all input pages and made the corresponding output pages available- Specified by:
isFinishedin interfaceOperator
-
canProduceMoreDataWithoutExtraInput
public boolean canProduceMoreDataWithoutExtraInput()Description copied from interface:OperatorReturns true if the operator can produce more output pages without requiring additional input pages. This is useful for operators that buffer data or have internal state that can produce multiple output pages.Operators that do not buffer data should return
false- they cannot produce pages out of thin air. Examples of operators that may returntrue:- Operators with internal buffers (e.g.,
AsyncOperatorwith pending results) - Operators processing a single input page into multiple output pages
- Aggregation operators that buffer partial results
- Specified by:
canProduceMoreDataWithoutExtraInputin interfaceOperator- Returns:
trueif the operator has buffered data that can produce output,falseotherwise
- Operators with internal buffers (e.g.,
-
isBlocked
Description copied from interface:OperatorAn operator can be blocked on some action (e.g. waiting for some resources to become available). If so, it returns a future that completes when the operator becomes unblocked. If the operator is not blocked, this method returnsOperator.NOT_BLOCKEDwhich is an already completed future. -
getOutput
Description copied from interface:Operatorreturns non-null if output page available. Only called when isFinished() == false -
close
public void close()Description copied from interface:Operatornotifies the operator that it won't be used anymore (i.e. none of the other methods called), and its resources can be cleaned up- Specified by:
closein interfaceAutoCloseable- Specified by:
closein interfaceCloseable- Specified by:
closein interfaceOperator- Specified by:
closein interfaceReleasable
-
ramBytesUsed
public long ramBytesUsed()- Specified by:
ramBytesUsedin interfaceorg.apache.lucene.util.Accountable
-
toString
-