Skip to content

Notify the mailbox reader when the last pending data offer gives up - #19329

Open
davecromberge wants to merge 1 commit into
apache:masterfrom
davecromberge:fix-contrib/mse-mailbox-pending-data-lost-wakeup
Open

Notify the mailbox reader when the last pending data offer gives up#19329
davecromberge wants to merge 1 commit into
apache:masterfrom
davecromberge:fix-contrib/mse-mailbox-pending-data-lost-wakeup

Conversation

@davecromberge

Copy link
Copy Markdown
Member

An error EOS drains the queued data blocks and makes every parked sender give up. While those offers are still in flight, poll returns null and asks the reader to wait for them (ReceivingMailbox.java:657). But a sender that gives up returns ALREADY_TERMINATED without notifying, and the reader coalesces notifications into a single slot, so the EOS notification cannot stand in for the missing one. Nothing wakes the reader again: it blocks until the query deadline and the query reports EXECUTION_TIMEOUT instead of the error that actually caused it.

Reachable whenever the queue is full and senders are parked when an error EOS or a cancellation arrives. The same gap swallows the TimeoutException and InterruptedException paths out of offerDataToBuffer, which unwind into an offerEos that is rejected as already terminated.

offerDataToBuffer now notifies on every exit path when it is the last pending offer and the upstream has finished — exactly the condition poll waits on. The lock is held there, since awaitNanos reacquires it on all three exits. On the success path this duplicates the notification from offerData, which is harmless because notifications coalesce.

The test asserts the notification count rather than blocking on a read, so it is deterministic: the wake-up is delivered when the last pending offer completes, whether or not the reader managed to poll first. It fails on master with expected [3] but found [2].

Supersedes #19323, which proposed a fix for a lost wake-up at reader registration. That one turned out to be unreachable: registration precedes the reader's first scan, and the scan makes the dropped notification redundant. Thanks to @yashmayya for pushing back on it and pointing at this path instead.

An error EOS drains the queued data blocks and makes every parked sender give
up. While those offers are still in flight, `poll` returns `null` and asks the
reader to wait for them. But a sender that gives up returns
`ALREADY_TERMINATED` without notifying, and the reader coalesces notifications
into a single slot, so the EOS notification cannot stand in for the missing
one. Nothing wakes the reader again: it blocks until the query deadline and the
query reports `EXECUTION_TIMEOUT` instead of the error that actually caused it.

Reachable whenever the queue is full and senders are parked when an error EOS
or a cancellation arrives. The same gap swallows the `TimeoutException` and
`InterruptedException` paths out of `offerDataToBuffer`, which unwind into an
`offerEos` that is rejected as already terminated.

`offerDataToBuffer` now notifies on every exit path when it is the last pending
offer and the upstream has finished, which is exactly the condition `poll` waits
on. On the success path this duplicates the notification from `offerData`, which
is harmless because notifications coalesce.

The test asserts the notification count rather than blocking on a read, so it is
deterministic: the wake-up is delivered when the last pending offer completes,
whether or not the reader managed to poll first. It fails on master with
`expected [3] but found [2]`.
davecromberge added a commit to permutive-engineering/pinot that referenced this pull request Aug 21, 2026
).

Notify the mailbox reader when the last pending data offer gives up. An error
EOS drains the queued data blocks and makes every parked sender give up; while
those offers are still in flight `poll` returns null and asks the reader to wait
for them, but a sender that gives up returns ALREADY_TERMINATED without
notifying and the reader coalesces notifications into a single slot. Nothing
wakes the reader again, so it blocks until the query deadline and the query
reports EXECUTION_TIMEOUT instead of the real error.

Replaces the previously carried cherry-pick of
fix-contrib/mse-inmemory-mailbox-reader-race (9c6408a, upstream
apache#19323), which is closed: that registerReader wake-up is provably
unreachable because the reader scans every mailbox before it parks, so a
notification dropped before registration is always redundant with that scan.

Upstream PR: apache#19329 (open)
@codecov-commenter

codecov-commenter commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 67.03%. Comparing base (22a1be9) to head (61b4b68).

Files with missing lines Patch % Lines
...g/apache/pinot/query/mailbox/ReceivingMailbox.java 50.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master   #19329      +/-   ##
============================================
+ Coverage     67.02%   67.03%   +0.01%     
- Complexity     1418     1424       +6     
============================================
  Files          3463     3463              
  Lines        221673   221674       +1     
  Branches      34955    34956       +1     
============================================
+ Hits         148578   148610      +32     
+ Misses        61260    61229      -31     
  Partials      11835    11835              
Flag Coverage Δ
integration 100.00% <ø> (+100.00%) ⬆️
integration1 100.00% <ø> (?)
integration2 0.00% <ø> (ø)
java-25 67.03% <50.00%> (+0.01%) ⬆️
lane-a 100.00% <ø> (+100.00%) ⬆️
lane-b 0.00% <ø> (ø)
temurin 67.03% <50.00%> (+0.01%) ⬆️
unittests 67.03% <50.00%> (+0.01%) ⬆️
unittests1 57.74% <50.00%> (+0.02%) ⬆️
unittests2 38.96% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@yashmayya
yashmayya requested review from gortiz and yashmayya and a balanced review from Copilot August 21, 2026 16:58
@yashmayya yashmayya added bug Something is not working as expected multi-stage Related to the multi-stage query engine labels Aug 21, 2026

Copilot AI left a comment

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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

Labels

bug Something is not working as expected multi-stage Related to the multi-stage query engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants