Skip to content

perf(optimizer): Make cost-based strategy of using parent preference in AddLocalExchanges#26960

Merged
feilong-liu merged 1 commit intoprestodb:masterfrom
kagamiori:adjust_parent_preference_in_addlocalexchanges
Jan 30, 2026
Merged

perf(optimizer): Make cost-based strategy of using parent preference in AddLocalExchanges#26960
feilong-liu merged 1 commit intoprestodb:masterfrom
kagamiori:adjust_parent_preference_in_addlocalexchanges

Conversation

@kagamiori
Copy link
Copy Markdown
Contributor

@kagamiori kagamiori commented Jan 14, 2026

We observed that the use of parent preference in AddLocalExchanges can limit parallelism when the cardinality of the partition column of parent preference is low. In a setup where a query is allowed to use many cores, limiting the parallelism significantly affect the query latency. More details can be found in #26961.

This PR makes three changes:

  • This PR introduces a new feature config localExchangeParentPreferenceStrategy that has three values: ALWAYS, NEVER, and AUTOMATIC. The default value is ALWAYS (i.e., current behavior).
  • This PR makes AddLocalExchanges to use parent preference according to the localExchangeParentPreferenceStrategy. When localExchangeParentPreferenceStrategy is ALWAYS, it always uses parent preference. When localExchangeParentPreferenceStrategy is NEVER, it always not uses parent preference. When localExchangeParentPreferenceStrategy is AUTOMATIC, it uses parent preference only when the estimated cardinality is larger than the task concurrency. (If estimated stats is not available, parent preference is not used.)
    • Notice that the estimated stats is only calculated when localExchangeParentPreferenceStrategy is AUTOMATIC.
  • This PR adds unit tests of the new config and the change to local-exchange.

Description

Motivation and Context

Impact

Test Plan

Contributor checklist

  • Please make sure your submission complies with our contributing guide, in particular code style and commit standards.
  • PR description addresses the issue accurately and concisely. If the change is non-trivial, a GitHub Issue is referenced.
  • Documented new properties (with its default value), SQL syntax, functions, or other functionality.
  • If release notes are required, they follow the release notes guidelines.
  • Adequate tests were added if applicable.
  • CI passed.
  • If adding new dependencies, verified they have an OpenSSF Scorecard score of 5.0 or higher (or obtained explicit TSC approval for lower scores).

Release Notes

Please follow release notes guidelines and fill in the release notes below.

== NO RELEASE NOTE ==

Summary by Sourcery

Introduce a configurable strategy for using parent preferences in AddLocalExchanges and make local exchange partitioning for aggregations cost-aware based on estimated cardinality and task concurrency.

New Features:

  • Add a local_exchange_parent_preference_strategy session/feature config to control how local exchanges use parent partitioning preferences with options ALWAYS, NEVER, and AUTOMATIC.

Enhancements:

  • Update AddLocalExchanges to optionally use stats-based decisions when applying parent partitioning preferences for aggregation local exchanges, leveraging the existing stats calculator.
  • Wire the stats calculator into AddLocalExchanges through PlanOptimizers to enable precomputation of plan statistics when the AUTOMATIC strategy is selected.

Tests:

  • Add planner tests validating local exchange behavior under ALWAYS, NEVER, and AUTOMATIC parent preference strategies and different task concurrency settings.
  • Extend FeaturesConfig tests to cover default and explicit mappings for the new local_exchange_parent_preference_strategy config.

@prestodb-ci prestodb-ci added the from:Meta PR from Meta label Jan 14, 2026
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Jan 14, 2026

Reviewer's Guide

Introduces a configurable, cost-based strategy for whether AddLocalExchanges should honor parent partitioning preferences for aggregations, wiring it through session/config properties, using stats when in AUTOMATIC mode, and adding planner tests to validate the behavior.

Sequence diagram for AddLocalExchanges optimization with AUTOMATIC strategy

sequenceDiagram
    participant Planner as PlanOptimizers
    participant Optimizer as AddLocalExchanges
    participant Session as Session
    participant StatsCalc as StatsCalculator
    participant StatsProv as CachingStatsProvider
    participant Plan as PlanNode
    participant Rew as Rewriter

    Planner->>Optimizer: optimize(Plan, Session, TypeProvider, VariableAllocator, PlanNodeIdAllocator, WarningCollector)
    Optimizer->>Session: getLocalExchangeParentPreferenceStrategy(Session)
    Session-->>Optimizer: LocalExchangeParentPreferenceStrategy strategy

    alt strategy == AUTOMATIC
        Optimizer->>StatsCalc: construct CachingStatsProvider(Session, TypeProvider)
        StatsCalc-->>Optimizer: StatsProv
        Optimizer->>Optimizer: preComputeStats(Plan, StatsProv)
        loop preComputeStats recursion
            Optimizer->>Plan: getSources()
            Plan-->>Optimizer: child PlanNodes
            Optimizer->>StatsProv: getStats(node)
            StatsProv-->>Optimizer: PlanNodeStatsEstimate
        end
        Optimizer->>Rew: new Rewriter(VariableAllocator, PlanNodeIdAllocator, Session, strategy, Optional StatsProv, nativeExecution)
    else strategy == ALWAYS or NEVER
        Optimizer->>Rew: new Rewriter(VariableAllocator, PlanNodeIdAllocator, Session, strategy, Optional empty, nativeExecution)
    end

    Optimizer->>Rew: accept(Plan, any StreamPreferredProperties)
    Rew-->>Optimizer: PlanWithProperties result
    Optimizer->>Optimizer: check for local ExchangeNode
    Optimizer-->>Planner: PlanOptimizerResult
Loading

Class diagram for new local exchange parent preference strategy integration

classDiagram
    class AddLocalExchanges {
        - Metadata metadata
        - StatsCalculator statsCalculator
        - boolean nativeExecution
        + AddLocalExchanges(Metadata metadata, StatsCalculator statsCalculator, boolean nativeExecution)
        + PlanOptimizerResult optimize(PlanNode plan, Session session, TypeProvider types, VariableAllocator variableAllocator, PlanNodeIdAllocator idAllocator, WarningCollector warningCollector)
        - void preComputeStats(PlanNode node, StatsProvider statsProvider)
    }

    class Rewriter {
        - VariableAllocator variableAllocator
        - PlanNodeIdAllocator idAllocator
        - Session session
        - TypeProvider types
        - LocalExchangeParentPreferenceStrategy parentPreferenceStrategy
        - Optional~StatsProvider~ statsProvider
        - boolean nativeExecution
        + Rewriter(VariableAllocator variableAllocator, PlanNodeIdAllocator idAllocator, Session session, LocalExchangeParentPreferenceStrategy parentPreferenceStrategy, Optional~StatsProvider~ statsProvider, boolean nativeExecution)
        + PlanWithProperties visitAggregation(AggregationNode node, StreamPreferredProperties parentPreferences)
    }

    class LocalExchangeParentPreferenceStrategy {
        <<enum>>
        + ALWAYS
        + NEVER
        + AUTOMATIC
    }

    class FeaturesConfig {
        - LocalExchangeParentPreferenceStrategy localExchangeParentPreferenceStrategy
        + LocalExchangeParentPreferenceStrategy getLocalExchangeParentPreferenceStrategy()
        + FeaturesConfig setLocalExchangeParentPreferenceStrategy(LocalExchangeParentPreferenceStrategy localExchangeParentPreferenceStrategy)
    }

    class SystemSessionProperties {
        + String LOCAL_EXCHANGE_PARENT_PREFERENCE_STRATEGY
        + LocalExchangeParentPreferenceStrategy getLocalExchangeParentPreferenceStrategy(Session session)
    }

    class PlanOptimizers {
        + PlanOptimizers(Metadata metadata, StatsCalculator statsCalculator, FeaturesConfig featuresConfig)
    }

    AddLocalExchanges *-- Rewriter
    Rewriter --> LocalExchangeParentPreferenceStrategy
    FeaturesConfig --> LocalExchangeParentPreferenceStrategy
    SystemSessionProperties --> LocalExchangeParentPreferenceStrategy
    PlanOptimizers --> AddLocalExchanges
    AddLocalExchanges --> StatsCalculator
    AddLocalExchanges --> StatsProvider
    Rewriter --> StatsProvider
    Rewriter --> AggregationNode
    Rewriter --> StreamPreferredProperties
Loading

Flow diagram for AUTOMATIC local exchange parent preference decision

