FrankChen021 commented on code in PR #20092:
URL: https://github.com/apache/druid/pull/20092#discussion_r4133467259


##########
indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/supervisor/SeekableStreamSupervisor.java:
##########
@@ -4367,101 +4371,36 @@ private void createNewTasks() throws 
JsonProcessingException
         }
 
         log.info("Creating new taskGroup[%d] for partitions[%s].", groupId, 
partitionGroups.get(groupId));
-        final DateTime minimumMessageTime;
-        if (ioConfig.getLateMessageRejectionStartDateTime().isPresent()) {
-          minimumMessageTime = 
ioConfig.getLateMessageRejectionStartDateTime().get();
-        } else {
-          minimumMessageTime = 
ioConfig.getLateMessageRejectionPeriod().isPresent()
-                               ? 
DateTimes.nowUtc().minus(ioConfig.getLateMessageRejectionPeriod().get())
-                               : null;
-        }
-
-        final DateTime maximumMessageTime = 
ioConfig.getEarlyMessageRejectionPeriod().isPresent()
-                                            ? DateTimes.nowUtc()
-                                                       
.plus(ioConfig.getTaskDuration())
-                                                       
.plus(ioConfig.getEarlyMessageRejectionPeriod().get())
-                                            : null;
-
-        final Map<PartitionIdType, OrderedSequenceNumber<SequenceOffsetType>> 
unfilteredStartingOffsets =
-            generateStartingSequencesForPartitionGroup(groupId, 
metadataOffsets, partitionsToReset);
-
-        final Map<PartitionIdType, OrderedSequenceNumber<SequenceOffsetType>> 
startingOffsets;
-        if (supportsPartitionExpiration()) {
-          startingOffsets = 
filterExpiredPartitionsFromStartingOffsets(unfilteredStartingOffsets);
-        } else {
-          startingOffsets = unfilteredStartingOffsets;
-        }
-
-        ImmutableMap<PartitionIdType, SequenceOffsetType> 
simpleStartingOffsets = startingOffsets
-            .entrySet()
-            .stream()
-            .filter(entry -> entry.getValue().get() != null)
-            .collect(
-                Collectors.collectingAndThen(
-                    Collectors.toMap(Entry::getKey, entry -> 
entry.getValue().get()),
-                    ImmutableMap::copyOf
-                )
-            );
-
-        ImmutableMap<PartitionIdType, SequenceOffsetType> 
simpleUnfilteredStartingOffsets;
-        if (supportsPartitionExpiration()) {
-          simpleUnfilteredStartingOffsets = unfilteredStartingOffsets
-              .entrySet()
-              .stream()
-              .filter(entry -> entry.getValue().get() != null)
-              .collect(
-                  Collectors.collectingAndThen(
-                      Collectors.toMap(Entry::getKey, entry -> 
entry.getValue().get()),
-                      ImmutableMap::copyOf
-                  )
-              );
-        } else {
-          simpleUnfilteredStartingOffsets = simpleStartingOffsets;
-        }
-
-        Set<PartitionIdType> exclusiveStartSequenceNumberPartitions;
-        if (!useExclusiveStartingSequence) {
-          exclusiveStartSequenceNumberPartitions = Collections.emptySet();
-        } else {
-          exclusiveStartSequenceNumberPartitions = startingOffsets
-              .entrySet()
-              .stream()
-              .filter(x -> x.getValue().get() != null
-                           && x.getValue().isExclusive())
-              .map(Entry::getKey)
-              .collect(Collectors.toSet());
-        }
-
-        // NEW: Extract end offsets for bounded mode
-        ImmutableMap<PartitionIdType, SequenceOffsetType> endOffsets = null;
-        if (ioConfig.isBounded()) {
-          endOffsets = ImmutableMap.copyOf(getEndOffsetsForGroup(groupId));
-        }
-
-        log.info(
-            "Initializing taskGroup[%d] with startingOffsets[%s] and 
endOffsets[%s]",
-            groupId,
-            simpleStartingOffsets,
-            endOffsets
-        );
-        newTaskGroups.put(
-            groupId,
-            new TaskGroup(
-                groupId,
-                simpleStartingOffsets,
-                simpleUnfilteredStartingOffsets,
-                endOffsets,
-                minimumMessageTime,
-                maximumMessageTime,
-                exclusiveStartSequenceNumberPartitions
-            )
-        );
+        newTaskGroups.put(groupId, buildNewTaskGroup(groupId, metadataOffsets, 
partitionsToReset));
       }
     }
 
     // If any partitions need a reset, issue a single batch reset.
     if (!partitionsToReset.isEmpty()) {
       resetInternal(createDataSourceMetaDataForReset(ioConfig.getStream(), 
partitionsToReset));
+
+      // The new task groups were built before the reset, so the ones that 
cover a partition which has to
+      // be reset hold no offset for it: 'getOffsetFromStorageForPartition' 
left the partition out rather
+      // than taking it from metadata storage. Installing them as they are 
would leave a mixed group
+      // reading the stale partition from its old position until the next 
rollover, and would make a group
+      // that consists only of reset partitions run no task at all. Rebuild 
the affected groups now that
+      // partitionOffsets has been reset, so that each of them starts from the 
reset position.
+      for (PartitionIdType partition : partitionsToReset.keySet()) {
+        final int groupId = getTaskGroupIdForPartition(partition);
+        final TaskGroup taskGroup = newTaskGroups.get(groupId);
+
+        if (taskGroup != null) {
+          newTaskGroups.put(groupId, buildNewTaskGroup(groupId, 
metadataOffsets, partitionsToReset));

Review Comment:
   [P2] Keep the automatic-reset regression test passing
   
   **Finding:** This new buildNewTaskGroup call performs another 
retrieveDataSourceMetadata call through 
generateStartingSequencesForPartitionGroup, even though resetInternal has 
emptied the affected partition group. 
KafkaSupervisorTest.testGetOffsetFromStorageForPartitionWithResetOffsetAutomatically
 still permits exactly four metadata reads: partition discovery, the initial 
offset snapshot, the initial group build, and resetInternal. Rebuilding here 
makes a fifth read, so EasyMock throws an unexpected-invocation AssertionError 
before the test reaches its reset alert assertion. This is a test regression 
introduced by this update, rather than unrelated master drift.
   
   **Suggestion:** Remove the ineffective rebuild before the unconditional 
StreamException, or update the reset test to cover the intended additional 
reads and verify successful recovery on the next supervisor cycle.



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