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