flowchart TD
    A[Start visitAggregation] --> B{parentPreferenceStrategy}
    B -->|ALWAYS| C[useParentPreferences = true]
    B -->|NEVER| D[useParentPreferences = false]
    B -->|AUTOMATIC| E[Initialize parentPartitionCardinality = 1]

    E --> F{Has partitioningColumns and statsProvider}
    F -->|No| G[useParentPreferences = parentPartitionCardinality >= taskConcurrency]
    F -->|Yes| H[Get stats for source node]

    H --> I[For each partitionColumn]
    I --> J{distinctCount is NaN}
    J -->|Yes| K[Set parentPartitionCardinality = 0 and break]
    J -->|No| L[Multiply parentPartitionCardinality by distinctCount]
    L --> M{More partitionColumns?}
    M -->|Yes| I
    M -->|No| G
    K --> G

    C --> N[Derive childRequirements from parentPreferences]
    D --> O[Derive childRequirements from any StreamPreferredProperties]
    G --> P{parentPartitionCardinality >= taskConcurrency}
    P -->|true| N
    P -->|false| O
    N --> Q[Proceed with local exchange using parent preferences]
    O --> R[Proceed with local exchange using grouping keys only]
    Q --> S[End]
    R --> S[End]
Loading

File-Level Changes

Change Details Files
Make AddLocalExchanges honor a configurable parent-preference strategy, using stats-based cardinality when in AUTOMATIC mode.
  • Add StatsCalculator dependency to AddLocalExchanges and precompute stats only when AUTOMATIC strategy is selected.
  • Thread LocalExchangeParentPreferenceStrategy and optional StatsProvider into the internal Rewriter.
  • In aggregation handling, decide whether to use parent stream preferences based on ALWAYS/NEVER/AUTOMATIC strategy, comparing estimated parent partition cardinality against task concurrency and falling back when stats are unavailable.
  • Update PlanOptimizers and optimizer tests to construct AddLocalExchanges with the new StatsCalculator parameter.
presto-main-base/src/main/java/com/facebook/presto/sql/planner/optimizations/AddLocalExchanges.java
presto-main-base/src/main/java/com/facebook/presto/sql/planner/PlanOptimizers.java
presto-main-base/src/test/java/com/facebook/presto/sql/planner/optimizations/TestEliminateSorts.java
Expose local-exchange parent preference strategy as a configurable feature and session property.
  • Define LocalExchangeParentPreferenceStrategy enum (ALWAYS, NEVER, AUTOMATIC) in FeaturesConfig with default ALWAYS.
  • Add config binding and getter/setter for optimizer.local-exchange-parent-preference-strategy in FeaturesConfig and SystemSessionProperties.
  • Expose a session property LOCAL_EXCHANGE_PARENT_PREFERENCE_STRATEGY with metadata and accessor getLocalExchangeParentPreferenceStrategy.
  • Extend TestFeaturesConfig default and explicit property mapping tests to cover the new feature flag.
presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/FeaturesConfig.java
presto-main-base/src/main/java/com/facebook/presto/SystemSessionProperties.java
presto-main-base/src/test/java/com/facebook/presto/sql/analyzer/TestFeaturesConfig.java
Add planner tests to verify local exchange behavior under different parent-preference strategies and task concurrency.
  • Introduce testLocalExchangeWithParentPreference in TestLogicalPlanner to exercise ALWAYS, NEVER, and AUTOMATIC strategies with differing task concurrency values.
  • Implement helper assertLocalExchangeWithParentPreference to construct sessions with the new property and assert resulting distributed plans.
  • Verify that in AUTOMATIC mode parent preference is used only when estimated parent cardinality is at least task concurrency, and that the plan shapes match expectations for each case.
presto-main-base/src/test/java/com/facebook/presto/sql/planner/TestLogicalPlanner.java

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@feilong-liu feilong-liu left a comment

Choose a reason for hiding this comment

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

Add some comments, also consider add unit test for it

