gortiz commented on code in PR #19783:
URL: https://github.com/apache/pinot/pull/19783#discussion_r4280602787


##########
pinot-broker/src/main/java/org/apache/pinot/broker/routing/segmentpartition/SegmentPartitionUtils.java:
##########
@@ -76,9 +100,42 @@ public static SegmentPartitionInfo 
extractPartitionInfo(String tableNameWithType
       return INVALID_PARTITION_INFO;
     }
 
-    return new SegmentPartitionInfo(partitionColumn,
-        PartitionFunctionFactory.getPartitionFunction(columnPartitionMetadata),
-        columnPartitionMetadata.getPartitions());
+    return new SegmentPartitionInfo(partitionColumn, 
getPartitionFunction(columnPartitionMetadata),
+        getPartitions(columnPartitionMetadata));
+  }
+
+  /// Returns a partition function for the given metadata, shared with the 
other segments with equal metadata.
+  private static PartitionFunction 
getPartitionFunction(ColumnPartitionMetadata columnPartitionMetadata) {
+    PartitionFunctionKey key = new 
PartitionFunctionKey(columnPartitionMetadata.getFunctionName(),
+        columnPartitionMetadata.getNumPartitions(), 
columnPartitionMetadata.getFunctionConfig());
+    PartitionFunction partitionFunction = PARTITION_FUNCTION_CACHE.get(key);
+    if (partitionFunction != null) {
+      return partitionFunction;
+    }
+    partitionFunction = 
PartitionFunctionFactory.getPartitionFunction(columnPartitionMetadata);
+    if (PARTITION_FUNCTION_CACHE.size() < MAX_CACHED_PARTITION_FUNCTIONS) {

Review Comment:
   Agreed. More than 1024 distinct combinations is unlikely on one broker, and 
past the limit the behavior is the same as before this PR. I will add an 
eviction policy if we ever see it in practice.



##########
pinot-broker/src/main/java/org/apache/pinot/broker/routing/timeboundary/TimeBoundaryManager.java:
##########
@@ -206,20 +208,58 @@ public synchronized void onAssignmentChange(IdealState 
idealState, ExternalView
       Set<String> onlineSegments) {
     updateExplicitlySetTimeBoundary(idealState);
 
+    // Read the ZK metadata of the new segments in one batch
+    List<String> newSegments = new ArrayList<>();
+    List<String> newSegmentZKMetadataPaths = new ArrayList<>();
     for (String segment : onlineSegments) {
       // NOTE: Only update the segment end time when there are ONLINE 
instances in the external view to prevent moving
       //       the time boundary before the new segment is picked up by the 
servers
-      Map<String, String> instanceStateMap = externalView.getStateMap(segment);
-      if (instanceStateMap != null && 
instanceStateMap.containsValue(SegmentStateModel.ONLINE)) {
-        _endTimeMsMap.computeIfAbsent(segment, k -> 
extractEndTimeMsFromSegmentZKMetadataZNRecord(segment,
-            _propertyStore.get(_segmentZKMetadataPathPrefix + segment, null, 
AccessOption.PERSISTENT)));
+      if (!_endTimeMsMap.containsKey(segment)) {
+        Map<String, String> instanceStateMap = 
externalView.getStateMap(segment);
+        if (instanceStateMap != null && 
instanceStateMap.containsValue(SegmentStateModel.ONLINE)) {
+          newSegments.add(segment);
+          newSegmentZKMetadataPaths.add(_segmentZKMetadataPathPrefix + 
segment);
+        }
+      }
+    }
+    // NOTE: Read before changing any state, so that a failed read leaves the 
state as it was. The read throws on a ZK
+    //       error other than a missing node, so that the routing entry keeps 
its IS/EV versions and retries.
+    List<ZNRecord> znRecords = newSegments.isEmpty() ? List.of()
+        : _propertyStore.get(newSegmentZKMetadataPaths, null, 
AccessOption.PERSISTENT, true);
+    boolean recomputeMaxEndTime = false;
+    // NOTE: Removing a segment can only lower the max end time, so a full 
scan is needed only when a removed segment
+    //       holds the current max end time.
+    Iterator<Map.Entry<String, Long>> iterator = 
_endTimeMsMap.entrySet().iterator();
+    while (iterator.hasNext()) {
+      Map.Entry<String, Long> entry = iterator.next();
+      if (!onlineSegments.contains(entry.getKey())) {
+        if (entry.getValue() >= _maxEndTimeMs) {
+          recomputeMaxEndTime = true;
+        }
+        iterator.remove();
+      }
+    }
+    if (recomputeMaxEndTime) {
+      _maxEndTimeMs = computeMaxEndTimeMs();
+    }
+    int numNewSegments = newSegments.size();
+    for (int i = 0; i < numNewSegments; i++) {
+      String segment = newSegments.get(i);
+      ZNRecord znRecord = znRecords.get(i);
+      if (znRecord == null) {
+        // NOTE: The node does not exist. Do not record the segment, so that 
the next assignment change reads it again.
+        LOGGER.warn("Failed to find segment ZK metadata for segment: {}, 
table: {}, will retry on next change", segment,

Review Comment:
   Agreed. If the WARN gets noisy, I will log it once per segment.



-- 
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