-
Notifications
You must be signed in to change notification settings - Fork 15k
MINOR: Various small cleanups in group-coordinator #21450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1289,8 +1289,8 @@ private void convertToClassicGroup( | |
| metadataImage | ||
| ); | ||
| } catch (SchemaException e) { | ||
| log.warn("Cannot downgrade the consumer group " + consumerGroup.groupId() + ": fail to parse " + | ||
| "the Consumer Protocol " + ConsumerProtocol.PROTOCOL_TYPE + ".", e); | ||
| log.warn("Cannot downgrade the consumer group {}: fail to parse the Consumer Protocol {}.", | ||
| consumerGroup.groupId(), ConsumerProtocol.PROTOCOL_TYPE, e); | ||
|
||
|
|
||
| throw new GroupIdNotFoundException(String.format("Cannot downgrade the classic group %s: %s.", | ||
| consumerGroup.groupId(), e.getMessage())); | ||
|
|
@@ -1370,16 +1370,14 @@ ConsumerGroup convertToConsumerGroup(ClassicGroup classicGroup, List<Coordinator | |
| metadataImage | ||
| ); | ||
| } catch (SchemaException e) { | ||
| log.warn("Cannot upgrade classic group " + classicGroup.groupId() + | ||
| " to consumer group because the embedded consumer protocol is malformed: " | ||
| + e.getMessage() + ".", e); | ||
| log.warn("Cannot upgrade classic group {} to consumer group because the embedded consumer protocol is malformed: {}.", | ||
| classicGroup.groupId(), e.getMessage(), e); | ||
|
||
|
|
||
| throw new GroupIdNotFoundException( | ||
| String.format("Cannot upgrade classic group %s to consumer group because the embedded consumer protocol is malformed.", classicGroup.groupId()) | ||
| ); | ||
| } catch (UnsupportedVersionException e) { | ||
| log.warn("Cannot upgrade classic group " + classicGroup.groupId() + | ||
| " to consumer group: " + e.getMessage() + ".", e); | ||
| log.warn("Cannot upgrade classic group {} to consumer group: {}.", classicGroup.groupId(), e.getMessage(), e); | ||
|
|
||
| throw new GroupIdNotFoundException( | ||
| String.format("Cannot upgrade classic group %s to consumer group because an unsupported custom assignor is in use. " + | ||
|
|
@@ -3530,7 +3528,7 @@ private boolean hasStreamsMemberMetadataChanged( | |
| String memberId = updatedMember.memberId(); | ||
| if (!updatedMember.equals(member)) { | ||
| records.add(newStreamsGroupMemberRecord(groupId, updatedMember)); | ||
| log.info("[GroupId {}][MemberId {}] Member updated its member metdata to {}.", | ||
| log.info("[GroupId {}][MemberId {}] Member updated its member metadata to {}.", | ||
| groupId, memberId, updatedMember); | ||
|
|
||
| return true; | ||
|
|
@@ -4027,7 +4025,7 @@ private CoordinatorResult<Void, CoordinatorRecord> computeDelayedTargetAssignmen | |
| throw new IllegalStateException("Group epoch should be always larger to assignment epoch"); | ||
| } | ||
|
|
||
| if (!group.configuredTopology().isPresent()) { | ||
| if (group.configuredTopology().isEmpty()) { | ||
| log.warn("[GroupId {}] Cannot compute delayed target assignment: configured topology is not present", groupId); | ||
| return EMPTY_RESULT; | ||
| } | ||
|
|
@@ -4350,9 +4348,8 @@ private <T> CoordinatorResult<T, CoordinatorRecord> streamsGroupFenceMember( | |
| StreamsGroupMember member, | ||
| T response | ||
| ) { | ||
| List<CoordinatorRecord> records = new ArrayList<>(); | ||
|
|
||
| records.addAll(removeStreamsMember(group.groupId(), member.memberId())); | ||
| List<CoordinatorRecord> records = new ArrayList<>(removeStreamsMember(group.groupId(), member.memberId())); | ||
|
|
||
| // We bump the group epoch. | ||
| int groupEpoch = group.groupEpoch() + 1; | ||
|
|
@@ -7287,30 +7284,26 @@ private CoordinatorResult<Void, CoordinatorRecord> expirePendingSync( | |
| * @return whether the group can accept a joining member. | ||
| */ | ||
| private boolean acceptJoiningMember(ClassicGroup group, String memberId) { | ||
| switch (group.currentState()) { | ||
| case EMPTY: | ||
| case DEAD: | ||
| return switch (group.currentState()) { | ||
| case EMPTY, DEAD -> | ||
| // Always accept the request when the group is empty or dead | ||
| return true; | ||
| case PREPARING_REBALANCE: | ||
| true; | ||
| case PREPARING_REBALANCE -> | ||
| // An existing member is accepted if it is already awaiting. New members are accepted | ||
| // up to the max group size. Note that the number of awaiting members is used here | ||
| // for two reasons: | ||
| // 1) the group size is not reliable as it could already be above the max group size | ||
| // if the max group size was reduced. | ||
| // 2) using the number of awaiting members allows to kick out the last rejoining | ||
| // members of the group. | ||
| return (group.hasMember(memberId) && group.member(memberId).isAwaitingJoin()) || | ||
| group.numAwaitingJoinResponse() < config.classicGroupMaxSize(); | ||
| case COMPLETING_REBALANCE: | ||
| case STABLE: | ||
| (group.hasMember(memberId) && group.member(memberId).isAwaitingJoin()) || | ||
| group.numAwaitingJoinResponse() < config.classicGroupMaxSize(); | ||
| case COMPLETING_REBALANCE, STABLE -> | ||
| // An existing member is accepted. New members are accepted up to the max group size. | ||
| // Note that the group size is used here. When the group transitions to CompletingRebalance, | ||
| // members who haven't rejoined are removed. | ||
| return group.hasMember(memberId) || group.numMembers() < config.classicGroupMaxSize(); | ||
| default: | ||
| throw new IllegalStateException("Unknown group state: " + group.stateAsString()); | ||
| } | ||
| group.hasMember(memberId) || group.numMembers() < config.classicGroupMaxSize(); | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -7645,24 +7638,12 @@ private byte[] prepareAssignment(ConsumerGroupMember member) { | |
|
|
||
| // Visible for testing | ||
| static Errors appendGroupMetadataErrorToResponseError(Errors appendError) { | ||
| switch (appendError) { | ||
| case UNKNOWN_TOPIC_OR_PARTITION: | ||
| case NOT_ENOUGH_REPLICAS: | ||
| case REQUEST_TIMED_OUT: | ||
| return COORDINATOR_NOT_AVAILABLE; | ||
|
|
||
| case NOT_LEADER_OR_FOLLOWER: | ||
| case KAFKA_STORAGE_ERROR: | ||
| return NOT_COORDINATOR; | ||
|
|
||
| case MESSAGE_TOO_LARGE: | ||
| case RECORD_LIST_TOO_LARGE: | ||
| case INVALID_FETCH_SIZE: | ||
| return UNKNOWN_SERVER_ERROR; | ||
|
|
||
| default: | ||
| return appendError; | ||
| } | ||
| return switch (appendError) { | ||
| case UNKNOWN_TOPIC_OR_PARTITION, NOT_ENOUGH_REPLICAS, REQUEST_TIMED_OUT -> COORDINATOR_NOT_AVAILABLE; | ||
| case NOT_LEADER_OR_FOLLOWER, KAFKA_STORAGE_ERROR -> NOT_COORDINATOR; | ||
| case MESSAGE_TOO_LARGE, RECORD_LIST_TOO_LARGE, INVALID_FETCH_SIZE -> UNKNOWN_SERVER_ERROR; | ||
| default -> appendError; | ||
| }; | ||
| } | ||
|
|
||
| private Optional<Errors> validateSyncGroup( | ||
|
|
@@ -7768,35 +7749,31 @@ private CoordinatorResult<HeartbeatResponseData, CoordinatorRecord> classicGroup | |
| ) { | ||
| validateClassicGroupHeartbeat(group, request.memberId(), request.groupInstanceId(), request.generationId()); | ||
|
|
||
| switch (group.currentState()) { | ||
| case EMPTY: | ||
| return new CoordinatorResult<>( | ||
| List.of(), | ||
| new HeartbeatResponseData().setErrorCode(Errors.UNKNOWN_MEMBER_ID.code()) | ||
| ); | ||
|
|
||
| case PREPARING_REBALANCE: | ||
| return switch (group.currentState()) { | ||
| case EMPTY -> new CoordinatorResult<>( | ||
| List.of(), | ||
| new HeartbeatResponseData().setErrorCode(Errors.UNKNOWN_MEMBER_ID.code()) | ||
| ); | ||
| case PREPARING_REBALANCE -> { | ||
| rescheduleClassicGroupMemberHeartbeat(group, group.member(request.memberId())); | ||
| return new CoordinatorResult<>( | ||
| yield new CoordinatorResult<>( | ||
| List.of(), | ||
| new HeartbeatResponseData().setErrorCode(Errors.REBALANCE_IN_PROGRESS.code()) | ||
| ); | ||
|
|
||
| case COMPLETING_REBALANCE: | ||
| case STABLE: | ||
| } | ||
| case COMPLETING_REBALANCE, STABLE -> { | ||
| // Consumers may start sending heartbeats after join-group response, while the group | ||
| // is in CompletingRebalance state. In this case, we should treat them as | ||
| // normal heartbeat requests and reset the timer | ||
| rescheduleClassicGroupMemberHeartbeat(group, group.member(request.memberId())); | ||
| return new CoordinatorResult<>( | ||
| yield new CoordinatorResult<>( | ||
| List.of(), | ||
| new HeartbeatResponseData() | ||
| ); | ||
|
|
||
| default: | ||
| throw new IllegalStateException("Reached unexpected state " + | ||
| } | ||
| default -> throw new IllegalStateException("Reached unexpected state " + | ||
| group.currentState() + " for group " + group.groupId()); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -8652,7 +8629,7 @@ private boolean maybeDeleteEmptyStreamsGroup(String groupId, List<CoordinatorRec | |
| * Checks whether the given protocol type or name in the request is inconsistent with the group's. | ||
| * | ||
| * @param protocolTypeOrName The request's protocol type or name. | ||
| * @param groupProtocolTypeOrName The group's protoocl type or name. | ||
| * @param groupProtocolTypeOrName The group's protocol type or name. | ||
| * | ||
| * @return True if protocol is inconsistent, false otherwise. | ||
| */ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider refactoring the call path to use
Mapinstead. I didn't see the specific benefit of usingPropertieshereThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can address that in a follow-up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to do that change let's do it in a separate PR. The caller path comes all the way from
ControllerConfigurationValidatorwhich usesPropertiesfor all resource types.