{
PlanWithProperties result = new Rewriter(variableAllocator, idAllocator, session, nativeExecution).accept(plan, any());
StatsProvider statsProvider = new CachingStatsProvider(statsCalculator, session, types);
preComputeStats(plan, statsProvider);
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.

Why need precompute here?

Copy link
Copy Markdown
Contributor Author

@kagamiori kagamiori Jan 28, 2026

Choose a reason for hiding this comment

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

Hi @feilong-liu, this is because visitAggregation() is called top-down from the root node recursively. The use of parent preference in visitAggregation() is done during the winding phase of the recursion (i.e., parent preference is passed from root to leaf), so the decision of whether to use parent preference should be made during the winding phase too. On the other hand, CachingStatsProvider produce stats during unwinding of its recursion (i.e., parent's stats is based on child's stats). If we call CachingStatsProvider::getStats() during the winding phase of visitAggregation(), the stats would be unknown because child's stats hasn't been calculated yet.

Update: Looked deeper and found that precomputing the stats is indeed unnecessary. The precomputation was added before when I saw that a test query got no stats in visitAggregation(). But I stepped through the execution and found that it was actually due to an internal plan node blocking the stats propagation. So I removed the preComputeStats here since it's irrelevant and unnecessary.

.constrainTo(node.getSource().getOutputVariables())
.withDefaultParallelism(session)
.withPartitioning(groupingKeys);
double parentPartitionCardinality = 1;
Copy link
Copy Markdown
Contributor

@feilong-liu feilong-liu Jan 20, 2026

Choose a reason for hiding this comment

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

In addition to rely on stats, perhaps also add one session property to control the behavior. It can be always_enabled, disabled, and cost_based. This will help the case where stats are not available or not accurate

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added. Thanks for the suggestion.

@kagamiori kagamiori force-pushed the adjust_parent_preference_in_addlocalexchanges branch 3 times, most recently from 4710a54 to 12d596d Compare January 28, 2026 00:18
@kagamiori kagamiori changed the title draft(optimizer): Disable parent preference in AddLocalExchanges when… perf(optimizer): Make cost-based strategy of using parent preference in AddLocalExchanges Jan 28, 2026
@kagamiori kagamiori requested a review from feilong-liu January 28, 2026 05:50
@kagamiori kagamiori force-pushed the adjust_parent_preference_in_addlocalexchanges branch from 12d596d to e99a9c8 Compare January 28, 2026 19:00
@kagamiori kagamiori marked this pull request as ready for review January 28, 2026 19:01
@kagamiori kagamiori requested review from a team and jaystarshot as code owners January 28, 2026 19:01
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • In the AUTOMATIC strategy, parentPartitionCardinality defaults to 1 when parent partitioning columns are absent or stats are unavailable, which can still enable parent preference for task_concurrency = 1; if the intent is to skip parent preference when stats are missing (as described in the PR), consider explicitly treating the "no stats / no partitioning" case as useParentPreferences = false.
  • The preComputeStats method eagerly traverses the entire plan tree and computes stats for every node; given that CachingStatsProvider already memoizes, you might want to rely on lazy getStats calls instead to avoid unnecessary work on large plans.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the AUTOMATIC strategy, `parentPartitionCardinality` defaults to `1` when parent partitioning columns are absent or stats are unavailable, which can still enable parent preference for `task_concurrency = 1`; if the intent is to skip parent preference when stats are missing (as described in the PR), consider explicitly treating the "no stats / no partitioning" case as `useParentPreferences = false`.
- The `preComputeStats` method eagerly traverses the entire plan tree and computes stats for every node; given that `CachingStatsProvider` already memoizes, you might want to rely on lazy `getStats` calls instead to avoid unnecessary work on large plans.

## Individual Comments

### Comment 1
<location> `presto-main-base/src/main/java/com/facebook/presto/sql/planner/optimizations/AddLocalExchanges.java:159-164` </location>
<code_context>
         return PlanOptimizerResult.optimizerResult(result.getNode(), optimizerTriggered);
     }

+    private void preComputeStats(PlanNode node, StatsProvider statsProvider)
+    {
+        for (PlanNode child : node.getSources()) {
+            preComputeStats(child, statsProvider);
+        }
+        statsProvider.getStats(node);
+    }
+
</code_context>

<issue_to_address>
**suggestion (performance):** Consider limiting or guarding the full-plan pre-computation of stats to avoid unnecessary work on large plans.

