Skip to content

[Pipe] Fix processor worker starvation on pipe stop - #18396

Open
Caideyipi wants to merge 3 commits into
apache:masterfrom
Caideyipi:fix/pipe-processor-cooperative-yield
Open

[Pipe] Fix processor worker starvation on pipe stop#18396
Caideyipi wants to merge 3 commits into
apache:masterfrom
Caideyipi:fix/pipe-processor-cooperative-yield

Conversation

@Caideyipi

@Caideyipi Caideyipi commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Description

  • Add an epoch-based execution guard so a processor invocation that observes STOP yields even if the pipe is immediately started again.
  • Check the guard around TsFile-close waits, parser admission, Tablet boundaries, and OOM backoff; yielding is neutral control flow and preserves the current event and parsing progress.
  • Make parser admission non-blocking for processor subtasks so a task that is not admitted immediately yields its worker while keeping its fair-queue request.
  • Cancel pending parser requests on STOP and release active parser reservations from the processor worker before yielding.
  • Add a deterministic shared-worker test covering a stopped Pipe, a parser-waiting Pipe, and a running Pipe in the same worker round.
  • Watch each processor worker for a continuously running event. Log the worker stack after 10 minutes and at most once every 30 minutes for the same event; cap the event description at 1 KiB and the stack at 64 frames.

Tests

  • mvn -o -nsu test -pl iotdb-core/datanode -Dtest=PipeProcessorSubtaskWorkerTest,PipeProcessorSubtaskExecutionGuardTest,PipeTsFileInsertionEventAdmissionTest,PipeMemoryManagerTest,PipeProcessorSubtaskExecutorTest
  • mvn -o -nsu test -pl iotdb-core/datanode -Dtest=TsFileInsertionEventParserTest
  • mvn -o test -pl iotdb-core/datanode -Dtest=PipeProcessorSubtaskWorkerTest,PipeProcessorSubtaskExecutionGuardTest -DfailIfNoTests=false
  • mvn -o compile -pl iotdb-core/datanode -P with-zh-locale

Comment on lines +276 to 280
if (ExceptionUtils.getRootCause(e) instanceof PipeProcessorSubtaskYieldException) {
isResumingFromYield.set(true);
throw (PipeProcessorSubtaskYieldException) ExceptionUtils.getRootCause(e);
}
if (ExceptionUtils.getRootCause(e) instanceof PipeRuntimeOutOfMemoryCriticalException) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to call getRootCause multiple times.

Comment on lines +25 to +28
private static final PipeProcessorSubtaskYieldException PAUSE_REQUESTED_INSTANCE =
new PipeProcessorSubtaskYieldException(Reason.PAUSE_REQUESTED);
private static final PipeProcessorSubtaskYieldException PARSER_NOT_ADMITTED_INSTANCE =
new PipeProcessorSubtaskYieldException(Reason.PARSER_NOT_ADMITTED);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a static exception instance may miss the actual stack traces.
Is it expected?

Comment on lines +915 to +920
while (remainingTimeInMs > 0) {
processorExecutionGuard.check();
Thread.sleep(Math.min(remainingTimeInMs, 100));
processorExecutionGuard.check();
remainingTimeInMs = deadlineInMs - System.currentTimeMillis();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to register this thread with the guard and let it interrupt registered threads when the epoch changes?

Frequent sleep-and-wake may reduce performance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants