|
16 | 16 | */
|
17 | 17 | package org.apache.kafka.coordinator.group.streams;
|
18 | 18 |
|
| 19 | +import org.apache.kafka.common.message.StreamsGroupHeartbeatRequestData; |
19 | 20 | import org.apache.kafka.coordinator.group.generated.StreamsGroupTargetAssignmentMemberValue;
|
20 | 21 |
|
21 | 22 | import java.util.Collections;
|
22 | 23 | import java.util.HashMap;
|
23 | 24 | import java.util.HashSet;
|
| 25 | +import java.util.Iterator; |
| 26 | +import java.util.List; |
24 | 27 | import java.util.Map;
|
| 28 | +import java.util.Map.Entry; |
25 | 29 | import java.util.Objects;
|
26 | 30 | import java.util.Set;
|
27 | 31 | import java.util.stream.Collectors;
|
|
30 | 34 | * An immutable tuple containing active, standby and warm-up tasks.
|
31 | 35 | *
|
32 | 36 | * @param activeTasks Active tasks.
|
33 |
| - * The key of the map is the subtopology ID and the value is the set of partition IDs. |
| 37 | + * The key of the map is the subtopology ID, and the value is the set of partition IDs. |
34 | 38 | * @param standbyTasks Standby tasks.
|
35 |
| - * The key of the map is the subtopology ID and the value is the set of partition IDs. |
| 39 | + * The key of the map is the subtopology ID, and the value is the set of partition IDs. |
36 | 40 | * @param warmupTasks Warm-up tasks.
|
37 |
| - * The key of the map is the subtopology ID and the value is the set of partition IDs. |
| 41 | + * The key of the map is the subtopology ID, and the value is the set of partition IDs. |
38 | 42 | */
|
39 | 43 | public record TasksTuple(Map<String, Set<Integer>> activeTasks,
|
40 | 44 | Map<String, Set<Integer>> standbyTasks,
|
@@ -88,7 +92,7 @@ private static Map<String, Set<Integer>> merge(final Map<String, Set<Integer>> t
|
88 | 92 | /**
|
89 | 93 | * Checks if this task tuple contains any of the tasks in another task tuple.
|
90 | 94 | *
|
91 |
| - * @param other The other task tuple. |
| 95 | + * @param other Another task tuple. |
92 | 96 | * @return true if there is at least one active, standby or warm-up task that is present in both tuples.
|
93 | 97 | */
|
94 | 98 | public boolean containsAny(TasksTuple other) {
|
@@ -130,4 +134,63 @@ public static TasksTuple fromTargetAssignmentRecord(StreamsGroupTargetAssignment
|
130 | 134 | )
|
131 | 135 | );
|
132 | 136 | }
|
| 137 | + |
| 138 | + public String toString() { |
| 139 | + return "(active=" + taskAssignmentToString(activeTasks) + |
| 140 | + ", standby=" + taskAssignmentToString(standbyTasks) + |
| 141 | + ", warmup=" + taskAssignmentToString(warmupTasks) + |
| 142 | + ')'; |
| 143 | + } |
| 144 | + |
| 145 | + public static TasksTuple fromHeartbeatRequest(final List<StreamsGroupHeartbeatRequestData.TaskIds> ownedActiveTasks, |
| 146 | + final List<StreamsGroupHeartbeatRequestData.TaskIds> ownedStandbyTasks, |
| 147 | + final List<StreamsGroupHeartbeatRequestData.TaskIds> ownedWarmupTasks) { |
| 148 | + return new TasksTuple( |
| 149 | + ownedActiveTasks.stream() |
| 150 | + .collect(Collectors.toMap( |
| 151 | + StreamsGroupHeartbeatRequestData.TaskIds::subtopologyId, |
| 152 | + taskId -> new HashSet<>(taskId.partitions()) |
| 153 | + ) |
| 154 | + ), |
| 155 | + ownedStandbyTasks.stream() |
| 156 | + .collect(Collectors.toMap( |
| 157 | + StreamsGroupHeartbeatRequestData.TaskIds::subtopologyId, |
| 158 | + taskId -> new HashSet<>(taskId.partitions()) |
| 159 | + ) |
| 160 | + ), |
| 161 | + ownedWarmupTasks.stream() |
| 162 | + .collect(Collectors.toMap( |
| 163 | + StreamsGroupHeartbeatRequestData.TaskIds::subtopologyId, |
| 164 | + taskId -> new HashSet<>(taskId.partitions()) |
| 165 | + ) |
| 166 | + ) |
| 167 | + ); |
| 168 | + } |
| 169 | + |
| 170 | + /** |
| 171 | + * @return The provided assignment as a String. |
| 172 | + * |
| 173 | + * Example: |
| 174 | + * [subtopologyID1-0, subtopologyID1-1, subtopologyID2-0, subtopologyID2-1] |
| 175 | + */ |
| 176 | + private static String taskAssignmentToString( |
| 177 | + Map<String, Set<Integer>> assignment |
| 178 | + ) { |
| 179 | + StringBuilder builder = new StringBuilder("["); |
| 180 | + Iterator<Entry<String, Set<Integer>>> subtopologyIterator = assignment.entrySet().iterator(); |
| 181 | + while (subtopologyIterator.hasNext()) { |
| 182 | + Map.Entry<String, Set<Integer>> entry = subtopologyIterator.next(); |
| 183 | + Iterator<Integer> partitionsIterator = entry.getValue().iterator(); |
| 184 | + while (partitionsIterator.hasNext()) { |
| 185 | + builder.append(entry.getKey()); |
| 186 | + builder.append("-"); |
| 187 | + builder.append(partitionsIterator.next()); |
| 188 | + if (partitionsIterator.hasNext() || subtopologyIterator.hasNext()) { |
| 189 | + builder.append(", "); |
| 190 | + } |
| 191 | + } |
| 192 | + } |
| 193 | + builder.append("]"); |
| 194 | + return builder.toString(); |
| 195 | + } |
133 | 196 | }
|
0 commit comments