You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by "xiangfu0 (via GitHub)" <gi...@apache.org> on 2026/10/23 20:39:26 UTC

[PR] Query optional segments in multi-stage leaf stages [pinot]

xiangfu0 opened a new pull request, #20017:
URL: https://github.com/apache/pinot/pull/20017

   The broker routes a new segment as optional until it sees the segment ONLINE in the external view. The single-stage engine sends optional segments to the servers, which query them if loaded and skip them otherwise. Multi-stage leaf stages dropped them, so right after a segment upload or a realtime commit a multi-stage query could return fewer rows than the single-stage one, with no error (the WindowFunnelTest flake worked around in #20015).
   
   Leaf workers now carry their optional segments apart from their segments, and the server leaf sets them as `InstanceRequest.optionalSegments` (`TableSegmentsInfo.optionalSegments` for logical tables). They are not merged into the segment list as in #19144: a segment that is not loaded yet would then fail the query as missing.
   
   - Covered: non-partitioned leaf stages of physical and logical tables, on both the default planner and the physical optimizer.
   - Unchanged: partitioned leaf stages, and replicated leaf stages (their segment list does not come from instance selection).
   - Wire: new `WorkerMetadata.optionalSegmentsMap` proto field, or an `optionalSegmentsMap` custom property under the legacy JSON encoding. An older server ignores either and skips optional segments as before; an older broker sends none.
   - `WorkerManager#filterLeafStageSegments` overrides see the optional segments in a separate map (`DispatchablePlanMetadata#getWorkerIdToOptionalSegmentsMap`).
   
   Testing: new `OptionalSegmentsQueryRunnerTest` (a loaded optional segment is queried and a missing one is skipped without error, on both planners; returns half the rows without this change), plus planner, serde (both encodings) and `ServerPlanRequestUtils` unit tests.
   
   Related: #18223, #19537.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Query optional segments in multi-stage leaf stages [pinot]

Posted by "codecov-commenter (via GitHub)" <gi...@apache.org>.
codecov-commenter commented on PR #20017:
URL: https://github.com/apache/pinot/pull/20017#issuecomment-6375884996

   ## [Codecov](https://app.codecov.io/gh/apache/pinot/pull/20017?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) Report
   :white_check_mark: All modified and coverable lines are covered by tests.
   :white_check_mark: Project coverage is 100.00%. Comparing base ([`678c8b0`](https://app.codecov.io/gh/apache/pinot/commit/678c8b07a90878662c2339d7701922b2cbb45ba5?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)) to head ([`1745fee`](https://app.codecov.io/gh/apache/pinot/commit/1745fee9a18e68ee9c7794cd0fa513585e71eaea?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)).
   :warning: Report is 9 commits behind head on master.
   
   <details><summary>Additional details and impacted files</summary>
   
   
   
   ```diff
   @@              Coverage Diff               @@
   ##             master    #20017       +/-   ##
   ==============================================
   + Coverage     69.68%   100.00%   +30.31%     
   + Complexity     1491         6     -1485     
   ==============================================
     Files          3548         3     -3545     
     Lines        235054         6   -235048     
     Branches      37702         0    -37702     
   ==============================================
   - Hits         163804         6   -163798     
   + Misses        58586         0    -58586     
   + Partials      12664         0    -12664     
   ```
   
   | [Flag](https://app.codecov.io/gh/apache/pinot/pull/20017/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Coverage Δ | |
   |---|---|---|
   | [integration](https://app.codecov.io/gh/apache/pinot/pull/20017/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `100.00% <ø> (ø)` | |
   | [integration1](https://app.codecov.io/gh/apache/pinot/pull/20017/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `100.00% <ø> (ø)` | |
   | [integration2](https://app.codecov.io/gh/apache/pinot/pull/20017/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   | [java-25](https://app.codecov.io/gh/apache/pinot/pull/20017/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `100.00% <ø> (+30.31%)` | :arrow_up: |
   | [lane-a](https://app.codecov.io/gh/apache/pinot/pull/20017/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `100.00% <ø> (ø)` | |
   | [lane-b](https://app.codecov.io/gh/apache/pinot/pull/20017/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   | [temurin](https://app.codecov.io/gh/apache/pinot/pull/20017/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `100.00% <ø> (+30.31%)` | :arrow_up: |
   | [unittests](https://app.codecov.io/gh/apache/pinot/pull/20017/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   | [unittests1](https://app.codecov.io/gh/apache/pinot/pull/20017/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   | [unittests2](https://app.codecov.io/gh/apache/pinot/pull/20017/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   
   Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#carryforward-flags-in-the-pull-request-comment) to find out more.
   </details>
   
   [:umbrella: View full report in Codecov by Harness](https://app.codecov.io/gh/apache/pinot/pull/20017?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).   
   :loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
   <details><summary> :rocket: New features to boost your workflow: </summary>
   
   - :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
   </details>


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Query optional segments in multi-stage leaf stages [pinot]

Posted by "xiangfu0 (via GitHub)" <gi...@apache.org>.
xiangfu0 commented on code in PR #20017:
URL: https://github.com/apache/pinot/pull/20017#discussion_r4365200111


##########
pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/plan/server/ServerPlanRequestUtils.java:
##########
@@ -203,18 +206,33 @@ public static List<InstanceRequest> constructServerQueryRequests(OpChainExecutio
       return List.of(
           compileInstanceRequest(executionContext, new PinotQuery(pinotQuery), timeBoundary, TableType.OFFLINE,
               offlineTableDataManager.getTableName(), offlineTableConfigAndSchema.getLeft(),
-              offlineTableConfigAndSchema.getRight(), offlineSegments, null),
+              offlineTableConfigAndSchema.getRight(), offlineSegments,
+              copyOptionalSegments(optionalSegmentsMap, TableType.OFFLINE.name()), null),
           compileInstanceRequest(executionContext, pinotQuery, timeBoundary, TableType.REALTIME,
               realtimeTableDataManager.getTableName(), realtimeTableConfigAndSchema.getLeft(),
-              realtimeTableConfigAndSchema.getRight(), realtimeSegments, null));
+              realtimeTableConfigAndSchema.getRight(), realtimeSegments,
+              copyOptionalSegments(optionalSegmentsMap, TableType.REALTIME.name()), null));
     }
   }
 
+  /// Returns a copy of the optional segments under the given key, or `null` when there are none. A copy because the
+  /// list is handed over to [InstanceRequest], whose consumers may append to it (e.g. the newly added segments of an
+  /// upsert table), while the original belongs to the worker metadata.
+  @Nullable
+  private static List<String> copyOptionalSegments(@Nullable Map<String, List<String>> optionalSegmentsMap,

Review Comment:
   Thanks. One nuance: on the server the worker metadata belongs to the one request, so the copy keeps that request's `WorkerMetadata` unchanged rather than guarding state shared across queries.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Query optional segments in multi-stage leaf stages [pinot]

Posted by "xiangfu0 (via GitHub)" <gi...@apache.org>.
xiangfu0 commented on code in PR #20017:
URL: https://github.com/apache/pinot/pull/20017#discussion_r4364304374


##########
pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/plan/server/ServerPlanRequestUtils.java:
##########
@@ -203,18 +206,33 @@ public static List<InstanceRequest> constructServerQueryRequests(OpChainExecutio
       return List.of(
           compileInstanceRequest(executionContext, new PinotQuery(pinotQuery), timeBoundary, TableType.OFFLINE,
               offlineTableDataManager.getTableName(), offlineTableConfigAndSchema.getLeft(),
-              offlineTableConfigAndSchema.getRight(), offlineSegments, null),
+              offlineTableConfigAndSchema.getRight(), offlineSegments,
+              copyOptionalSegments(optionalSegmentsMap, TableType.OFFLINE.name()), null),
           compileInstanceRequest(executionContext, pinotQuery, timeBoundary, TableType.REALTIME,
               realtimeTableDataManager.getTableName(), realtimeTableConfigAndSchema.getLeft(),
-              realtimeTableConfigAndSchema.getRight(), realtimeSegments, null));
+              realtimeTableConfigAndSchema.getRight(), realtimeSegments,
+              copyOptionalSegments(optionalSegmentsMap, TableType.REALTIME.name()), null));
     }
   }
 
+  /// Returns a copy of the optional segments under the given key, or `null` when there are none. A copy because the
+  /// list is handed over to [InstanceRequest], whose consumers may append to it (e.g. the newly added segments of an
+  /// upsert table), while the original belongs to the worker metadata.
+  @Nullable
+  private static List<String> copyOptionalSegments(@Nullable Map<String, List<String>> optionalSegmentsMap,

Review Comment:
   Good call making this a copy rather than handing over the worker metadata's list directly. It's not just defensive: on an upsert table the server appends the newly-added segments to this exact list in place (`SingleTableExecutionInfo` does `optionalSegments.add(...)`), and the worker metadata map is shared across queries and read concurrently by other planning threads, so reusing it would corrupt shared state. The comment captures the "why" well.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Query optional segments in multi-stage leaf stages [pinot]

Posted by "xiangfu0 (via GitHub)" <gi...@apache.org>.
xiangfu0 closed pull request #20017: Query optional segments in multi-stage leaf stages
URL: https://github.com/apache/pinot/pull/20017


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Query optional segments in multi-stage leaf stages [pinot]

Posted by "xiangfu0 (via GitHub)" <gi...@apache.org>.
xiangfu0 commented on code in PR #20017:
URL: https://github.com/apache/pinot/pull/20017#discussion_r4366341258


##########
pinot-query-planner/src/main/java/org/apache/pinot/query/routing/WorkerManager.java:
##########
@@ -1231,6 +1269,10 @@ private void setSegmentsForReplicatedLeafFragment(DispatchablePlanMetadata metad
   /// segment lists (or the whole map) on the metadata, rather than by editing them in place: part of what the
   /// assignment is built from is the broker's published partition metadata, shared across queries and read concurrently
   /// by other planning threads. What is handed over is nevertheless kept safe to edit in place.
+  ///
+  /// The optional segments of each worker are held apart from its segment lists, in
+  /// [DispatchablePlanMetadata#getWorkerIdToOptionalSegmentsMap()], under the same worker ids; an override that filters

Review Comment:
   Good call documenting that an override must now filter the optional map too. Worth knowing there are no in-tree overrides of `filterLeafStageSegments`, so any subclass that prunes segments (e.g. a downstream fork) won't filter optional segments until updated — the doc is the right mitigation, just flagging the behavioral obligation for downstream maintainers.



##########
pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/plan/server/ServerPlanRequestUtils.java:
##########
@@ -203,18 +206,33 @@ public static List<InstanceRequest> constructServerQueryRequests(OpChainExecutio
       return List.of(
           compileInstanceRequest(executionContext, new PinotQuery(pinotQuery), timeBoundary, TableType.OFFLINE,
               offlineTableDataManager.getTableName(), offlineTableConfigAndSchema.getLeft(),
-              offlineTableConfigAndSchema.getRight(), offlineSegments, null),
+              offlineTableConfigAndSchema.getRight(), offlineSegments,
+              copyOptionalSegments(optionalSegmentsMap, TableType.OFFLINE.name()), null),
           compileInstanceRequest(executionContext, pinotQuery, timeBoundary, TableType.REALTIME,
               realtimeTableDataManager.getTableName(), realtimeTableConfigAndSchema.getLeft(),
-              realtimeTableConfigAndSchema.getRight(), realtimeSegments, null));
+              realtimeTableConfigAndSchema.getRight(), realtimeSegments,
+              copyOptionalSegments(optionalSegmentsMap, TableType.REALTIME.name()), null));
     }
   }
 
+  /// Returns a copy of the optional segments under the given key, or `null` when there are none. A copy because the
+  /// list is handed over to [InstanceRequest], whose consumers may append to it (e.g. the newly added segments of an
+  /// upsert table), while the original belongs to the worker metadata.
+  @Nullable
+  private static List<String> copyOptionalSegments(@Nullable Map<String, List<String>> optionalSegmentsMap,
+      String key) {
+    if (optionalSegmentsMap == null) {
+      return null;
+    }
+    List<String> optionalSegments = optionalSegmentsMap.get(key);
+    return CollectionUtils.isNotEmpty(optionalSegments) ? new ArrayList<>(optionalSegments) : null;

Review Comment:
   The defensive copy here is correct and load-bearing: `SingleTableExecutionInfo` appends newly-added upsert segments onto this list in place, so handing over the worker-metadata-owned list directly would mutate shared planning state. Nice that the test asserts `assertNotSame` on it.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Query optional segments in multi-stage leaf stages [pinot]

Posted by "xiangfu0 (via GitHub)" <gi...@apache.org>.
xiangfu0 commented on PR #20017:
URL: https://github.com/apache/pinot/pull/20017#issuecomment-6480976065

   Closing because #20015 addresses the integration setup race behind the observed WindowFunnelTest failure. The broader optional-segment behavior change in this PR is deferred pending an independently demonstrated production case.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Query optional segments in multi-stage leaf stages [pinot]

Posted by "xiangfu0 (via GitHub)" <gi...@apache.org>.
xiangfu0 commented on code in PR #20017:
URL: https://github.com/apache/pinot/pull/20017#discussion_r4396978682


##########
pinot-query-planner/src/main/java/org/apache/pinot/query/routing/WorkerManager.java:
##########
@@ -1231,6 +1269,10 @@ private void setSegmentsForReplicatedLeafFragment(DispatchablePlanMetadata metad
   /// segment lists (or the whole map) on the metadata, rather than by editing them in place: part of what the
   /// assignment is built from is the broker's published partition metadata, shared across queries and read concurrently
   /// by other planning threads. What is handed over is nevertheless kept safe to edit in place.
+  ///
+  /// The optional segments of each worker are held apart from its segment lists, in
+  /// [DispatchablePlanMetadata#getWorkerIdToOptionalSegmentsMap()], under the same worker ids; an override that filters

Review Comment:
   Acknowledged. The extension-point Javadoc explicitly requires overrides to filter getWorkerIdToOptionalSegmentsMap() alongside the required assignments, using the same worker IDs. Downstream overrides that prune segments need to apply that policy to both maps.



##########
pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/plan/server/ServerPlanRequestUtils.java:
##########
@@ -203,18 +206,33 @@ public static List<InstanceRequest> constructServerQueryRequests(OpChainExecutio
       return List.of(
           compileInstanceRequest(executionContext, new PinotQuery(pinotQuery), timeBoundary, TableType.OFFLINE,
               offlineTableDataManager.getTableName(), offlineTableConfigAndSchema.getLeft(),
-              offlineTableConfigAndSchema.getRight(), offlineSegments, null),
+              offlineTableConfigAndSchema.getRight(), offlineSegments,
+              copyOptionalSegments(optionalSegmentsMap, TableType.OFFLINE.name()), null),
           compileInstanceRequest(executionContext, pinotQuery, timeBoundary, TableType.REALTIME,
               realtimeTableDataManager.getTableName(), realtimeTableConfigAndSchema.getLeft(),
-              realtimeTableConfigAndSchema.getRight(), realtimeSegments, null));
+              realtimeTableConfigAndSchema.getRight(), realtimeSegments,
+              copyOptionalSegments(optionalSegmentsMap, TableType.REALTIME.name()), null));
     }
   }
 
+  /// Returns a copy of the optional segments under the given key, or `null` when there are none. A copy because the
+  /// list is handed over to [InstanceRequest], whose consumers may append to it (e.g. the newly added segments of an
+  /// upsert table), while the original belongs to the worker metadata.
+  @Nullable
+  private static List<String> copyOptionalSegments(@Nullable Map<String, List<String>> optionalSegmentsMap,
+      String key) {
+    if (optionalSegmentsMap == null) {
+      return null;
+    }
+    List<String> optionalSegments = optionalSegmentsMap.get(key);
+    return CollectionUtils.isNotEmpty(optionalSegments) ? new ArrayList<>(optionalSegments) : null;

Review Comment:
   Confirmed: copyOptionalSegments creates a new ArrayList before building the InstanceRequest, and testHybridTableRequestsCarryOptionalSegmentsPerTableType asserts that it differs by identity from the worker-metadata list. This lets the server append newly added upsert segments without changing the planning metadata.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org