Jackie-Jiang commented on code in PR #19891:
URL: https://github.com/apache/pinot/pull/19891#discussion_r4300442487


##########
pinot-broker/src/main/java/org/apache/pinot/broker/routing/instanceselector/BaseInstanceSelector.java:
##########
@@ -577,16 +595,22 @@ public SelectionResult select(BrokerRequest 
brokerRequest, List<String> segments
     SegmentStates segmentStates = _segmentStates;
     InstanceMapping mapping = select(segments, requestIdInt, segmentStates, 
queryOptions);
     Set<String> unavailableSegments = segmentStates.getUnavailableSegments();
+    Set<String> segmentsWithoutCandidates = 
segmentStates.getSegmentsWithoutCandidates();
 
     if (unavailableSegments.isEmpty()) {
       return new SelectionResult(mapping, List.of(), 0);
     } else {
       List<String> unavailableSegmentsForRequest = new ArrayList<>();
+      boolean failOpenEligible = false;
       for (String segment : segments) {
         if (unavailableSegments.contains(segment)) {
           unavailableSegmentsForRequest.add(segment);
+          failOpenEligible |= !segmentsWithoutCandidates.contains(segment);
         }
       }
+      if (failOpenEligible) {
+        
_brokerMetrics.addMeteredGlobalValue(BrokerMeter.FAIL_OPEN_ELIGIBLE_REQUESTS, 
1);

Review Comment:
   [P2] Count eligible requests before subclass selection can throw.
   
   The protected `select(...)` call at line 596 runs before this increment. For 
`multiStageReplicaGroup`, an old segment whose ONLINE IS/EV candidates are all 
excluded has no enabled candidate list, and 
`MultiStageReplicaGroupSelector.assign()` throws before reaching this meter. 
The segment meter increments, but affected requests are omitted. Classify and 
record eligibility from the captured snapshot before invoking subclass 
selection, preserving the existing exception behavior. The new test's 
`selectorType` provider does not include this selector.



##########
pinot-broker/src/main/java/org/apache/pinot/broker/routing/instanceselector/BaseInstanceSelector.java:
##########
@@ -446,6 +447,9 @@ void refreshSegmentStates() {
                 + "(all candidate instances: {} are disabled, counting segment 
as unavailable)", segment,
             _tableNameWithType, candidateInstances);
         unavailableSegments.add(segment);
+        if (candidates.isEmpty()) {
+          segmentsWithoutCandidates.add(segment);

Review Comment:
   [P2] Distinguish failure-detector exclusions from administrative disables.
   
   A nonempty candidate list does not establish the eligibility described in 
the PR's testing section. The supplied enabled-instance set excludes servers 
with `HELIX_ENABLED=false`, `QUERIES_DISABLED=true`, or shutdown in progress, 
as well as failure-detector exclusions. If all replicas are administratively 
disabled while IS/EV remain ONLINE, both new meters count them as fail-open 
eligible. Please carry the exclusion reason into this classification and 
require at least one candidate that is still administratively enabled but 
excluded by the failure detector. A routing-manager test contrasting these 
cases would cover the distinction.



##########
pinot-broker/src/main/java/org/apache/pinot/broker/routing/instanceselector/SegmentStates.java:
##########
@@ -38,12 +38,22 @@ public class SegmentStates {
   private final Map<String, List<SegmentInstanceCandidate>> 
_instanceCandidatesMap;
   private final Set<String> _servingInstances;
   private final Set<String> _unavailableSegments;
+  private final Set<String> _segmentsWithoutCandidates;

Review Comment:
   Simplification: store `_failOpenEligibleSegments` directly here. Both 
consumers currently reconstruct eligibility as unavailable minus 
candidate-less, which introduces compound conditions and negation. An explicit 
eligible set lets transition detection use 
`!previousEligibleSegments.contains(segment)` and request classification use 
`eligibleSegments.contains(segment)`. The existing three-argument constructor 
can default it to `Set.of()`, preserving its conservative behavior. Keep the 
set in this same published snapshot so routing and eligibility stay consistent.



##########
pinot-broker/src/main/java/org/apache/pinot/broker/routing/instanceselector/BaseInstanceSelector.java:
##########
@@ -470,7 +474,21 @@ void refreshSegmentStates() {
       }
     }
 
-    _segmentStates = new SegmentStates(instanceCandidatesMap, 
servingInstances, unavailableSegments);
+    SegmentStates previousSegmentStates = _segmentStates;
+    Set<String> previousUnavailableSegments =
+        previousSegmentStates != null ? 
previousSegmentStates.getUnavailableSegments() : Set.of();
+    Set<String> previousSegmentsWithoutCandidates =
+        previousSegmentStates != null ? 
previousSegmentStates.getSegmentsWithoutCandidates() : Set.of();
+    for (String segment : unavailableSegments) {
+      boolean wasAlreadyUnavailableWithCandidates =
+          previousUnavailableSegments.contains(segment) && 
!previousSegmentsWithoutCandidates.contains(segment);
+      if (!segmentsWithoutCandidates.contains(segment) && 
!wasAlreadyUnavailableWithCandidates) {
+        _brokerMetrics.addMeteredTableValue(_tableNameWithType, 
BrokerMeter.FAIL_OPEN_ELIGIBLE_SEGMENTS, 1);

Review Comment:
   [P2] Emit segment transitions only from the main table selector.
   
   `BaseBrokerRoutingManager` creates a separate selector for each configured 
table sampler, using the same table name and `BrokerMetrics`, and updates all 
of them on instance changes. A segment included in N samplers therefore 
increments this meter N+1 times for one transition. The main routing entry 
should own table-level emission, following the existing replica-health 
reporting approach. An overlapping-sampler test would catch this. The 
transition count can also be accumulated during the existing old-segment loop 
and emitted once, avoiding the extra pass and repeated meter calls.



##########
pinot-broker/src/main/java/org/apache/pinot/broker/routing/instanceselector/BaseInstanceSelector.java:
##########
@@ -577,16 +595,22 @@ public SelectionResult select(BrokerRequest 
brokerRequest, List<String> segments
     SegmentStates segmentStates = _segmentStates;
     InstanceMapping mapping = select(segments, requestIdInt, segmentStates, 
queryOptions);
     Set<String> unavailableSegments = segmentStates.getUnavailableSegments();
+    Set<String> segmentsWithoutCandidates = 
segmentStates.getSegmentsWithoutCandidates();
 
     if (unavailableSegments.isEmpty()) {
       return new SelectionResult(mapping, List.of(), 0);
     } else {
       List<String> unavailableSegmentsForRequest = new ArrayList<>();
+      boolean failOpenEligible = false;
       for (String segment : segments) {
         if (unavailableSegments.contains(segment)) {
           unavailableSegmentsForRequest.add(segment);
+          failOpenEligible |= !segmentsWithoutCandidates.contains(segment);
         }
       }
+      if (failOpenEligible) {
+        
_brokerMetrics.addMeteredGlobalValue(BrokerMeter.FAIL_OPEN_ELIGIBLE_REQUESTS, 
1);

Review Comment:
   [P2] Deduplicate request counts across scans of the same physical table.
   
   This increments once per `select` invocation, while the meter documents once 
per query per physical table. Both MSE planners route separate leaf scans 
independently. A non-partitioned self-join with distinct leaves that both touch 
an eligible segment can therefore increment twice for the same request and 
physical table. Aggregate eligibility in request-scoped state and emit once per 
physical table; a self-join regression with distinct leaf filters would cover 
this.



-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to