Skip to content

Add streaming shared subplan example - #24780

Open
nathanb9 wants to merge 6 commits into
apache:mainfrom
nathanb9:streaming-shared-subplan-example
Open

Add streaming shared subplan example#24780
nathanb9 wants to merge 6 commits into
apache:mainfrom
nathanb9:streaming-shared-subplan-example

Conversation

@nathanb9

@nathanb9 nathanb9 commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Im trying to produce an example of how a downstream project could use datafusion to enable the reuse of a subplan in a streaming fashion.

motivation

  • Discussions in issue: Avoid recompute CTEs (common table expressions) / share input plans #8777
  • Streaming a common subplan to multiple consumers allows:
    1. Allow producers and consumers to execute concurrently where the subplan which is being streamed is not a pipeline breaker (so not the example in this PR)
    2. Potentially reduce source I/O when all consumers finish early, unlike full materialization of the subplan

how the example works

  1. The expensive HashJoinExec is marked as a shared subplan with an ID.
  2. During physical optimization, the shared references are replaced with one StreamingFanoutExec and one
    StreamingFanoutReaderExec per consumer.
  3. StreamingFanoutExec executes each input partition once and creates a bounded output lane for every (consumer, partition) pair.
  4. As each RecordBatch arrives, it is sent to every consumer's lane using RecordBatchReceiverStreamBuilder.
  5. Each StreamingFanoutReaderExec selects the lanes belonging to its consumer. Reader 0 exposes the fan-out as its
    physical child; the other reader accesses the same fan-out through a shared Arc.

extension points used

  • StreamingShareNode implements [UserDefinedLogicalNodeCore] and marks a logical subplan with a stable sharing ID.
  • StreamingShareQueryPlanner implements [QueryPlanner] and installs StreamingShareExtensionPlanner, an [ExtensionPlanner] that converts the logical marker into a temporary StreamingShareMarkerExec.
  • RewriteStreamingShares implements [PhysicalOptimizerRule]. It counts consumers and replaces the temporary markers with one fan-out and one reader per consumer.
  • StreamingFanoutState and FanoutPartition are example-only runtime helpers. They use [RecordBatchReceiverStreamBuilder] for bounded streams and [SpawnedTask] to run each input partition once.

diagrammed from example in issue: #8777

                             ┌────────────────────┐
                             │     UnionExec      │
                             └────────────────────┘
                                ▲              ▲
                    Projection east      Projection west
                           ▲                    ▲
                     Aggregate SUM        Aggregate SUM
                           ▲                    ▲
                      Filter east           Filter west
                           ▲                    ▲
          ┌────────────────────────┐  ┌────────────────────────┐
          │ FanoutReaderExec       │  │ FanoutReaderExec       │
          │ consumer = 0           │  │ consumer = 1           │
          └────────────────────────┘  └────────────────────────┘
                           ▲                    ⋮
                 physical child                 ⋮ shared Arc
                           │                    ⋮
          ┌────────────────────────┐            ⋮
          │ StreamingFanoutExec    │............┘
          │ owns all buffering     │
          │ exposes C × P lanes    │
          └────────────────────────┘
                           ▲
                     HashJoinExec
                      ▲         ▲
                Customers     Orders
                

@codecov-commenter

codecov-commenter commented Aug 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.52%. Comparing base (74f4dd6) to head (eea8c09).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #24780      +/-   ##
==========================================
- Coverage   81.53%   81.52%   -0.01%     
==========================================
  Files        1123     1123              
  Lines      406102   406148      +46     
  Branches   406102   406148      +46     
==========================================
- Hits       331111   331110       -1     
- Misses      55628    55667      +39     
- Partials    19363    19371       +8     

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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