preComputeStats() recursively walks the full plan and calls statsProvider.getStats() on every node when the strategy is AUTOMATIC. For large plans this can be quite expensive, especially since AddLocalExchanges runs for every query and relatively late in optimization. If the decision logic only needs stats for specific node types or subtrees, consider narrowing the traversal or adding a cheap guard (e.g., early exit when stats are disabled/unavailable). Alternatively, prefer on-demand stats with caching instead of a full upfront traversal.

Suggested implementation:

```java
            StatsProvider provider = new CachingStatsProvider(statsCalculator, session, types);
            if (shouldPreComputeStats(plan, provider)) {
                preComputeStats(plan, provider, MAX_PRECOMPUTE_STATS_NODES);
            }
            statsProvider = Optional.of(provider);
        }

        PlanWithProperties result = new Rewriter(variableAllocator, idAllocator, session, strategy, statsProvider, nativeExecution).accept(plan, any());
        boolean optimizerTriggered = PlanNodeSearcher.searchFrom(result.getNode()).where(node -> node instanceof ExchangeNode && ((ExchangeNode) node).getScope().isLocal()).findFirst().isPresent();
        return PlanOptimizerResult.optimizerResult(result.getNode(), optimizerTriggered);
    }

    private static final int MAX_PRECOMPUTE_STATS_NODES = 10_000;

    private boolean shouldPreComputeStats(PlanNode root, StatsProvider statsProvider)
    {
        // Cheap guard: if we can't get meaningful stats for the root, skip the full traversal.
        PlanNodeStatsEstimate rootStats = statsProvider.getStats(root);
        return !rootStats.isOutputRowCountUnknown();
    }

    private void preComputeStats(PlanNode node, StatsProvider statsProvider, int remainingBudget)
    {
        if (remainingBudget <= 0) {
            return;
        }

        int budget = remainingBudget - 1;
        for (PlanNode child : node.getSources()) {
            if (budget <= 0) {
                break;
            }
            int before = budget;
            preComputeStats(child, statsProvider, budget);
            // Heuristic: assume each recursive call consumes at least one unit of budget.
            // For safety, decrement by one after each child to avoid unbounded traversal.
            budget = before - 1;
        }
        statsProvider.getStats(node);
    }

```

1. If the actual `PlanNodeStatsEstimate` API differs (e.g., no `isOutputRowCountUnknown()`), adjust `shouldPreComputeStats` to use the correct way of checking whether stats are unavailable, such as comparing to `PlanNodeStatsEstimate.unknown()`.
2. The `MAX_PRECOMPUTE_STATS_NODES` value (10_000) can be tuned or made configurable via a session property if your codebase typically uses a different limit for “large” plans.
3. If you prefer a more precise budget accounting, you can rework `preComputeStats` to return the remaining budget instead of using the simple decrement heuristic shown here, but keep the same guard and budget pattern to avoid full-plan walks.
</issue_to_address>

### Comment 2
<location> `presto-main-base/src/test/java/com/facebook/presto/sql/planner/TestLogicalPlanner.java:2162-2165` </location>
<code_context>
+        assertLocalExchangeWithParentPreference(query, "NEVER", "4", false);
+        assertLocalExchangeWithParentPreference(query, "NEVER", "2", false);
+
+        // Test AUTOMATIC strategy: cost-based decision.
+        // When task concurrency (4) > parent cardinality (3), don't use parent preferences.
+        assertLocalExchangeWithParentPreference(query, "AUTOMATIC", "4", false);
+        // When task concurrency (2) <= parent cardinality (3), use parent preferences.
+        assertLocalExchangeWithParentPreference(query, "AUTOMATIC", "2", true);
+    }
</code_context>

<issue_to_address>
**issue (testing):** Add a test for AUTOMATIC strategy when stats are not available to assert we fall back to not using parent preference

The current test only covers AUTOMATIC when stats are available. Please add a case where stats are missing (e.g., a plan/table without stats or configuration that disables stats) and assert that AUTOMATIC behaves like NEVER (no parent preference). This ensures regressions in the `statsProvider.isPresent()` / pre-computation path are caught.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +2162 to +2165
// Test AUTOMATIC strategy: cost-based decision.
// When task concurrency (4) > parent cardinality (3), don't use parent preferences.
assertLocalExchangeWithParentPreference(query, "AUTOMATIC", "4", false);
// When task concurrency (2) <= parent cardinality (3), use parent preferences.
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.

