115
115
import org .apache .kafka .coordinator .group .generated .ShareGroupMemberMetadataValue ;
116
116
import org .apache .kafka .coordinator .group .generated .ShareGroupMetadataKey ;
117
117
import org .apache .kafka .coordinator .group .generated .ShareGroupMetadataValue ;
118
- import org .apache .kafka .coordinator .group .generated .ShareGroupPartitionMetadataKey ;
119
- import org .apache .kafka .coordinator .group .generated .ShareGroupPartitionMetadataValue ;
120
118
import org .apache .kafka .coordinator .group .generated .ShareGroupStatePartitionMetadataKey ;
121
119
import org .apache .kafka .coordinator .group .generated .ShareGroupStatePartitionMetadataValue ;
122
120
import org .apache .kafka .coordinator .group .generated .ShareGroupTargetAssignmentMemberKey ;
141
139
import org .apache .kafka .coordinator .group .modern .ModernGroup ;
142
140
import org .apache .kafka .coordinator .group .modern .SubscriptionCount ;
143
141
import org .apache .kafka .coordinator .group .modern .TargetAssignmentBuilder ;
144
- import org .apache .kafka .coordinator .group .modern .TopicMetadata ;
145
142
import org .apache .kafka .coordinator .group .modern .consumer .ConsumerGroup ;
146
143
import org .apache .kafka .coordinator .group .modern .consumer .ConsumerGroupMember ;
147
144
import org .apache .kafka .coordinator .group .modern .consumer .CurrentAssignmentBuilder ;
235
232
import static org .apache .kafka .coordinator .group .GroupCoordinatorRecordHelpers .newShareGroupMemberSubscriptionRecord ;
236
233
import static org .apache .kafka .coordinator .group .GroupCoordinatorRecordHelpers .newShareGroupMemberSubscriptionTombstoneRecord ;
237
234
import static org .apache .kafka .coordinator .group .GroupCoordinatorRecordHelpers .newShareGroupStatePartitionMetadataRecord ;
238
- import static org .apache .kafka .coordinator .group .GroupCoordinatorRecordHelpers .newShareGroupSubscriptionMetadataRecord ;
239
235
import static org .apache .kafka .coordinator .group .GroupCoordinatorRecordHelpers .newShareGroupTargetAssignmentTombstoneRecord ;
240
236
import static org .apache .kafka .coordinator .group .Utils .assignmentToString ;
241
237
import static org .apache .kafka .coordinator .group .Utils .ofSentinel ;
@@ -2541,18 +2537,18 @@ private CoordinatorResult<Map.Entry<ShareGroupHeartbeatResponseData, Optional<In
2541
2537
) || initializedAssignmentPending (group );
2542
2538
2543
2539
int groupEpoch = group .groupEpoch ();
2544
- Map <String , TopicMetadata > subscriptionMetadata = group .subscriptionMetadata ();
2540
+ Map <String , SubscriptionCount > subscribedTopicNamesMap = group .subscribedTopicNames ();
2545
2541
SubscriptionType subscriptionType = group .subscriptionType ();
2546
2542
2547
2543
if (bumpGroupEpoch || group .hasMetadataExpired (currentTimeMs )) {
2548
2544
// The subscription metadata is updated in two cases:
2549
2545
// 1) The member has updated its subscriptions;
2550
2546
// 2) The refresh deadline has been reached.
2551
- Map < String , SubscriptionCount > subscribedTopicNamesMap = group .computeSubscribedTopicNames (member , updatedMember );
2552
- subscriptionMetadata = group . computeSubscriptionMetadata (
2547
+ subscribedTopicNamesMap = group .computeSubscribedTopicNames (member , updatedMember );
2548
+ long groupMetadataHash = ModernGroup . computeMetadataHash (
2553
2549
subscribedTopicNamesMap ,
2554
- metadataImage . topics () ,
2555
- metadataImage . cluster ()
2550
+ topicHashCache ,
2551
+ metadataImage
2556
2552
);
2557
2553
2558
2554
int numMembers = group .numMembers ();
@@ -2565,17 +2561,16 @@ private CoordinatorResult<Map.Entry<ShareGroupHeartbeatResponseData, Optional<In
2565
2561
numMembers
2566
2562
);
2567
2563
2568
- if (! subscriptionMetadata . equals ( group .subscriptionMetadata () )) {
2569
- log .info ("[GroupId {}] Computed new subscription metadata: {}." ,
2570
- groupId , subscriptionMetadata );
2564
+ if (groupMetadataHash != group .metadataHash ( )) {
2565
+ log .info ("[GroupId {}] Computed new metadata hash : {}." ,
2566
+ groupId , groupMetadataHash );
2571
2567
bumpGroupEpoch = true ;
2572
- records .add (newShareGroupSubscriptionMetadataRecord (groupId , subscriptionMetadata ));
2573
2568
}
2574
2569
2575
2570
if (bumpGroupEpoch ) {
2576
2571
groupEpoch += 1 ;
2577
- records .add (newShareGroupEpochRecord (groupId , groupEpoch , 0 ));
2578
- log .info ("[GroupId {}] Bumped group epoch to {}." , groupId , groupEpoch );
2572
+ records .add (newShareGroupEpochRecord (groupId , groupEpoch , groupMetadataHash ));
2573
+ log .info ("[GroupId {}] Bumped group epoch to {} with metadata hash {} ." , groupId , groupEpoch , groupMetadataHash );
2579
2574
}
2580
2575
2581
2576
group .setMetadataRefreshDeadline (currentTimeMs + METADATA_REFRESH_INTERVAL_MS , groupEpoch );
@@ -2631,7 +2626,7 @@ private CoordinatorResult<Map.Entry<ShareGroupHeartbeatResponseData, Optional<In
2631
2626
records ,
2632
2627
Map .entry (
2633
2628
response ,
2634
- maybeCreateInitializeShareGroupStateRequest (groupId , groupEpoch , subscriptionMetadata , records )
2629
+ maybeCreateInitializeShareGroupStateRequest (groupId , groupEpoch , subscribedTopicNamesMap . keySet () , records )
2635
2630
)
2636
2631
);
2637
2632
}
@@ -2664,13 +2659,13 @@ private boolean initializedAssignmentPending(ShareGroup group) {
2664
2659
* Computes the diff between the subscribed metadata and the initialized share topic
2665
2660
* partitions corresponding to a share group.
2666
2661
*
2667
- * @param groupId The share group id for which diff is being calculated
2668
- * @param subscriptionMetadata The subscription metadata corresponding to the share group.
2662
+ * @param groupId The share group id for which diff is being calculated
2663
+ * @param subscriptionTopicNames The subscription topic names to the share group.
2669
2664
* @return A map of topic partitions which are subscribed by the share group but not initialized yet.
2670
2665
*/
2671
2666
// Visibility for testing
2672
- Map <Uuid , InitMapValue > subscribedTopicsChangeMap (String groupId , Map <String , TopicMetadata > subscriptionMetadata ) {
2673
- if (subscriptionMetadata == null || subscriptionMetadata .isEmpty ()) {
2667
+ Map <Uuid , InitMapValue > subscribedTopicsChangeMap (String groupId , Set <String > subscriptionTopicNames ) {
2668
+ if (subscriptionTopicNames == null || subscriptionTopicNames .isEmpty ()) {
2674
2669
return Map .of ();
2675
2670
}
2676
2671
@@ -2689,18 +2684,20 @@ Map<Uuid, InitMapValue> subscribedTopicsChangeMap(String groupId, Map<String, To
2689
2684
.filter (entry -> curTimestamp - entry .getValue ().timestamp () < delta )
2690
2685
.collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue ))
2691
2686
);
2692
-
2693
2687
// Here will add any topics which are subscribed but not initialized and initializing
2694
2688
// topics whose timestamp indicates that they are older than delta elapsed.
2695
- subscriptionMetadata .forEach ((topicName , topicMetadata ) -> {
2696
- Set <Integer > alreadyInitializedPartSet = alreadyInitialized .containsKey (topicMetadata .id ()) ? alreadyInitialized .get (topicMetadata .id ()).partitions () : Set .of ();
2697
- if (alreadyInitializedPartSet .isEmpty () || alreadyInitializedPartSet .size () < topicMetadata .numPartitions ()) {
2698
- Set <Integer > partitionSet = IntStream .range (0 , topicMetadata .numPartitions ()).boxed ().collect (Collectors .toSet ());
2699
- partitionSet .removeAll (alreadyInitializedPartSet );
2700
- // alreadyInitialized contains all initialized topics and initializing topics which are less than delta old
2701
- // which means we are putting subscribed topics which are unseen or initializing for more than delta. But, we
2702
- // are also updating the timestamp here which means, old initializing will not be included repeatedly.
2703
- topicPartitionChangeMap .computeIfAbsent (topicMetadata .id (), k -> new InitMapValue (topicMetadata .name (), partitionSet , curTimestamp ));
2689
+ subscriptionTopicNames .forEach (topicName -> {
2690
+ TopicImage topicImage = metadataImage .topics ().getTopic (topicName );
2691
+ if (topicImage != null ) {
2692
+ Set <Integer > alreadyInitializedPartSet = alreadyInitialized .containsKey (topicImage .id ()) ? alreadyInitialized .get (topicImage .id ()).partitions () : Set .of ();
2693
+ if (alreadyInitializedPartSet .isEmpty () || alreadyInitializedPartSet .size () < topicImage .partitions ().size ()) {
2694
+ Set <Integer > partitionSet = IntStream .range (0 , topicImage .partitions ().size ()).boxed ()
2695
+ .filter (p -> !alreadyInitializedPartSet .contains (p )).collect (Collectors .toSet ());
2696
+ // alreadyInitialized contains all initialized topics and initializing topics which are less than delta old
2697
+ // which means we are putting subscribed topics which are unseen or initializing for more than delta. But, we
2698
+ // are also updating the timestamp here which means, old initializing will not be included repeatedly.
2699
+ topicPartitionChangeMap .computeIfAbsent (topicImage .id (), k -> new InitMapValue (topicImage .name (), partitionSet , curTimestamp ));
2700
+ }
2704
2701
}
2705
2702
});
2706
2703
return topicPartitionChangeMap ;
@@ -2710,22 +2707,22 @@ Map<Uuid, InitMapValue> subscribedTopicsChangeMap(String groupId, Map<String, To
2710
2707
* Based on the diff between the subscribed topic partitions and the initialized topic partitions,
2711
2708
* created initialize request for the non-initialized ones.
2712
2709
*
2713
- * @param groupId The share group id for which partitions need to be initialized.
2714
- * @param groupEpoch The group epoch of the share group.
2715
- * @param subscriptionMetadata The subscription metadata for the share group.
2710
+ * @param groupId The share group id for which partitions need to be initialized.
2711
+ * @param groupEpoch The group epoch of the share group.
2712
+ * @param subscriptionTopicNames The subscription topic names for the share group.
2716
2713
* @return An optional representing the persister initialize request.
2717
2714
*/
2718
2715
private Optional <InitializeShareGroupStateParameters > maybeCreateInitializeShareGroupStateRequest (
2719
2716
String groupId ,
2720
2717
int groupEpoch ,
2721
- Map <String , TopicMetadata > subscriptionMetadata ,
2718
+ Set <String > subscriptionTopicNames ,
2722
2719
List <CoordinatorRecord > records
2723
2720
) {
2724
- if (subscriptionMetadata == null || subscriptionMetadata .isEmpty () || metadataImage .isEmpty ()) {
2721
+ if (subscriptionTopicNames == null || subscriptionTopicNames .isEmpty () || metadataImage .isEmpty ()) {
2725
2722
return Optional .empty ();
2726
2723
}
2727
2724
2728
- Map <Uuid , InitMapValue > topicPartitionChangeMap = subscribedTopicsChangeMap (groupId , subscriptionMetadata );
2725
+ Map <Uuid , InitMapValue > topicPartitionChangeMap = subscribedTopicsChangeMap (groupId , subscriptionTopicNames );
2729
2726
2730
2727
// Nothing to initialize.
2731
2728
if (topicPartitionChangeMap .isEmpty ()) {
@@ -4078,21 +4075,20 @@ private <T> CoordinatorResult<T, CoordinatorRecord> shareGroupFenceMember(
4078
4075
records .add (newShareGroupMemberSubscriptionTombstoneRecord (group .groupId (), member .memberId ()));
4079
4076
4080
4077
// We update the subscription metadata without the leaving member.
4081
- Map < String , TopicMetadata > subscriptionMetadata = group . computeSubscriptionMetadata (
4078
+ long groupMetadataHash = ModernGroup . computeMetadataHash (
4082
4079
group .computeSubscribedTopicNames (member , null ),
4083
- metadataImage . topics () ,
4084
- metadataImage . cluster ()
4080
+ topicHashCache ,
4081
+ metadataImage
4085
4082
);
4086
4083
4087
- if (!subscriptionMetadata .equals (group .subscriptionMetadata ())) {
4088
- log .info ("[GroupId {}] Computed new subscription metadata: {}." ,
4089
- group .groupId (), subscriptionMetadata );
4090
- records .add (newShareGroupSubscriptionMetadataRecord (group .groupId (), subscriptionMetadata ));
4084
+ if (groupMetadataHash != group .metadataHash ()) {
4085
+ log .info ("[GroupId {}] Computed new metadata hash: {}." ,
4086
+ group .groupId (), groupMetadataHash );
4091
4087
}
4092
4088
4093
4089
// We bump the group epoch.
4094
4090
int groupEpoch = group .groupEpoch () + 1 ;
4095
- records .add (newShareGroupEpochRecord (group .groupId (), groupEpoch , 0 ));
4091
+ records .add (newShareGroupEpochRecord (group .groupId (), groupEpoch , groupMetadataHash ));
4096
4092
4097
4093
cancelGroupSessionTimeout (group .groupId (), member .memberId ());
4098
4094
@@ -5357,6 +5353,7 @@ public void replay(
5357
5353
if (value != null ) {
5358
5354
ShareGroup shareGroup = getOrMaybeCreatePersistedShareGroup (groupId , true );
5359
5355
shareGroup .setGroupEpoch (value .epoch ());
5356
+ shareGroup .setMetadataHash (value .metadataHash ());
5360
5357
} else {
5361
5358
ShareGroup shareGroup = getOrMaybeCreatePersistedShareGroup (groupId , false );
5362
5359
if (!shareGroup .members ().isEmpty ()) {
@@ -5537,32 +5534,6 @@ public void replay(
5537
5534
}
5538
5535
}
5539
5536
5540
- /**
5541
- * Replays ShareGroupPartitionMetadataKey/Value to update the hard state of
5542
- * the share group. It updates the subscription metadata of the share
5543
- * group.
5544
- *
5545
- * @param key A ShareGroupPartitionMetadataKey key.
5546
- * @param value A ShareGroupPartitionMetadataValue record.
5547
- */
5548
- public void replay (
5549
- ShareGroupPartitionMetadataKey key ,
5550
- ShareGroupPartitionMetadataValue value
5551
- ) {
5552
- String groupId = key .groupId ();
5553
- ShareGroup group = getOrMaybeCreatePersistedShareGroup (groupId , false );
5554
-
5555
- if (value != null ) {
5556
- Map <String , TopicMetadata > subscriptionMetadata = new HashMap <>();
5557
- value .topics ().forEach (topicMetadata ->
5558
- subscriptionMetadata .put (topicMetadata .topicName (), TopicMetadata .fromRecord (topicMetadata ))
5559
- );
5560
- group .setSubscriptionMetadata (subscriptionMetadata );
5561
- } else {
5562
- group .setSubscriptionMetadata (Map .of ());
5563
- }
5564
- }
5565
-
5566
5537
/**
5567
5538
* Replays ShareGroupTargetAssignmentMemberKey/Value to update the hard state of
5568
5539
* the share group. It updates the target assignment of the member or deletes it.
0 commit comments