issue (testing): Add a test for AUTOMATIC strategy when stats are not available to assert we fall back to not using parent preference

The current test only covers AUTOMATIC when stats are available. Please add a case where stats are missing (e.g., a plan/table without stats or configuration that disables stats) and assert that AUTOMATIC behaves like NEVER (no parent preference). This ensures regressions in the statsProvider.isPresent() / pre-computation path are caught.

Copy link
Copy Markdown
Contributor

@steveburnett steveburnett left a comment

Choose a reason for hiding this comment

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

Please include documentation for the new property, as described in Designing Your Code in CONTRIBUTING.md:

"All new language features, new functions, session and config properties, and major features have documentation added"

@kagamiori kagamiori force-pushed the adjust_parent_preference_in_addlocalexchanges branch from e99a9c8 to 23c4f64 Compare January 29, 2026 05:19
@kagamiori
Copy link
Copy Markdown
Contributor Author

kagamiori commented Jan 29, 2026

Please include documentation for the new property, as described in Designing Your Code in CONTRIBUTING.md:

"All new language features, new functions, session and config properties, and major features have documentation added"

Hi @feilong-liu, do you have a recommendation of where the right place to document the new config added in FeaturesConfig.java would be? Thanks!

@feilong-liu
Copy link
Copy Markdown
Contributor

Please include documentation for the new property, as described in Designing Your Code in CONTRIBUTING.md:
"All new language features, new functions, session and config properties, and major features have documentation added"

Hi @feilong-liu, do you have a recommendation of where the right place to document the new config added in FeaturesConfig.java would be? Thanks!

presto-docs/src/main/sphinx/admin/properties-session.rst for session property
presto-docs/src/main/sphinx/admin/properties.rst for feature config

Also you can try AI to write the doc, it's very good at it.

Copy link
Copy Markdown
Contributor

@feilong-liu feilong-liu left a comment

Choose a reason for hiding this comment

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

Overall lgtm

Comment on lines +149 to +150
StatsProvider provider = new CachingStatsProvider(statsCalculator, session, types);
statsProvider = Optional.of(provider);
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.

Suggested change
StatsProvider provider = new CachingStatsProvider(statsCalculator, session, types);
statsProvider = Optional.of(provider);
statsProvider = Optional.of(new CachingStatsProvider(statsCalculator, session, types));

@kagamiori kagamiori force-pushed the adjust_parent_preference_in_addlocalexchanges branch from 23c4f64 to fcdbe23 Compare January 30, 2026 04:40
@kagamiori kagamiori requested a review from elharo as a code owner January 30, 2026 04:40
…n limit parallelism when the cardinality of the partition column of parent preference is low. In a setup where a query is allowed to use many cores, limiting the parallelism significantly affect the query latency. More details can be found in prestodb#26961.

This PR makes three changes:
* This PR introduces a new feature config `localExchangeParentPreferenceStrategy` that has three values: ALWAYS, NEVER, and AUTOMATIC. The default value is ALWAYS (i.e., current behavior).
* This PR makes AddLocalExchanges to use parent preference according to the localExchangeParentPreferenceStrategy. When localExchangeParentPreferenceStrategy is ALWAYS, it always uses parent preference. When localExchangeParentPreferenceStrategy is NEVER, it always not uses parent preference. When localExchangeParentPreferenceStrategy is AUTOMATIC, it uses parent preference only when the estimated cardinality is larger than the task concurrency. (If estimated stats is not available, parent preference is not used.)
  - Notice that the estimated stats is only calculated when localExchangeParentPreferenceStrategy is AUTOMATIC.
* This PR adds unit tests of the new config and the change to local-exchange.
@kagamiori kagamiori force-pushed the adjust_parent_preference_in_addlocalexchanges branch from fcdbe23 to 553a31a Compare January 30, 2026 04:45
Copy link
Copy Markdown
Contributor

@steveburnett steveburnett left a comment

Choose a reason for hiding this comment

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

LGTM! (docs)

Pull branch, local doc build, looks good.

Thank you for the documentation!

@feilong-liu feilong-liu merged commit 4e8c0ba into prestodb:master Jan 30, 2026
87 of 88 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

from:Meta PR from Meta

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants