mirror of https://github.com/apache/kafka.git
KAFKA-19441: encapsulate MetadataImage in GroupCoordinator/ShareCoordinator (#20061)
CI / build (push) Waiting to run
Details
CI / build (push) Waiting to run
Details
The MetadataImage has a lot of stuff in it and it gets passed around in many places in the new GroupCoordinator. This makes it difficult to understand what metadata the group coordinator actually relies on and makes it too easy to use metadata in ways it wasn't meant to be used. This change encapsulate the MetadataImage in an interface (`CoordinatorMetadataImage`) that indicates and controls what metadata the group coordinator actually uses. Now it is much easier at a glance to see what dependencies the GroupCoordinator has on the metadata. Also, now we have a level of indirection that allows more flexibility in how the GroupCoordinator is provided the metadata it needs.
This commit is contained in:
parent
f33c5e9d72
commit
f81853ca88
|
@ -57,6 +57,7 @@
|
||||||
<allow pkg="org.apache.kafka.coordinator.common" />
|
<allow pkg="org.apache.kafka.coordinator.common" />
|
||||||
<allow pkg="org.apache.kafka.deferred" />
|
<allow pkg="org.apache.kafka.deferred" />
|
||||||
<allow pkg="org.apache.kafka.image" />
|
<allow pkg="org.apache.kafka.image" />
|
||||||
|
<allow pkg="org.apache.kafka.metadata" />
|
||||||
<allow pkg="org.apache.kafka.server.authorizer" />
|
<allow pkg="org.apache.kafka.server.authorizer" />
|
||||||
<allow pkg="org.apache.kafka.server.common" />
|
<allow pkg="org.apache.kafka.server.common" />
|
||||||
<allow pkg="org.apache.kafka.server.metrics" />
|
<allow pkg="org.apache.kafka.server.metrics" />
|
||||||
|
|
|
@ -52,6 +52,8 @@
|
||||||
<allow pkg="org.apache.kafka.server"/>
|
<allow pkg="org.apache.kafka.server"/>
|
||||||
<allow pkg="org.apache.kafka.storage"/>
|
<allow pkg="org.apache.kafka.storage"/>
|
||||||
<allow pkg="org.apache.kafka.clients"/>
|
<allow pkg="org.apache.kafka.clients"/>
|
||||||
|
<allow class="org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage"/>
|
||||||
|
<allow class="org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage"/>
|
||||||
<allow class="org.apache.kafka.coordinator.common.runtime.HdrHistogram"/>
|
<allow class="org.apache.kafka.coordinator.common.runtime.HdrHistogram"/>
|
||||||
<allow pkg="org.apache.kafka.coordinator.group"/>
|
<allow pkg="org.apache.kafka.coordinator.group"/>
|
||||||
<allow pkg="org.apache.kafka.image"/>
|
<allow pkg="org.apache.kafka.image"/>
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.kafka.coordinator.common.runtime;
|
||||||
|
|
||||||
|
import org.apache.kafka.common.Uuid;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides metadata deltas to Coordinators (GroupCoordinator, ShareCoordinator, etc) such as changed topics and deleted topics
|
||||||
|
* Implementations should be immutable.
|
||||||
|
*/
|
||||||
|
public interface CoordinatorMetadataDelta {
|
||||||
|
|
||||||
|
CoordinatorMetadataDelta EMPTY = emptyDelta();
|
||||||
|
|
||||||
|
Collection<Uuid> createdTopicIds();
|
||||||
|
|
||||||
|
Collection<Uuid> changedTopicIds();
|
||||||
|
|
||||||
|
Set<Uuid> deletedTopicIds();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the previous image of the coordinator metadata.
|
||||||
|
* This image is a snapshot of the metadata before the delta occurred.
|
||||||
|
*/
|
||||||
|
CoordinatorMetadataImage image();
|
||||||
|
|
||||||
|
private static CoordinatorMetadataDelta emptyDelta() {
|
||||||
|
return new CoordinatorMetadataDelta() {
|
||||||
|
@Override
|
||||||
|
public Collection<Uuid> createdTopicIds() {
|
||||||
|
return Set.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Uuid> changedTopicIds() {
|
||||||
|
return Set.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Uuid> deletedTopicIds() {
|
||||||
|
return Set.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CoordinatorMetadataImage image() {
|
||||||
|
return CoordinatorMetadataImage.EMPTY;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.kafka.coordinator.common.runtime;
|
||||||
|
|
||||||
|
import org.apache.kafka.common.Uuid;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides metadata to Coordinators (GroupCoordinator, ShareCoordinator, etc) such as topics, partitions, and their configurations.
|
||||||
|
* Implementations should be thread-safe and immutable.
|
||||||
|
*/
|
||||||
|
public interface CoordinatorMetadataImage {
|
||||||
|
CoordinatorMetadataImage EMPTY = emptyImage();
|
||||||
|
|
||||||
|
Set<Uuid> topicIds();
|
||||||
|
|
||||||
|
Set<String> topicNames();
|
||||||
|
|
||||||
|
Optional<TopicMetadata> topicMetadata(String topicName);
|
||||||
|
|
||||||
|
Optional<TopicMetadata> topicMetadata(Uuid topicId);
|
||||||
|
|
||||||
|
CoordinatorMetadataDelta emptyDelta();
|
||||||
|
|
||||||
|
long version();
|
||||||
|
|
||||||
|
boolean isEmpty();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Metadata about a particular topic
|
||||||
|
*/
|
||||||
|
interface TopicMetadata {
|
||||||
|
String name();
|
||||||
|
|
||||||
|
Uuid id();
|
||||||
|
|
||||||
|
int partitionCount();
|
||||||
|
|
||||||
|
List<String> partitionRacks(int partitionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CoordinatorMetadataImage emptyImage() {
|
||||||
|
|
||||||
|
return new CoordinatorMetadataImage() {
|
||||||
|
@Override
|
||||||
|
public Set<Uuid> topicIds() {
|
||||||
|
return Set.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> topicNames() {
|
||||||
|
return Set.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<TopicMetadata> topicMetadata(String topicName) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<TopicMetadata> topicMetadata(Uuid topicId) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CoordinatorMetadataDelta emptyDelta() {
|
||||||
|
return CoordinatorMetadataDelta.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long version() {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -39,8 +39,6 @@ import org.apache.kafka.common.utils.Time;
|
||||||
import org.apache.kafka.common.utils.Utils;
|
import org.apache.kafka.common.utils.Utils;
|
||||||
import org.apache.kafka.deferred.DeferredEvent;
|
import org.apache.kafka.deferred.DeferredEvent;
|
||||||
import org.apache.kafka.deferred.DeferredEventQueue;
|
import org.apache.kafka.deferred.DeferredEventQueue;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.server.util.timer.Timer;
|
import org.apache.kafka.server.util.timer.Timer;
|
||||||
import org.apache.kafka.server.util.timer.TimerTask;
|
import org.apache.kafka.server.util.timer.TimerTask;
|
||||||
import org.apache.kafka.storage.internals.log.LogConfig;
|
import org.apache.kafka.storage.internals.log.LogConfig;
|
||||||
|
@ -2016,7 +2014,7 @@ public class CoordinatorRuntime<S extends CoordinatorShard<U>, U> implements Aut
|
||||||
/**
|
/**
|
||||||
* The latest known metadata image.
|
* The latest known metadata image.
|
||||||
*/
|
*/
|
||||||
private volatile MetadataImage metadataImage = MetadataImage.EMPTY;
|
private volatile CoordinatorMetadataImage metadataImage = CoordinatorMetadataImage.EMPTY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -2481,18 +2479,18 @@ public class CoordinatorRuntime<S extends CoordinatorShard<U>, U> implements Aut
|
||||||
* @param delta The metadata delta.
|
* @param delta The metadata delta.
|
||||||
*/
|
*/
|
||||||
public void onNewMetadataImage(
|
public void onNewMetadataImage(
|
||||||
MetadataImage newImage,
|
CoordinatorMetadataImage newImage,
|
||||||
MetadataDelta delta
|
CoordinatorMetadataDelta delta
|
||||||
) {
|
) {
|
||||||
throwIfNotRunning();
|
throwIfNotRunning();
|
||||||
log.debug("Scheduling applying of a new metadata image with offset {}.", newImage.offset());
|
log.debug("Scheduling applying of a new metadata image with version {}.", newImage.version());
|
||||||
|
|
||||||
// Update global image.
|
// Update global image.
|
||||||
metadataImage = newImage;
|
metadataImage = newImage;
|
||||||
|
|
||||||
// Push an event for each coordinator.
|
// Push an event for each coordinator.
|
||||||
coordinators.keySet().forEach(tp -> {
|
coordinators.keySet().forEach(tp -> {
|
||||||
scheduleInternalOperation("UpdateImage(tp=" + tp + ", offset=" + newImage.offset() + ")", tp, () -> {
|
scheduleInternalOperation("UpdateImage(tp=" + tp + ", version=" + newImage.version() + ")", tp, () -> {
|
||||||
CoordinatorContext context = coordinators.get(tp);
|
CoordinatorContext context = coordinators.get(tp);
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
context.lock.lock();
|
context.lock.lock();
|
||||||
|
@ -2500,18 +2498,18 @@ public class CoordinatorRuntime<S extends CoordinatorShard<U>, U> implements Aut
|
||||||
if (context.state == CoordinatorState.ACTIVE) {
|
if (context.state == CoordinatorState.ACTIVE) {
|
||||||
// The new image can be applied to the coordinator only if the coordinator
|
// The new image can be applied to the coordinator only if the coordinator
|
||||||
// exists and is in the active state.
|
// exists and is in the active state.
|
||||||
log.debug("Applying new metadata image with offset {} to {}.", newImage.offset(), tp);
|
log.debug("Applying new metadata image with version {} to {}.", newImage.version(), tp);
|
||||||
context.coordinator.onNewMetadataImage(newImage, delta);
|
context.coordinator.onNewMetadataImage(newImage, delta);
|
||||||
} else {
|
} else {
|
||||||
log.debug("Ignored new metadata image with offset {} for {} because the coordinator is not active.",
|
log.debug("Ignored new metadata image with version {} for {} because the coordinator is not active.",
|
||||||
newImage.offset(), tp);
|
newImage.version(), tp);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
context.lock.unlock();
|
context.lock.unlock();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug("Ignored new metadata image with offset {} for {} because the coordinator does not exist.",
|
log.debug("Ignored new metadata image with version {} for {} because the coordinator does not exist.",
|
||||||
newImage.offset(), tp);
|
newImage.version(), tp);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
package org.apache.kafka.coordinator.common.runtime;
|
package org.apache.kafka.coordinator.common.runtime;
|
||||||
|
|
||||||
import org.apache.kafka.common.requests.TransactionResult;
|
import org.apache.kafka.common.requests.TransactionResult;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CoordinatorShard is basically a replicated state machine managed by the
|
* CoordinatorShard is basically a replicated state machine managed by the
|
||||||
|
@ -32,16 +30,16 @@ public interface CoordinatorShard<U> {
|
||||||
*
|
*
|
||||||
* @param newImage The metadata image.
|
* @param newImage The metadata image.
|
||||||
*/
|
*/
|
||||||
default void onLoaded(MetadataImage newImage) {}
|
default void onLoaded(CoordinatorMetadataImage newImage) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A new metadata image is available. This is only called after {@link CoordinatorShard#onLoaded(MetadataImage)}
|
* A new metadata image is available. This is only called after {@link CoordinatorShard#onLoaded(CoordinatorMetadataImage)}
|
||||||
* is called to signal that the coordinator has been fully loaded.
|
* is called to signal that the coordinator has been fully loaded.
|
||||||
*
|
*
|
||||||
* @param newImage The new metadata image.
|
* @param newImage The new metadata image.
|
||||||
* @param delta The delta image.
|
* @param delta The delta image.
|
||||||
*/
|
*/
|
||||||
default void onNewMetadataImage(MetadataImage newImage, MetadataDelta delta) {}
|
default void onNewMetadataImage(CoordinatorMetadataImage newImage, CoordinatorMetadataDelta delta) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The coordinator has been unloaded. This is used to apply
|
* The coordinator has been unloaded. This is used to apply
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.kafka.coordinator.common.runtime;
|
||||||
|
|
||||||
|
import org.apache.kafka.common.Uuid;
|
||||||
|
import org.apache.kafka.image.MetadataDelta;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of {@link CoordinatorMetadataDelta} that wraps the KRaft MetadataDelta.
|
||||||
|
*/
|
||||||
|
public class KRaftCoordinatorMetadataDelta implements CoordinatorMetadataDelta {
|
||||||
|
|
||||||
|
final MetadataDelta metadataDelta;
|
||||||
|
|
||||||
|
public KRaftCoordinatorMetadataDelta(MetadataDelta metadataDelta) {
|
||||||
|
this.metadataDelta = metadataDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Uuid> createdTopicIds() {
|
||||||
|
if (metadataDelta == null || metadataDelta.topicsDelta() == null) {
|
||||||
|
return Set.of();
|
||||||
|
}
|
||||||
|
return metadataDelta.topicsDelta().createdTopicIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Uuid> changedTopicIds() {
|
||||||
|
if (metadataDelta == null || metadataDelta.topicsDelta() == null) {
|
||||||
|
return Set.of();
|
||||||
|
}
|
||||||
|
return metadataDelta.topicsDelta().changedTopics().keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Uuid> deletedTopicIds() {
|
||||||
|
if (metadataDelta == null || metadataDelta.topicsDelta() == null) {
|
||||||
|
return Set.of();
|
||||||
|
}
|
||||||
|
return metadataDelta.topicsDelta().deletedTopicIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CoordinatorMetadataImage image() {
|
||||||
|
return new KRaftCoordinatorMetadataImage(metadataDelta.image());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return metadataDelta.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o == null || !o.getClass().equals(this.getClass())) return false;
|
||||||
|
KRaftCoordinatorMetadataDelta other = (KRaftCoordinatorMetadataDelta) o;
|
||||||
|
return metadataDelta.equals(other.metadataDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return metadataDelta.hashCode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.kafka.coordinator.common.runtime;
|
||||||
|
|
||||||
|
import org.apache.kafka.common.Uuid;
|
||||||
|
import org.apache.kafka.image.ClusterImage;
|
||||||
|
import org.apache.kafka.image.MetadataDelta;
|
||||||
|
import org.apache.kafka.image.MetadataImage;
|
||||||
|
import org.apache.kafka.image.TopicImage;
|
||||||
|
import org.apache.kafka.metadata.BrokerRegistration;
|
||||||
|
import org.apache.kafka.metadata.PartitionRegistration;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of {@link CoordinatorMetadataImage} that wraps the KRaft MetadataImage.
|
||||||
|
*/
|
||||||
|
public class KRaftCoordinatorMetadataImage implements CoordinatorMetadataImage {
|
||||||
|
|
||||||
|
private final MetadataImage metadataImage;
|
||||||
|
|
||||||
|
public KRaftCoordinatorMetadataImage(MetadataImage metadataImage) {
|
||||||
|
this.metadataImage = metadataImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Uuid> topicIds() {
|
||||||
|
return Collections.unmodifiableSet(metadataImage.topics().topicsById().keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> topicNames() {
|
||||||
|
return Collections.unmodifiableSet(metadataImage.topics().topicsByName().keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<TopicMetadata> topicMetadata(Uuid topicId) {
|
||||||
|
TopicImage topicImage = metadataImage.topics().getTopic(topicId);
|
||||||
|
if (topicImage == null) return Optional.empty();
|
||||||
|
|
||||||
|
ClusterImage clusterImage = metadataImage.cluster();
|
||||||
|
if (clusterImage == null) return Optional.empty();
|
||||||
|
|
||||||
|
return Optional.of(new KraftTopicMetadata(topicImage, clusterImage));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<TopicMetadata> topicMetadata(String topicName) {
|
||||||
|
TopicImage topicImage = metadataImage.topics().getTopic(topicName);
|
||||||
|
if (topicImage == null) return Optional.empty();
|
||||||
|
|
||||||
|
ClusterImage clusterImage = metadataImage.cluster();
|
||||||
|
if (clusterImage == null) return Optional.empty();
|
||||||
|
|
||||||
|
return Optional.of(new KraftTopicMetadata(topicImage, clusterImage));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CoordinatorMetadataDelta emptyDelta() {
|
||||||
|
return new KRaftCoordinatorMetadataDelta(new MetadataDelta(metadataImage));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long version() {
|
||||||
|
return metadataImage.offset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return metadataImage.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return metadataImage.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o == null || !o.getClass().equals(this.getClass())) return false;
|
||||||
|
KRaftCoordinatorMetadataImage other = (KRaftCoordinatorMetadataImage) o;
|
||||||
|
return metadataImage.equals(other.metadataImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return metadataImage.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class KraftTopicMetadata implements TopicMetadata {
|
||||||
|
private final TopicImage topicImage;
|
||||||
|
private final ClusterImage clusterImage;
|
||||||
|
|
||||||
|
public KraftTopicMetadata(TopicImage topicImage, ClusterImage clusterImage) {
|
||||||
|
this.topicImage = topicImage;
|
||||||
|
this.clusterImage = clusterImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return topicImage.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uuid id() {
|
||||||
|
return topicImage.id();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int partitionCount() {
|
||||||
|
return topicImage.partitions().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> partitionRacks(int partition) {
|
||||||
|
List<String> racks = new ArrayList<>();
|
||||||
|
PartitionRegistration partitionRegistration = topicImage.partitions().get(partition);
|
||||||
|
if (partitionRegistration != null) {
|
||||||
|
for (int replicaId : partitionRegistration.replicas) {
|
||||||
|
BrokerRegistration broker = clusterImage.broker(replicaId);
|
||||||
|
if (broker != null) {
|
||||||
|
broker.rack().ifPresent(racks::add);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return racks;
|
||||||
|
} else {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,6 @@ package org.apache.kafka.coordinator.common.runtime;
|
||||||
import org.apache.kafka.common.TopicPartition;
|
import org.apache.kafka.common.TopicPartition;
|
||||||
import org.apache.kafka.common.requests.TransactionResult;
|
import org.apache.kafka.common.requests.TransactionResult;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
|
||||||
import org.apache.kafka.image.MetadataImage;
|
import org.apache.kafka.image.MetadataImage;
|
||||||
import org.apache.kafka.timeline.SnapshotRegistry;
|
import org.apache.kafka.timeline.SnapshotRegistry;
|
||||||
|
|
||||||
|
@ -179,7 +178,7 @@ public class SnapshottableCoordinator<S extends CoordinatorShard<U>, U> implemen
|
||||||
*
|
*
|
||||||
* @param newImage The metadata image.
|
* @param newImage The metadata image.
|
||||||
*/
|
*/
|
||||||
synchronized void onLoaded(MetadataImage newImage) {
|
synchronized void onLoaded(CoordinatorMetadataImage newImage) {
|
||||||
this.coordinator.onLoaded(newImage);
|
this.coordinator.onLoaded(newImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +206,7 @@ public class SnapshottableCoordinator<S extends CoordinatorShard<U>, U> implemen
|
||||||
* @param newImage The new metadata image.
|
* @param newImage The new metadata image.
|
||||||
* @param delta The delta image.
|
* @param delta The delta image.
|
||||||
*/
|
*/
|
||||||
synchronized void onNewMetadataImage(MetadataImage newImage, MetadataDelta delta) {
|
synchronized void onNewMetadataImage(CoordinatorMetadataImage newImage, CoordinatorMetadataDelta delta) {
|
||||||
this.coordinator.onNewMetadataImage(newImage, delta);
|
this.coordinator.onNewMetadataImage(newImage, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,6 @@ import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.Time;
|
import org.apache.kafka.common.utils.Time;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
import org.apache.kafka.image.MetadataDelta;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
import org.apache.kafka.image.MetadataImage;
|
||||||
import org.apache.kafka.image.MetadataProvenance;
|
|
||||||
import org.apache.kafka.server.util.FutureUtils;
|
import org.apache.kafka.server.util.FutureUtils;
|
||||||
import org.apache.kafka.server.util.timer.MockTimer;
|
import org.apache.kafka.server.util.timer.MockTimer;
|
||||||
import org.apache.kafka.storage.internals.log.LogConfig;
|
import org.apache.kafka.storage.internals.log.LogConfig;
|
||||||
|
@ -155,7 +154,7 @@ public class CoordinatorRuntimeTest {
|
||||||
assertEquals(ACTIVE, ctx.state);
|
assertEquals(ACTIVE, ctx.state);
|
||||||
|
|
||||||
// Verify that onLoaded is called.
|
// Verify that onLoaded is called.
|
||||||
verify(coordinator, times(1)).onLoaded(MetadataImage.EMPTY);
|
verify(coordinator, times(1)).onLoaded(CoordinatorMetadataImage.EMPTY);
|
||||||
|
|
||||||
// Verify that the listener is registered.
|
// Verify that the listener is registered.
|
||||||
verify(writer, times(1)).registerListener(
|
verify(writer, times(1)).registerListener(
|
||||||
|
@ -1897,11 +1896,11 @@ public class CoordinatorRuntimeTest {
|
||||||
// Coordinator 0 is loaded. It should get the current image
|
// Coordinator 0 is loaded. It should get the current image
|
||||||
// that is the empty one.
|
// that is the empty one.
|
||||||
future0.complete(null);
|
future0.complete(null);
|
||||||
verify(coordinator0).onLoaded(MetadataImage.EMPTY);
|
verify(coordinator0).onLoaded(CoordinatorMetadataImage.EMPTY);
|
||||||
|
|
||||||
// Publish a new image.
|
// Publish a new image.
|
||||||
MetadataDelta delta = new MetadataDelta(MetadataImage.EMPTY);
|
CoordinatorMetadataDelta delta = new KRaftCoordinatorMetadataDelta(new MetadataDelta(MetadataImage.EMPTY));
|
||||||
MetadataImage newImage = delta.apply(MetadataProvenance.EMPTY);
|
CoordinatorMetadataImage newImage = CoordinatorMetadataImage.EMPTY;
|
||||||
runtime.onNewMetadataImage(newImage, delta);
|
runtime.onNewMetadataImage(newImage, delta);
|
||||||
|
|
||||||
// Coordinator 0 should be notified about it.
|
// Coordinator 0 should be notified about it.
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.kafka.coordinator.common.runtime;
|
||||||
|
|
||||||
|
import org.apache.kafka.common.Uuid;
|
||||||
|
import org.apache.kafka.common.metadata.PartitionChangeRecord;
|
||||||
|
import org.apache.kafka.common.metadata.RemoveTopicRecord;
|
||||||
|
import org.apache.kafka.common.metadata.TopicRecord;
|
||||||
|
import org.apache.kafka.image.MetadataDelta;
|
||||||
|
import org.apache.kafka.image.MetadataImage;
|
||||||
|
import org.apache.kafka.image.MetadataProvenance;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
public class KRaftCoordinatorMetadataDeltaTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKRaftCoordinatorDeltaWithNulls() {
|
||||||
|
assertTrue(new KRaftCoordinatorMetadataDelta(null).changedTopicIds().isEmpty());
|
||||||
|
assertTrue(new KRaftCoordinatorMetadataDelta(new MetadataDelta(MetadataImage.EMPTY)).changedTopicIds().isEmpty());
|
||||||
|
|
||||||
|
assertTrue(new KRaftCoordinatorMetadataDelta(null).deletedTopicIds().isEmpty());
|
||||||
|
assertTrue(new KRaftCoordinatorMetadataDelta(new MetadataDelta(MetadataImage.EMPTY)).deletedTopicIds().isEmpty());
|
||||||
|
|
||||||
|
assertTrue(new KRaftCoordinatorMetadataDelta(null).createdTopicIds().isEmpty());
|
||||||
|
assertTrue(new KRaftCoordinatorMetadataDelta(new MetadataDelta(MetadataImage.EMPTY)).createdTopicIds().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKRaftCoordinatorDelta() {
|
||||||
|
Uuid topicId = Uuid.randomUuid();
|
||||||
|
String topicName = "test-topic";
|
||||||
|
Uuid topicId2 = Uuid.randomUuid();
|
||||||
|
String topicName2 = "test-topic2";
|
||||||
|
Uuid deletedTopicId = Uuid.randomUuid();
|
||||||
|
String deletedTopicName = "deleted-topic";
|
||||||
|
Uuid changedTopicId = Uuid.randomUuid();
|
||||||
|
String changedTopicName = "changed-topic";
|
||||||
|
|
||||||
|
MetadataImage image = new MetadataImageBuilder()
|
||||||
|
.addTopic(deletedTopicId, deletedTopicName, 1)
|
||||||
|
.addTopic(changedTopicId, changedTopicName, 1)
|
||||||
|
.build();
|
||||||
|
MetadataDelta delta = new MetadataDelta(image);
|
||||||
|
delta.replay(new TopicRecord().setTopicId(topicId).setName(topicName));
|
||||||
|
delta.replay(new TopicRecord().setTopicId(topicId2).setName(topicName2));
|
||||||
|
delta.replay(new RemoveTopicRecord().setTopicId(deletedTopicId));
|
||||||
|
delta.replay(new PartitionChangeRecord().setTopicId(changedTopicId).setPartitionId(0));
|
||||||
|
|
||||||
|
KRaftCoordinatorMetadataDelta coordinatorDelta = new KRaftCoordinatorMetadataDelta(delta);
|
||||||
|
|
||||||
|
// created topics
|
||||||
|
Collection<Uuid> createdTopicIds = coordinatorDelta.createdTopicIds();
|
||||||
|
assertNotNull(createdTopicIds);
|
||||||
|
assertEquals(2, createdTopicIds.size());
|
||||||
|
assertTrue(createdTopicIds.contains(topicId));
|
||||||
|
assertTrue(createdTopicIds.contains(topicId2));
|
||||||
|
|
||||||
|
// deleted topics
|
||||||
|
Set<Uuid> deletedTopicIds = coordinatorDelta.deletedTopicIds();
|
||||||
|
assertNotNull(deletedTopicIds);
|
||||||
|
assertEquals(1, deletedTopicIds.size());
|
||||||
|
assertTrue(deletedTopicIds.contains(deletedTopicId));
|
||||||
|
|
||||||
|
// changed topics (also includes created topics)
|
||||||
|
Collection<Uuid> changedTopicIds = coordinatorDelta.changedTopicIds();
|
||||||
|
assertNotNull(changedTopicIds);
|
||||||
|
assertEquals(3, changedTopicIds.size());
|
||||||
|
assertTrue(changedTopicIds.contains(changedTopicId));
|
||||||
|
assertTrue(changedTopicIds.contains(topicId));
|
||||||
|
assertTrue(changedTopicIds.contains(topicId2));
|
||||||
|
|
||||||
|
CoordinatorMetadataImage coordinatorImage = coordinatorDelta.image();
|
||||||
|
// the image only contains the original topics, not the new topics yet since we never called delta.apply()
|
||||||
|
assertNotNull(coordinatorImage);
|
||||||
|
assertEquals(Set.of(deletedTopicName, changedTopicName), coordinatorImage.topicNames());
|
||||||
|
|
||||||
|
// the image contains the correct topics after calling apply
|
||||||
|
MetadataImage imageAfterApply = delta.apply(new MetadataProvenance(123, 0, 0L, true));
|
||||||
|
CoordinatorMetadataImage coordinatorImageApply = new KRaftCoordinatorMetadataImage(imageAfterApply);
|
||||||
|
assertNotNull(coordinatorImageApply);
|
||||||
|
assertEquals(Set.of(topicName, topicName2, changedTopicName), coordinatorImageApply.topicNames());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEqualsAndHashcode() {
|
||||||
|
Uuid topicId = Uuid.randomUuid();
|
||||||
|
String topicName = "test-topic";
|
||||||
|
Uuid topicId2 = Uuid.randomUuid();
|
||||||
|
String topicName2 = "test-topic2";
|
||||||
|
Uuid topicId3 = Uuid.randomUuid();
|
||||||
|
String topicName3 = "test-topic3";
|
||||||
|
|
||||||
|
MetadataDelta delta = new MetadataDelta(MetadataImage.EMPTY);
|
||||||
|
delta.replay(new TopicRecord().setTopicId(topicId).setName(topicName));
|
||||||
|
delta.replay(new TopicRecord().setTopicId(topicId2).setName(topicName2));
|
||||||
|
|
||||||
|
KRaftCoordinatorMetadataDelta coordinatorDelta = new KRaftCoordinatorMetadataDelta(delta);
|
||||||
|
KRaftCoordinatorMetadataDelta coordinatorDeltaCopy = new KRaftCoordinatorMetadataDelta(delta);
|
||||||
|
|
||||||
|
MetadataDelta delta2 = new MetadataDelta(MetadataImage.EMPTY);
|
||||||
|
delta.replay(new TopicRecord().setTopicId(topicId3).setName(topicName3));
|
||||||
|
KRaftCoordinatorMetadataDelta coordinatorDelta2 = new KRaftCoordinatorMetadataDelta(delta2);
|
||||||
|
|
||||||
|
assertEquals(coordinatorDelta, coordinatorDeltaCopy);
|
||||||
|
assertEquals(coordinatorDelta.hashCode(), coordinatorDeltaCopy.hashCode());
|
||||||
|
assertNotEquals(coordinatorDelta, coordinatorDelta2);
|
||||||
|
assertNotEquals(coordinatorDelta.hashCode(), coordinatorDelta2.hashCode());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.kafka.coordinator.common.runtime;
|
||||||
|
|
||||||
|
import org.apache.kafka.common.Uuid;
|
||||||
|
import org.apache.kafka.image.MetadataImage;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
class KRaftCoordinatorMetadataImageTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKRaftCoordinatorMetadataImage() {
|
||||||
|
Uuid topicId = Uuid.randomUuid();
|
||||||
|
String topicName = "test-topic";
|
||||||
|
int partitionCount = 2;
|
||||||
|
Uuid topicId2 = Uuid.randomUuid();
|
||||||
|
String topicName2 = "test-topic2";
|
||||||
|
int partitionCount2 = 4;
|
||||||
|
Uuid noPartitionTopicId = Uuid.randomUuid();
|
||||||
|
String noPartitionTopic = "no-partition-topic";
|
||||||
|
long imageVersion = 123L;
|
||||||
|
|
||||||
|
MetadataImage metadataImage = new MetadataImageBuilder()
|
||||||
|
.addTopic(topicId, topicName, partitionCount)
|
||||||
|
.addTopic(topicId2, topicName2, partitionCount2)
|
||||||
|
.addTopic(noPartitionTopicId, noPartitionTopic, 0)
|
||||||
|
.addRacks()
|
||||||
|
.build(imageVersion);
|
||||||
|
|
||||||
|
KRaftCoordinatorMetadataImage image = new KRaftCoordinatorMetadataImage(metadataImage);
|
||||||
|
|
||||||
|
assertEquals(Set.of(topicName, topicName2, noPartitionTopic), image.topicNames());
|
||||||
|
assertEquals(Set.of(topicId, topicId2, noPartitionTopicId), image.topicIds());
|
||||||
|
|
||||||
|
image.topicMetadata(topicName).ifPresentOrElse(
|
||||||
|
topicMetadata -> {
|
||||||
|
assertEquals(topicName, topicMetadata.name());
|
||||||
|
assertEquals(topicId, topicMetadata.id());
|
||||||
|
assertEquals(partitionCount, topicMetadata.partitionCount());
|
||||||
|
List<String> racks0 = topicMetadata.partitionRacks(0);
|
||||||
|
List<String> racks1 = topicMetadata.partitionRacks(1);
|
||||||
|
assertEquals(2, racks0.size());
|
||||||
|
assertEquals(2, racks1.size());
|
||||||
|
assertEquals("rack0", racks0.get(0));
|
||||||
|
assertEquals("rack1", racks0.get(1));
|
||||||
|
assertEquals("rack1", racks1.get(0));
|
||||||
|
assertEquals("rack2", racks1.get(1));
|
||||||
|
},
|
||||||
|
() -> fail("Expected topic metadata for " + topicName)
|
||||||
|
);
|
||||||
|
|
||||||
|
image.topicMetadata(topicName2).ifPresentOrElse(
|
||||||
|
topicMetadata -> {
|
||||||
|
assertEquals(topicName2, topicMetadata.name());
|
||||||
|
assertEquals(topicId2, topicMetadata.id());
|
||||||
|
assertEquals(partitionCount2, topicMetadata.partitionCount());
|
||||||
|
List<String> racks0 = topicMetadata.partitionRacks(0);
|
||||||
|
List<String> racks1 = topicMetadata.partitionRacks(1);
|
||||||
|
assertEquals(2, racks0.size());
|
||||||
|
assertEquals(2, racks1.size());
|
||||||
|
assertEquals("rack0", racks0.get(0));
|
||||||
|
assertEquals("rack1", racks0.get(1));
|
||||||
|
assertEquals("rack1", racks1.get(0));
|
||||||
|
assertEquals("rack2", racks1.get(1));
|
||||||
|
},
|
||||||
|
() -> fail("Expected topic metadata for " + topicName)
|
||||||
|
);
|
||||||
|
|
||||||
|
image.topicMetadata(noPartitionTopic).ifPresentOrElse(
|
||||||
|
topicMetadata -> {
|
||||||
|
assertEquals(noPartitionTopic, topicMetadata.name());
|
||||||
|
assertEquals(noPartitionTopicId, topicMetadata.id());
|
||||||
|
assertEquals(0, topicMetadata.partitionCount());
|
||||||
|
List<String> racks = topicMetadata.partitionRacks(0);
|
||||||
|
assertEquals(0, racks.size());
|
||||||
|
},
|
||||||
|
() -> fail("Expected topic metadata for " + topicName)
|
||||||
|
);
|
||||||
|
|
||||||
|
assertNotNull(image.emptyDelta());
|
||||||
|
|
||||||
|
assertEquals(metadataImage.offset(), image.version());
|
||||||
|
assertEquals(imageVersion, image.version());
|
||||||
|
|
||||||
|
assertFalse(image.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEqualsAndHashcode() {
|
||||||
|
Uuid topicId = Uuid.randomUuid();
|
||||||
|
String topicName = "test-topic";
|
||||||
|
int partitionCount = 2;
|
||||||
|
Uuid topicId2 = Uuid.randomUuid();
|
||||||
|
String topicName2 = "test-topic2";
|
||||||
|
int partitionCount2 = 4;
|
||||||
|
long imageVersion = 123L;
|
||||||
|
|
||||||
|
MetadataImage metadataImage = new MetadataImageBuilder()
|
||||||
|
.addTopic(topicId, topicName, partitionCount)
|
||||||
|
.addRacks()
|
||||||
|
.build(imageVersion);
|
||||||
|
|
||||||
|
KRaftCoordinatorMetadataImage coordinatorMetadataImage = new KRaftCoordinatorMetadataImage(metadataImage);
|
||||||
|
KRaftCoordinatorMetadataImage coordinatorMetadataImageCopy = new KRaftCoordinatorMetadataImage(metadataImage);
|
||||||
|
|
||||||
|
MetadataImage metadataImage2 = new MetadataImageBuilder()
|
||||||
|
.addTopic(topicId2, topicName2, partitionCount2)
|
||||||
|
.addRacks()
|
||||||
|
.build(imageVersion);
|
||||||
|
|
||||||
|
KRaftCoordinatorMetadataImage coordinatorMetadataImage2 = new KRaftCoordinatorMetadataImage(metadataImage2);
|
||||||
|
|
||||||
|
assertEquals(coordinatorMetadataImage, coordinatorMetadataImageCopy);
|
||||||
|
assertNotEquals(coordinatorMetadataImage, coordinatorMetadataImage2);
|
||||||
|
|
||||||
|
assertEquals(coordinatorMetadataImage.hashCode(), coordinatorMetadataImageCopy.hashCode());
|
||||||
|
assertNotEquals(coordinatorMetadataImage.hashCode(), coordinatorMetadataImage2.hashCode());
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.apache.kafka.coordinator.group;
|
package org.apache.kafka.coordinator.common.runtime;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.common.metadata.PartitionRecord;
|
import org.apache.kafka.common.metadata.PartitionRecord;
|
||||||
|
@ -75,4 +75,12 @@ public class MetadataImageBuilder {
|
||||||
public MetadataImage build(long version) {
|
public MetadataImage build(long version) {
|
||||||
return delta.apply(new MetadataProvenance(version, 0, 0L, true));
|
return delta.apply(new MetadataProvenance(version, 0, 0L, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CoordinatorMetadataImage buildCoordinatorMetadataImage() {
|
||||||
|
return new KRaftCoordinatorMetadataImage(build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoordinatorMetadataImage buildCoordinatorMetadataImage(long version) {
|
||||||
|
return new KRaftCoordinatorMetadataImage(build(version));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@ import kafka.utils.Logging
|
||||||
import org.apache.kafka.common.TopicPartition
|
import org.apache.kafka.common.TopicPartition
|
||||||
import org.apache.kafka.common.errors.TimeoutException
|
import org.apache.kafka.common.errors.TimeoutException
|
||||||
import org.apache.kafka.common.internals.Topic
|
import org.apache.kafka.common.internals.Topic
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.{KRaftCoordinatorMetadataDelta, KRaftCoordinatorMetadataImage}
|
||||||
import org.apache.kafka.coordinator.group.GroupCoordinator
|
import org.apache.kafka.coordinator.group.GroupCoordinator
|
||||||
import org.apache.kafka.coordinator.share.ShareCoordinator
|
import org.apache.kafka.coordinator.share.ShareCoordinator
|
||||||
import org.apache.kafka.coordinator.transaction.TransactionLogConfig
|
import org.apache.kafka.coordinator.transaction.TransactionLogConfig
|
||||||
|
@ -233,7 +234,7 @@ class BrokerMetadataPublisher(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Propagate the new image to the group coordinator.
|
// Propagate the new image to the group coordinator.
|
||||||
groupCoordinator.onNewMetadataImage(newImage, delta)
|
groupCoordinator.onNewMetadataImage(new KRaftCoordinatorMetadataImage(newImage), new KRaftCoordinatorMetadataDelta(delta))
|
||||||
} catch {
|
} catch {
|
||||||
case t: Throwable => metadataPublishingFaultHandler.handleFault("Error updating group " +
|
case t: Throwable => metadataPublishingFaultHandler.handleFault("Error updating group " +
|
||||||
s"coordinator with local changes in $deltaName", t)
|
s"coordinator with local changes in $deltaName", t)
|
||||||
|
@ -241,7 +242,7 @@ class BrokerMetadataPublisher(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Propagate the new image to the share coordinator.
|
// Propagate the new image to the share coordinator.
|
||||||
shareCoordinator.onNewMetadataImage(newImage, delta)
|
shareCoordinator.onNewMetadataImage(new KRaftCoordinatorMetadataImage(newImage), newImage.features(), new KRaftCoordinatorMetadataDelta(delta))
|
||||||
} catch {
|
} catch {
|
||||||
case t: Throwable => metadataPublishingFaultHandler.handleFault("Error updating share " +
|
case t: Throwable => metadataPublishingFaultHandler.handleFault("Error updating share " +
|
||||||
s"coordinator with local changes in $deltaName", t)
|
s"coordinator with local changes in $deltaName", t)
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.apache.kafka.common.internals.Topic
|
||||||
import org.apache.kafka.common.metadata.{FeatureLevelRecord, PartitionRecord, RemoveTopicRecord, TopicRecord}
|
import org.apache.kafka.common.metadata.{FeatureLevelRecord, PartitionRecord, RemoveTopicRecord, TopicRecord}
|
||||||
import org.apache.kafka.common.test.{KafkaClusterTestKit, TestKitNodes}
|
import org.apache.kafka.common.test.{KafkaClusterTestKit, TestKitNodes}
|
||||||
import org.apache.kafka.common.utils.Exit
|
import org.apache.kafka.common.utils.Exit
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.{KRaftCoordinatorMetadataDelta, KRaftCoordinatorMetadataImage}
|
||||||
import org.apache.kafka.coordinator.group.GroupCoordinator
|
import org.apache.kafka.coordinator.group.GroupCoordinator
|
||||||
import org.apache.kafka.coordinator.share.ShareCoordinator
|
import org.apache.kafka.coordinator.share.ShareCoordinator
|
||||||
import org.apache.kafka.image.{AclsImage, ClientQuotasImage, ClusterImageTest, ConfigurationsImage, DelegationTokenImage, FeaturesImage, MetadataDelta, MetadataImage, MetadataImageTest, MetadataProvenance, ProducerIdsImage, ScramImage, TopicsImage}
|
import org.apache.kafka.image.{AclsImage, ClientQuotasImage, ClusterImageTest, ConfigurationsImage, DelegationTokenImage, FeaturesImage, MetadataDelta, MetadataImage, MetadataImageTest, MetadataProvenance, ProducerIdsImage, ScramImage, TopicsImage}
|
||||||
|
@ -291,7 +292,7 @@ class BrokerMetadataPublisherTest {
|
||||||
.numBytes(42)
|
.numBytes(42)
|
||||||
.build())
|
.build())
|
||||||
|
|
||||||
verify(groupCoordinator).onNewMetadataImage(image, delta)
|
verify(groupCoordinator).onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), new KRaftCoordinatorMetadataDelta(delta))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -53,9 +53,9 @@ import org.apache.kafka.common.message.TxnOffsetCommitRequestData;
|
||||||
import org.apache.kafka.common.message.TxnOffsetCommitResponseData;
|
import org.apache.kafka.common.message.TxnOffsetCommitResponseData;
|
||||||
import org.apache.kafka.common.requests.TransactionResult;
|
import org.apache.kafka.common.requests.TransactionResult;
|
||||||
import org.apache.kafka.common.utils.BufferSupplier;
|
import org.apache.kafka.common.utils.BufferSupplier;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataDelta;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsGroupHeartbeatResult;
|
import org.apache.kafka.coordinator.group.streams.StreamsGroupHeartbeatResult;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.server.authorizer.AuthorizableRequestContext;
|
import org.apache.kafka.server.authorizer.AuthorizableRequestContext;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
@ -469,8 +469,8 @@ public interface GroupCoordinator {
|
||||||
* @param delta The metadata delta.
|
* @param delta The metadata delta.
|
||||||
*/
|
*/
|
||||||
void onNewMetadataImage(
|
void onNewMetadataImage(
|
||||||
MetadataImage newImage,
|
CoordinatorMetadataImage newImage,
|
||||||
MetadataDelta delta
|
CoordinatorMetadataDelta delta
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -84,6 +84,8 @@ import org.apache.kafka.common.utils.Time;
|
||||||
import org.apache.kafka.common.utils.Utils;
|
import org.apache.kafka.common.utils.Utils;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorEventProcessor;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorEventProcessor;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorLoader;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorLoader;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataDelta;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorResult;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorResult;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRuntime;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRuntime;
|
||||||
|
@ -94,9 +96,6 @@ import org.apache.kafka.coordinator.common.runtime.PartitionWriter;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.ConsumerGroupPartitionAssignor;
|
import org.apache.kafka.coordinator.group.api.assignor.ConsumerGroupPartitionAssignor;
|
||||||
import org.apache.kafka.coordinator.group.metrics.GroupCoordinatorMetrics;
|
import org.apache.kafka.coordinator.group.metrics.GroupCoordinatorMetrics;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsGroupHeartbeatResult;
|
import org.apache.kafka.coordinator.group.streams.StreamsGroupHeartbeatResult;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.image.TopicImage;
|
|
||||||
import org.apache.kafka.server.authorizer.AuthorizableRequestContext;
|
import org.apache.kafka.server.authorizer.AuthorizableRequestContext;
|
||||||
import org.apache.kafka.server.authorizer.Authorizer;
|
import org.apache.kafka.server.authorizer.Authorizer;
|
||||||
import org.apache.kafka.server.record.BrokerCompressionType;
|
import org.apache.kafka.server.record.BrokerCompressionType;
|
||||||
|
@ -329,9 +328,9 @@ public class GroupCoordinatorService implements GroupCoordinator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The metadata image to extract topic id to names map.
|
* The metadata image to extract topic id to names map.
|
||||||
* This is initialised when the {@link GroupCoordinator#onNewMetadataImage(MetadataImage, MetadataDelta)} is called
|
* This is initialised when the {@link GroupCoordinator#onNewMetadataImage(CoordinatorMetadataImage, CoordinatorMetadataDelta)} is called
|
||||||
*/
|
*/
|
||||||
private MetadataImage metadataImage = null;
|
private CoordinatorMetadataImage metadataImage = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -1689,8 +1688,9 @@ public class GroupCoordinatorService implements GroupCoordinator {
|
||||||
List<ReadShareGroupStateSummaryRequestData.ReadStateSummaryData> readStateSummaryData = new ArrayList<>(requestData.topics().size());
|
List<ReadShareGroupStateSummaryRequestData.ReadStateSummaryData> readStateSummaryData = new ArrayList<>(requestData.topics().size());
|
||||||
List<DescribeShareGroupOffsetsResponseData.DescribeShareGroupOffsetsResponseTopic> describeShareGroupOffsetsResponseTopicList = new ArrayList<>(requestData.topics().size());
|
List<DescribeShareGroupOffsetsResponseData.DescribeShareGroupOffsetsResponseTopic> describeShareGroupOffsetsResponseTopicList = new ArrayList<>(requestData.topics().size());
|
||||||
requestData.topics().forEach(topic -> {
|
requestData.topics().forEach(topic -> {
|
||||||
Uuid topicId = metadataImage.topics().topicNameToIdView().get(topic.topicName());
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadataOpt = metadataImage.topicMetadata(topic.topicName());
|
||||||
if (topicId != null) {
|
if (topicMetadataOpt.isPresent()) {
|
||||||
|
var topicId = topicMetadataOpt.get().id();
|
||||||
requestTopicIdToNameMapping.put(topicId, topic.topicName());
|
requestTopicIdToNameMapping.put(topicId, topic.topicName());
|
||||||
readStateSummaryData.add(new ReadShareGroupStateSummaryRequestData.ReadStateSummaryData()
|
readStateSummaryData.add(new ReadShareGroupStateSummaryRequestData.ReadStateSummaryData()
|
||||||
.setTopicId(topicId)
|
.setTopicId(topicId)
|
||||||
|
@ -1757,9 +1757,8 @@ public class GroupCoordinatorService implements GroupCoordinator {
|
||||||
ReadShareGroupStateSummaryRequestData readSummaryRequestData = new ReadShareGroupStateSummaryRequestData()
|
ReadShareGroupStateSummaryRequestData readSummaryRequestData = new ReadShareGroupStateSummaryRequestData()
|
||||||
.setGroupId(requestData.groupId());
|
.setGroupId(requestData.groupId());
|
||||||
topicPartitionMap.forEach((topicId, partitionSet) -> {
|
topicPartitionMap.forEach((topicId, partitionSet) -> {
|
||||||
String topicName = metadataImage.topics().topicIdToNameView().get(topicId);
|
metadataImage.topicMetadata(topicId).ifPresent(topicMetadata -> {
|
||||||
if (topicName != null) {
|
requestTopicIdToNameMapping.put(topicId, topicMetadata.name());
|
||||||
requestTopicIdToNameMapping.put(topicId, topicName);
|
|
||||||
readSummaryRequestData.topics().add(new ReadShareGroupStateSummaryRequestData.ReadStateSummaryData()
|
readSummaryRequestData.topics().add(new ReadShareGroupStateSummaryRequestData.ReadStateSummaryData()
|
||||||
.setTopicId(topicId)
|
.setTopicId(topicId)
|
||||||
.setPartitions(
|
.setPartitions(
|
||||||
|
@ -1767,7 +1766,7 @@ public class GroupCoordinatorService implements GroupCoordinator {
|
||||||
partitionIndex -> new ReadShareGroupStateSummaryRequestData.PartitionData().setPartition(partitionIndex)
|
partitionIndex -> new ReadShareGroupStateSummaryRequestData.PartitionData().setPartition(partitionIndex)
|
||||||
).toList()
|
).toList()
|
||||||
));
|
));
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
return readShareGroupStateSummary(readSummaryRequestData, requestTopicIdToNameMapping, describeShareGroupOffsetsResponseTopicList);
|
return readShareGroupStateSummary(readSummaryRequestData, requestTopicIdToNameMapping, describeShareGroupOffsetsResponseTopicList);
|
||||||
});
|
});
|
||||||
|
@ -1917,18 +1916,20 @@ public class GroupCoordinatorService implements GroupCoordinator {
|
||||||
.filter(errData -> errData.errorCode() != Errors.NONE.code())
|
.filter(errData -> errData.errorCode() != Errors.NONE.code())
|
||||||
.findAny();
|
.findAny();
|
||||||
|
|
||||||
|
String topicName = metadataImage.topicMetadata(topicData.topicId()).map(CoordinatorMetadataImage.TopicMetadata::name).orElse(null);
|
||||||
|
|
||||||
if (errItem.isPresent()) {
|
if (errItem.isPresent()) {
|
||||||
errorTopicResponses.add(
|
errorTopicResponses.add(
|
||||||
new DeleteShareGroupOffsetsResponseData.DeleteShareGroupOffsetsResponseTopic()
|
new DeleteShareGroupOffsetsResponseData.DeleteShareGroupOffsetsResponseTopic()
|
||||||
.setTopicId(topicData.topicId())
|
.setTopicId(topicData.topicId())
|
||||||
.setTopicName(metadataImage.topics().topicIdToNameView().get(topicData.topicId()))
|
.setTopicName(topicName)
|
||||||
.setErrorMessage(Errors.forCode(errItem.get().errorCode()).message())
|
.setErrorMessage(Errors.forCode(errItem.get().errorCode()).message())
|
||||||
.setErrorCode(errItem.get().errorCode())
|
.setErrorCode(errItem.get().errorCode())
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
successTopics.put(
|
successTopics.put(
|
||||||
topicData.topicId(),
|
topicData.topicId(),
|
||||||
metadataImage.topics().topicIdToNameView().get(topicData.topicId())
|
topicName
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2138,17 +2139,14 @@ public class GroupCoordinatorService implements GroupCoordinator {
|
||||||
|
|
||||||
// At this point the metadata will not have been updated
|
// At this point the metadata will not have been updated
|
||||||
// with the deleted topics. However, we must guard against it.
|
// with the deleted topics. However, we must guard against it.
|
||||||
if (metadataImage == null || metadataImage.equals(MetadataImage.EMPTY)) {
|
if (metadataImage == null || metadataImage.equals(CoordinatorMetadataImage.EMPTY)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Uuid> topicIds = new HashSet<>();
|
Set<Uuid> topicIds = topicPartitions.stream()
|
||||||
for (TopicPartition tp : topicPartitions) {
|
.filter(tp -> metadataImage.topicMetadata(tp.topic()).isPresent())
|
||||||
TopicImage image = metadataImage.topics().getTopic(tp.topic());
|
.map(tp -> metadataImage.topicMetadata(tp.topic()).get().id())
|
||||||
if (image != null) {
|
.collect(Collectors.toSet());
|
||||||
topicIds.add(image.id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topicIds.isEmpty()) {
|
if (topicIds.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -2200,12 +2198,12 @@ public class GroupCoordinatorService implements GroupCoordinator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link GroupCoordinator#onNewMetadataImage(MetadataImage, MetadataDelta)}.
|
* See {@link GroupCoordinator#onNewMetadataImage(CoordinatorMetadataImage, CoordinatorMetadataDelta)}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onNewMetadataImage(
|
public void onNewMetadataImage(
|
||||||
MetadataImage newImage,
|
CoordinatorMetadataImage newImage,
|
||||||
MetadataDelta delta
|
CoordinatorMetadataDelta delta
|
||||||
) {
|
) {
|
||||||
throwIfNotActive();
|
throwIfNotActive();
|
||||||
metadataImage = newImage;
|
metadataImage = newImage;
|
||||||
|
|
|
@ -61,6 +61,8 @@ import org.apache.kafka.common.requests.TransactionResult;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.Time;
|
import org.apache.kafka.common.utils.Time;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorExecutor;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorExecutor;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataDelta;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetrics;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetrics;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetricsShard;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetricsShard;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
|
@ -117,8 +119,6 @@ import org.apache.kafka.coordinator.group.metrics.GroupCoordinatorMetrics;
|
||||||
import org.apache.kafka.coordinator.group.metrics.GroupCoordinatorMetricsShard;
|
import org.apache.kafka.coordinator.group.metrics.GroupCoordinatorMetricsShard;
|
||||||
import org.apache.kafka.coordinator.group.modern.share.ShareGroup;
|
import org.apache.kafka.coordinator.group.modern.share.ShareGroup;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsGroupHeartbeatResult;
|
import org.apache.kafka.coordinator.group.streams.StreamsGroupHeartbeatResult;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.server.authorizer.AuthorizableRequestContext;
|
import org.apache.kafka.server.authorizer.AuthorizableRequestContext;
|
||||||
import org.apache.kafka.server.authorizer.Authorizer;
|
import org.apache.kafka.server.authorizer.Authorizer;
|
||||||
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
||||||
|
@ -1088,8 +1088,8 @@ public class GroupCoordinatorShard implements CoordinatorShard<CoordinatorRecord
|
||||||
* @param newImage The metadata image.
|
* @param newImage The metadata image.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onLoaded(MetadataImage newImage) {
|
public void onLoaded(CoordinatorMetadataImage newImage) {
|
||||||
MetadataDelta emptyDelta = new MetadataDelta(newImage);
|
CoordinatorMetadataDelta emptyDelta = newImage.emptyDelta();
|
||||||
groupMetadataManager.onNewMetadataImage(newImage, emptyDelta);
|
groupMetadataManager.onNewMetadataImage(newImage, emptyDelta);
|
||||||
coordinatorMetrics.activateMetricsShard(metricsShard);
|
coordinatorMetrics.activateMetricsShard(metricsShard);
|
||||||
|
|
||||||
|
@ -1113,7 +1113,7 @@ public class GroupCoordinatorShard implements CoordinatorShard<CoordinatorRecord
|
||||||
* @param delta The delta image.
|
* @param delta The delta image.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onNewMetadataImage(MetadataImage newImage, MetadataDelta delta) {
|
public void onNewMetadataImage(CoordinatorMetadataImage newImage, CoordinatorMetadataDelta delta) {
|
||||||
groupMetadataManager.onNewMetadataImage(newImage, delta);
|
groupMetadataManager.onNewMetadataImage(newImage, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,8 @@ import org.apache.kafka.common.resource.ResourcePattern;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.Time;
|
import org.apache.kafka.common.utils.Time;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorExecutor;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorExecutor;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataDelta;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorResult;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorResult;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorTimer;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorTimer;
|
||||||
|
@ -160,11 +162,6 @@ import org.apache.kafka.coordinator.group.streams.topics.ConfiguredTopology;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.EndpointToPartitionsManager;
|
import org.apache.kafka.coordinator.group.streams.topics.EndpointToPartitionsManager;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.InternalTopicManager;
|
import org.apache.kafka.coordinator.group.streams.topics.InternalTopicManager;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.TopicConfigurationException;
|
import org.apache.kafka.coordinator.group.streams.topics.TopicConfigurationException;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.image.TopicImage;
|
|
||||||
import org.apache.kafka.image.TopicsDelta;
|
|
||||||
import org.apache.kafka.image.TopicsImage;
|
|
||||||
import org.apache.kafka.server.authorizer.Action;
|
import org.apache.kafka.server.authorizer.Action;
|
||||||
import org.apache.kafka.server.authorizer.AuthorizableRequestContext;
|
import org.apache.kafka.server.authorizer.AuthorizableRequestContext;
|
||||||
import org.apache.kafka.server.authorizer.AuthorizationResult;
|
import org.apache.kafka.server.authorizer.AuthorizationResult;
|
||||||
|
@ -294,7 +291,7 @@ public class GroupMetadataManager {
|
||||||
private CoordinatorExecutor<CoordinatorRecord> executor = null;
|
private CoordinatorExecutor<CoordinatorRecord> executor = null;
|
||||||
private GroupCoordinatorConfig config = null;
|
private GroupCoordinatorConfig config = null;
|
||||||
private GroupConfigManager groupConfigManager = null;
|
private GroupConfigManager groupConfigManager = null;
|
||||||
private MetadataImage metadataImage = null;
|
private CoordinatorMetadataImage metadataImage = null;
|
||||||
private ShareGroupPartitionAssignor shareGroupAssignor = null;
|
private ShareGroupPartitionAssignor shareGroupAssignor = null;
|
||||||
private GroupCoordinatorMetricsShard metrics;
|
private GroupCoordinatorMetricsShard metrics;
|
||||||
private Optional<Plugin<Authorizer>> authorizerPlugin = null;
|
private Optional<Plugin<Authorizer>> authorizerPlugin = null;
|
||||||
|
@ -340,7 +337,7 @@ public class GroupMetadataManager {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder withMetadataImage(MetadataImage metadataImage) {
|
Builder withMetadataImage(CoordinatorMetadataImage metadataImage) {
|
||||||
this.metadataImage = metadataImage;
|
this.metadataImage = metadataImage;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -363,7 +360,7 @@ public class GroupMetadataManager {
|
||||||
GroupMetadataManager build() {
|
GroupMetadataManager build() {
|
||||||
if (logContext == null) logContext = new LogContext();
|
if (logContext == null) logContext = new LogContext();
|
||||||
if (snapshotRegistry == null) snapshotRegistry = new SnapshotRegistry(logContext);
|
if (snapshotRegistry == null) snapshotRegistry = new SnapshotRegistry(logContext);
|
||||||
if (metadataImage == null) metadataImage = MetadataImage.EMPTY;
|
if (metadataImage == null) metadataImage = CoordinatorMetadataImage.EMPTY;
|
||||||
if (time == null) time = Time.SYSTEM;
|
if (time == null) time = Time.SYSTEM;
|
||||||
if (authorizerPlugin == null) authorizerPlugin = Optional.empty();
|
if (authorizerPlugin == null) authorizerPlugin = Optional.empty();
|
||||||
|
|
||||||
|
@ -485,17 +482,17 @@ public class GroupMetadataManager {
|
||||||
/**
|
/**
|
||||||
* The metadata image.
|
* The metadata image.
|
||||||
*/
|
*/
|
||||||
private MetadataImage metadataImage;
|
private CoordinatorMetadataImage metadataImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The cache for topic hash value by topic name.
|
* The cache for topic hash value by topic name.
|
||||||
* A topic hash is calculated when there is a group subscribes to it.
|
* A topic hash is calculated when there is a group subscribes to it.
|
||||||
* A topic hash is removed when it's updated in MetadataImage or there is no group subscribes to it.
|
* A topic hash is removed when it's updated in CoordinatorMetadataImage or there is no group subscribes to it.
|
||||||
*/
|
*/
|
||||||
private final Map<String, Long> topicHashCache;
|
private final Map<String, Long> topicHashCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This tracks the version (or the offset) of the last metadata image
|
* This tracks the version of the last metadata image
|
||||||
* with newly created topics.
|
* with newly created topics.
|
||||||
*/
|
*/
|
||||||
private long lastMetadataImageWithNewTopics = -1L;
|
private long lastMetadataImageWithNewTopics = -1L;
|
||||||
|
@ -526,7 +523,7 @@ public class GroupMetadataManager {
|
||||||
CoordinatorTimer<Void, CoordinatorRecord> timer,
|
CoordinatorTimer<Void, CoordinatorRecord> timer,
|
||||||
CoordinatorExecutor<CoordinatorRecord> executor,
|
CoordinatorExecutor<CoordinatorRecord> executor,
|
||||||
GroupCoordinatorMetricsShard metrics,
|
GroupCoordinatorMetricsShard metrics,
|
||||||
MetadataImage metadataImage,
|
CoordinatorMetadataImage metadataImage,
|
||||||
GroupCoordinatorConfig config,
|
GroupCoordinatorConfig config,
|
||||||
GroupConfigManager groupConfigManager,
|
GroupConfigManager groupConfigManager,
|
||||||
ShareGroupPartitionAssignor shareGroupAssignor,
|
ShareGroupPartitionAssignor shareGroupAssignor,
|
||||||
|
@ -560,7 +557,7 @@ public class GroupMetadataManager {
|
||||||
/**
|
/**
|
||||||
* @return The current metadata image used by the group metadata manager.
|
* @return The current metadata image used by the group metadata manager.
|
||||||
*/
|
*/
|
||||||
public MetadataImage image() {
|
public CoordinatorMetadataImage image() {
|
||||||
return metadataImage;
|
return metadataImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,7 +646,7 @@ public class GroupMetadataManager {
|
||||||
describedGroups.add(consumerGroup(groupId, committedOffset).asDescribedGroup(
|
describedGroups.add(consumerGroup(groupId, committedOffset).asDescribedGroup(
|
||||||
committedOffset,
|
committedOffset,
|
||||||
defaultConsumerGroupAssignor.name(),
|
defaultConsumerGroupAssignor.name(),
|
||||||
metadataImage.topics()
|
metadataImage
|
||||||
));
|
));
|
||||||
} catch (GroupIdNotFoundException exception) {
|
} catch (GroupIdNotFoundException exception) {
|
||||||
describedGroups.add(new ConsumerGroupDescribeResponseData.DescribedGroup()
|
describedGroups.add(new ConsumerGroupDescribeResponseData.DescribedGroup()
|
||||||
|
@ -681,7 +678,7 @@ public class GroupMetadataManager {
|
||||||
describedGroups.add(shareGroup(groupId, committedOffset).asDescribedGroup(
|
describedGroups.add(shareGroup(groupId, committedOffset).asDescribedGroup(
|
||||||
committedOffset,
|
committedOffset,
|
||||||
shareGroupAssignor.name(),
|
shareGroupAssignor.name(),
|
||||||
metadataImage.topics()
|
metadataImage
|
||||||
));
|
));
|
||||||
} catch (GroupIdNotFoundException exception) {
|
} catch (GroupIdNotFoundException exception) {
|
||||||
describedGroups.add(new ShareGroupDescribeResponseData.DescribedGroup()
|
describedGroups.add(new ShareGroupDescribeResponseData.DescribedGroup()
|
||||||
|
@ -1940,7 +1937,7 @@ public class GroupMetadataManager {
|
||||||
|
|
||||||
if (reconfigureTopology || group.configuredTopology().isEmpty()) {
|
if (reconfigureTopology || group.configuredTopology().isEmpty()) {
|
||||||
log.info("[GroupId {}][MemberId {}] Configuring the topology {}", groupId, memberId, updatedTopology);
|
log.info("[GroupId {}][MemberId {}] Configuring the topology {}", groupId, memberId, updatedTopology);
|
||||||
updatedConfiguredTopology = InternalTopicManager.configureTopics(logContext, metadataHash, updatedTopology, metadataImage.topics());
|
updatedConfiguredTopology = InternalTopicManager.configureTopics(logContext, metadataHash, updatedTopology, metadataImage);
|
||||||
group.setConfiguredTopology(updatedConfiguredTopology);
|
group.setConfiguredTopology(updatedConfiguredTopology);
|
||||||
} else {
|
} else {
|
||||||
updatedConfiguredTopology = group.configuredTopology().get();
|
updatedConfiguredTopology = group.configuredTopology().get();
|
||||||
|
@ -2471,7 +2468,7 @@ public class GroupMetadataManager {
|
||||||
group::currentPartitionEpoch,
|
group::currentPartitionEpoch,
|
||||||
targetAssignmentEpoch,
|
targetAssignmentEpoch,
|
||||||
targetAssignment,
|
targetAssignment,
|
||||||
toTopicPartitions(subscription.ownedPartitions(), metadataImage.topics()),
|
toTopicPartitions(subscription.ownedPartitions(), metadataImage),
|
||||||
records
|
records
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2748,19 +2745,20 @@ public class GroupMetadataManager {
|
||||||
// Here will add any topics which are subscribed but not initialized and initializing
|
// Here will add any topics which are subscribed but not initialized and initializing
|
||||||
// topics whose timestamp indicates that they are older than delta elapsed.
|
// topics whose timestamp indicates that they are older than delta elapsed.
|
||||||
subscriptionTopicNames.forEach(topicName -> {
|
subscriptionTopicNames.forEach(topicName -> {
|
||||||
TopicImage topicImage = metadataImage.topics().getTopic(topicName);
|
metadataImage.topicMetadata(topicName).ifPresent(topicMetadata -> {
|
||||||
if (topicImage != null) {
|
Set<Integer> alreadyInitializedPartSet = alreadyInitialized.containsKey(topicMetadata.id()) ? alreadyInitialized.get(topicMetadata.id()).partitions() : Set.of();
|
||||||
Set<Integer> alreadyInitializedPartSet = alreadyInitialized.containsKey(topicImage.id()) ? alreadyInitialized.get(topicImage.id()).partitions() : Set.of();
|
if (alreadyInitializedPartSet.isEmpty() || alreadyInitializedPartSet.size() < topicMetadata.partitionCount()) {
|
||||||
if (alreadyInitializedPartSet.isEmpty() || alreadyInitializedPartSet.size() < topicImage.partitions().size()) {
|
|
||||||
Set<Integer> partitionSet = new HashSet<>(topicImage.partitions().keySet());
|
|
||||||
partitionSet.removeAll(alreadyInitializedPartSet);
|
|
||||||
// alreadyInitialized contains all initialized topics and initializing topics which are less than delta old
|
// alreadyInitialized contains all initialized topics and initializing topics which are less than delta old
|
||||||
// which means we are putting subscribed topics which are unseen or initializing for more than delta. But, we
|
// which means we are putting subscribed topics which are unseen or initializing for more than delta. But, we
|
||||||
// are also updating the timestamp here which means, old initializing will not be included repeatedly.
|
// are also updating the timestamp here which means, old initializing will not be included repeatedly.
|
||||||
topicPartitionChangeMap.computeIfAbsent(topicImage.id(), k -> new InitMapValue(topicImage.name(), partitionSet, curTimestamp));
|
topicPartitionChangeMap.computeIfAbsent(topicMetadata.id(), k -> {
|
||||||
}
|
Set<Integer> partitionSet = IntStream.range(0, topicMetadata.partitionCount()).boxed().collect(Collectors.toCollection(HashSet::new));
|
||||||
|
partitionSet.removeAll(alreadyInitializedPartSet);
|
||||||
|
return new InitMapValue(topicMetadata.name(), partitionSet, curTimestamp);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
return topicPartitionChangeMap;
|
return topicPartitionChangeMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2839,7 +2837,8 @@ public class GroupMetadataManager {
|
||||||
if (!currentDeleting.isEmpty()) {
|
if (!currentDeleting.isEmpty()) {
|
||||||
finalInitializingMap.keySet().forEach(key -> {
|
finalInitializingMap.keySet().forEach(key -> {
|
||||||
if (currentDeleting.remove(key)) {
|
if (currentDeleting.remove(key)) {
|
||||||
log.warn("Initializing topic {} for share group {} found in deleting state as well, removing from deleting.", metadataImage.topics().getTopic(key).name(), groupId);
|
String topicName = metadataImage.topicMetadata(key).map(CoordinatorMetadataImage.TopicMetadata::name).orElse(null);
|
||||||
|
log.warn("Initializing topic {} for share group {} found in deleting state as well, removing from deleting.", topicName, groupId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3213,7 +3212,7 @@ public class GroupMetadataManager {
|
||||||
String groupId,
|
String groupId,
|
||||||
Logger log,
|
Logger log,
|
||||||
Time time,
|
Time time,
|
||||||
MetadataImage image,
|
CoordinatorMetadataImage image,
|
||||||
Optional<Plugin<Authorizer>> authorizerPlugin,
|
Optional<Plugin<Authorizer>> authorizerPlugin,
|
||||||
Set<String> regexes
|
Set<String> regexes
|
||||||
) {
|
) {
|
||||||
|
@ -3235,7 +3234,7 @@ public class GroupMetadataManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String topicName : image.topics().topicsByName().keySet()) {
|
for (String topicName : image.topicNames()) {
|
||||||
for (Pattern regex : compiledRegexes) {
|
for (Pattern regex : compiledRegexes) {
|
||||||
if (regex.matcher(topicName).matches()) {
|
if (regex.matcher(topicName).matches()) {
|
||||||
resolvedRegexes.get(regex.pattern()).add(topicName);
|
resolvedRegexes.get(regex.pattern()).add(topicName);
|
||||||
|
@ -3249,7 +3248,7 @@ public class GroupMetadataManager {
|
||||||
resolvedRegexes
|
resolvedRegexes
|
||||||
);
|
);
|
||||||
|
|
||||||
long version = image.provenance().lastContainedOffset();
|
long version = image.version();
|
||||||
Map<String, ResolvedRegularExpression> result = new HashMap<>(resolvedRegexes.size());
|
Map<String, ResolvedRegularExpression> result = new HashMap<>(resolvedRegexes.size());
|
||||||
for (Map.Entry<String, Set<String>> resolvedRegex : resolvedRegexes.entrySet()) {
|
for (Map.Entry<String, Set<String>> resolvedRegex : resolvedRegexes.entrySet()) {
|
||||||
result.put(
|
result.put(
|
||||||
|
@ -3259,7 +3258,7 @@ public class GroupMetadataManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("[GroupId {}] Scanned {} topics to refresh regular expressions {} in {}ms.",
|
log.info("[GroupId {}] Scanned {} topics to refresh regular expressions {} in {}ms.",
|
||||||
groupId, image.topics().topicsByName().size(), resolvedRegexes.keySet(),
|
groupId, image.topicNames().size(), resolvedRegexes.keySet(),
|
||||||
time.milliseconds() - startTimeMs);
|
time.milliseconds() - startTimeMs);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -3867,7 +3866,7 @@ public class GroupMetadataManager {
|
||||||
int groupEpoch,
|
int groupEpoch,
|
||||||
StreamsGroupMember updatedMember,
|
StreamsGroupMember updatedMember,
|
||||||
ConfiguredTopology configuredTopology,
|
ConfiguredTopology configuredTopology,
|
||||||
MetadataImage metadataImage,
|
CoordinatorMetadataImage metadataImage,
|
||||||
List<CoordinatorRecord> records
|
List<CoordinatorRecord> records
|
||||||
) {
|
) {
|
||||||
TaskAssignor assignor = streamsGroupAssignor(group.groupId());
|
TaskAssignor assignor = streamsGroupAssignor(group.groupId());
|
||||||
|
@ -4925,24 +4924,20 @@ public class GroupMetadataManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Uuid, String> attachTopicName(Set<Uuid> topicIds) {
|
private Map<Uuid, String> attachTopicName(Set<Uuid> topicIds) {
|
||||||
TopicsImage topicsImage = metadataImage.topics();
|
|
||||||
Map<Uuid, String> finalMap = new HashMap<>();
|
Map<Uuid, String> finalMap = new HashMap<>();
|
||||||
for (Uuid topicId : topicIds) {
|
for (Uuid topicId : topicIds) {
|
||||||
TopicImage topicImage = topicsImage.getTopic(topicId);
|
String topicName = metadataImage.topicMetadata(topicId).map(CoordinatorMetadataImage.TopicMetadata::name).orElse("<UNKNOWN>");
|
||||||
String topicName = (topicImage != null) ? topicImage.name() : "<UNKNOWN>";
|
|
||||||
finalMap.put(topicId, topicName);
|
finalMap.put(topicId, topicName);
|
||||||
}
|
}
|
||||||
return Collections.unmodifiableMap(finalMap);
|
return Collections.unmodifiableMap(finalMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Uuid, InitMapValue> attachInitValue(Map<Uuid, Set<Integer>> initMap) {
|
private Map<Uuid, InitMapValue> attachInitValue(Map<Uuid, Set<Integer>> initMap) {
|
||||||
TopicsImage topicsImage = metadataImage.topics();
|
|
||||||
Map<Uuid, InitMapValue> finalMap = new HashMap<>();
|
Map<Uuid, InitMapValue> finalMap = new HashMap<>();
|
||||||
long timestamp = time.milliseconds();
|
long timestamp = time.milliseconds();
|
||||||
for (Map.Entry<Uuid, Set<Integer>> entry : initMap.entrySet()) {
|
for (Map.Entry<Uuid, Set<Integer>> entry : initMap.entrySet()) {
|
||||||
Uuid topicId = entry.getKey();
|
Uuid topicId = entry.getKey();
|
||||||
TopicImage topicImage = topicsImage.getTopic(topicId);
|
String topicName = metadataImage.topicMetadata(topicId).map(CoordinatorMetadataImage.TopicMetadata::name).orElse("<UNKNOWN>");
|
||||||
String topicName = (topicImage != null) ? topicImage.name() : "<UNKNOWN>";
|
|
||||||
finalMap.put(topicId, new InitMapValue(topicName, entry.getValue(), timestamp));
|
finalMap.put(topicId, new InitMapValue(topicName, entry.getValue(), timestamp));
|
||||||
}
|
}
|
||||||
return Collections.unmodifiableMap(finalMap);
|
return Collections.unmodifiableMap(finalMap);
|
||||||
|
@ -5774,41 +5769,37 @@ public class GroupMetadataManager {
|
||||||
* @param newImage The new metadata image.
|
* @param newImage The new metadata image.
|
||||||
* @param delta The delta image.
|
* @param delta The delta image.
|
||||||
*/
|
*/
|
||||||
public void onNewMetadataImage(MetadataImage newImage, MetadataDelta delta) {
|
public void onNewMetadataImage(CoordinatorMetadataImage newImage, CoordinatorMetadataDelta delta) {
|
||||||
metadataImage = newImage;
|
metadataImage = newImage;
|
||||||
|
|
||||||
// Initialize the last offset if it was not yet.
|
// Initialize the last version if it was not yet.
|
||||||
if (lastMetadataImageWithNewTopics == -1L) {
|
if (lastMetadataImageWithNewTopics == -1L) {
|
||||||
lastMetadataImageWithNewTopics = metadataImage.provenance().lastContainedOffset();
|
lastMetadataImageWithNewTopics = metadataImage.version();
|
||||||
}
|
}
|
||||||
|
|
||||||
TopicsDelta topicsDelta = delta.topicsDelta();
|
// Updated the last version of the image with newly created topics. This is used to
|
||||||
if (topicsDelta == null) return;
|
|
||||||
|
|
||||||
// Updated the last offset of the image with newly created topics. This is used to
|
|
||||||
// trigger a refresh of all the regular expressions when topics are created. Note
|
// trigger a refresh of all the regular expressions when topics are created. Note
|
||||||
// that we don't trigger a refresh when topics are deleted. Those are removed from
|
// that we don't trigger a refresh when topics are deleted. Those are removed from
|
||||||
// the subscription metadata (and the assignment) via the above mechanism. The
|
// the subscription metadata (and the assignment) via the above mechanism. The
|
||||||
// resolved regular expressions are cleaned up on the next refresh.
|
// resolved regular expressions are cleaned up on the next refresh.
|
||||||
if (!topicsDelta.createdTopicIds().isEmpty()) {
|
if (!delta.createdTopicIds().isEmpty()) {
|
||||||
lastMetadataImageWithNewTopics = metadataImage.provenance().lastContainedOffset();
|
lastMetadataImageWithNewTopics = metadataImage.version();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify all the groups subscribed to the created, updated or
|
// Notify all the groups subscribed to the created, updated or
|
||||||
// deleted topics.
|
// deleted topics.
|
||||||
Set<String> allGroupIds = new HashSet<>();
|
Set<String> allGroupIds = new HashSet<>();
|
||||||
topicsDelta.changedTopics().forEach((topicId, topicDelta) -> {
|
delta.changedTopicIds().forEach(topicId ->
|
||||||
String topicName = topicDelta.name();
|
metadataImage.topicMetadata(topicId).ifPresent(topicMetadata -> {
|
||||||
// Remove topic hash from the cache to recalculate it.
|
// Remove topic hash from the cache to recalculate it.
|
||||||
topicHashCache.remove(topicName);
|
topicHashCache.remove(topicMetadata.name());
|
||||||
allGroupIds.addAll(groupsSubscribedToTopic(topicName));
|
allGroupIds.addAll(groupsSubscribedToTopic(topicMetadata.name()));
|
||||||
});
|
}));
|
||||||
topicsDelta.deletedTopicIds().forEach(topicId -> {
|
delta.deletedTopicIds().forEach(topicId ->
|
||||||
TopicImage topicImage = delta.image().topics().getTopic(topicId);
|
delta.image().topicMetadata(topicId).ifPresent(topicMetadata -> {
|
||||||
String topicName = topicImage.name();
|
topicHashCache.remove(topicMetadata.name());
|
||||||
topicHashCache.remove(topicName);
|
allGroupIds.addAll(groupsSubscribedToTopic(topicMetadata.name()));
|
||||||
allGroupIds.addAll(groupsSubscribedToTopic(topicName));
|
}));
|
||||||
});
|
|
||||||
allGroupIds.forEach(groupId -> {
|
allGroupIds.forEach(groupId -> {
|
||||||
Group group = groups.get(groupId);
|
Group group = groups.get(groupId);
|
||||||
if (group != null) {
|
if (group != null) {
|
||||||
|
@ -7480,7 +7471,7 @@ public class GroupMetadataManager {
|
||||||
return ConsumerProtocol.serializeAssignment(
|
return ConsumerProtocol.serializeAssignment(
|
||||||
toConsumerProtocolAssignment(
|
toConsumerProtocolAssignment(
|
||||||
member.assignedPartitions(),
|
member.assignedPartitions(),
|
||||||
metadataImage.topics()
|
metadataImage
|
||||||
),
|
),
|
||||||
ConsumerProtocol.deserializeVersion(
|
ConsumerProtocol.deserializeVersion(
|
||||||
ByteBuffer.wrap(member.classicMemberMetadata().get().supportedProtocols().iterator().next().metadata())
|
ByteBuffer.wrap(member.classicMemberMetadata().get().supportedProtocols().iterator().next().metadata())
|
||||||
|
@ -8041,20 +8032,23 @@ public class GroupMetadataManager {
|
||||||
// a retry for the same is possible. Since this is part of an admin operation
|
// a retry for the same is possible. Since this is part of an admin operation
|
||||||
// retrying delete should not pose issues related to
|
// retrying delete should not pose issues related to
|
||||||
// performance. Also, the share coordinator is idempotent on delete partitions.
|
// performance. Also, the share coordinator is idempotent on delete partitions.
|
||||||
|
|
||||||
Set<Uuid> currentDeleting = shareGroupStatePartitionMetadata.get(shareGroupId).deletingTopics();
|
Set<Uuid> currentDeleting = shareGroupStatePartitionMetadata.get(shareGroupId).deletingTopics();
|
||||||
Map<Uuid, InitMapValue> deleteRetryCandidates = new HashMap<>();
|
Map<Uuid, InitMapValue> deleteRetryCandidates = new HashMap<>();
|
||||||
Set<Uuid> deletingToIgnore = new HashSet<>();
|
Set<Uuid> deletingToIgnore = new HashSet<>();
|
||||||
if (!currentDeleting.isEmpty()) {
|
if (!currentDeleting.isEmpty()) {
|
||||||
if (metadataImage == null || metadataImage.equals(MetadataImage.EMPTY)) {
|
if (metadataImage == null || metadataImage.equals(CoordinatorMetadataImage.EMPTY)) {
|
||||||
deletingToIgnore.addAll(currentDeleting);
|
deletingToIgnore.addAll(currentDeleting);
|
||||||
} else {
|
} else {
|
||||||
for (Uuid deletingTopicId : currentDeleting) {
|
for (Uuid deletingTopicId : currentDeleting) {
|
||||||
TopicImage topicImage = metadataImage.topics().getTopic(deletingTopicId);
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadataOp = metadataImage.topicMetadata(deletingTopicId);
|
||||||
if (topicImage == null) {
|
if (topicMetadataOp.isEmpty()) {
|
||||||
deletingToIgnore.add(deletingTopicId);
|
deletingToIgnore.add(deletingTopicId);
|
||||||
} else {
|
} else {
|
||||||
deleteRetryCandidates.put(deletingTopicId, new InitMapValue(topicImage.name(), topicImage.partitions().keySet(), -1));
|
deleteRetryCandidates.put(deletingTopicId,
|
||||||
|
new InitMapValue(
|
||||||
|
topicMetadataOp.get().name(),
|
||||||
|
IntStream.range(0, topicMetadataOp.get().partitionCount()).boxed().collect(Collectors.toSet()),
|
||||||
|
-1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8135,9 +8129,10 @@ public class GroupMetadataManager {
|
||||||
Set<Uuid> deletingTopics = new HashSet<>(currentMap.deletingTopics());
|
Set<Uuid> deletingTopics = new HashSet<>(currentMap.deletingTopics());
|
||||||
|
|
||||||
requestData.topics().forEach(topic -> {
|
requestData.topics().forEach(topic -> {
|
||||||
TopicImage topicImage = metadataImage.topics().getTopic(topic.topicName());
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadataOpt = metadataImage.topicMetadata(topic.topicName());
|
||||||
if (topicImage != null) {
|
if (topicMetadataOpt.isPresent()) {
|
||||||
Uuid topicId = topicImage.id();
|
var topicMetadata = topicMetadataOpt.get();
|
||||||
|
Uuid topicId = topicMetadata.id();
|
||||||
// A deleteState request to persister should only be sent with those topic partitions for which corresponding
|
// A deleteState request to persister should only be sent with those topic partitions for which corresponding
|
||||||
// share partitions are initialized for the group.
|
// share partitions are initialized for the group.
|
||||||
if (initializedTopics.containsKey(topicId)) {
|
if (initializedTopics.containsKey(topicId)) {
|
||||||
|
@ -8157,7 +8152,7 @@ public class GroupMetadataManager {
|
||||||
// If the topic for which delete share group offsets request is sent is already present in the deletingTopics set,
|
// If the topic for which delete share group offsets request is sent is already present in the deletingTopics set,
|
||||||
// we will include that topic in the delete share group state request.
|
// we will include that topic in the delete share group state request.
|
||||||
List<DeleteShareGroupStateRequestData.PartitionData> partitions = new ArrayList<>();
|
List<DeleteShareGroupStateRequestData.PartitionData> partitions = new ArrayList<>();
|
||||||
topicImage.partitions().keySet().forEach(partition ->
|
IntStream.range(0, topicMetadata.partitionCount()).forEach(partition ->
|
||||||
partitions.add(new DeleteShareGroupStateRequestData.PartitionData().setPartition(partition)));
|
partitions.add(new DeleteShareGroupStateRequestData.PartitionData().setPartition(partition)));
|
||||||
deleteShareGroupStateRequestTopicsData.add(
|
deleteShareGroupStateRequestTopicsData.add(
|
||||||
new DeleteShareGroupStateRequestData.DeleteStateData()
|
new DeleteShareGroupStateRequestData.DeleteStateData()
|
||||||
|
@ -8205,13 +8200,13 @@ public class GroupMetadataManager {
|
||||||
Map<Uuid, Map<Integer, Long>> offsetByTopicPartitions = new HashMap<>();
|
Map<Uuid, Map<Integer, Long>> offsetByTopicPartitions = new HashMap<>();
|
||||||
|
|
||||||
alterShareGroupOffsetsRequest.topics().forEach(topic -> {
|
alterShareGroupOffsetsRequest.topics().forEach(topic -> {
|
||||||
TopicImage topicImage = metadataImage.topics().getTopic(topic.topicName());
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadataOpt = metadataImage.topicMetadata(topic.topicName());
|
||||||
if (topicImage != null) {
|
if (topicMetadataOpt.isPresent()) {
|
||||||
Uuid topicId = topicImage.id();
|
var topicMetadata = topicMetadataOpt.get();
|
||||||
Set<Integer> existingPartitions = new HashSet<>(topicImage.partitions().keySet());
|
Uuid topicId = topicMetadata.id();
|
||||||
List<AlterShareGroupOffsetsResponseData.AlterShareGroupOffsetsResponsePartition> partitions = new ArrayList<>();
|
List<AlterShareGroupOffsetsResponseData.AlterShareGroupOffsetsResponsePartition> partitions = new ArrayList<>();
|
||||||
topic.partitions().forEach(partition -> {
|
topic.partitions().forEach(partition -> {
|
||||||
if (existingPartitions.contains(partition.partitionIndex())) {
|
if (partition.partitionIndex() < topicMetadata.partitionCount()) {
|
||||||
partitions.add(
|
partitions.add(
|
||||||
new AlterShareGroupOffsetsResponseData.AlterShareGroupOffsetsResponsePartition()
|
new AlterShareGroupOffsetsResponseData.AlterShareGroupOffsetsResponsePartition()
|
||||||
.setPartitionIndex(partition.partitionIndex())
|
.setPartitionIndex(partition.partitionIndex())
|
||||||
|
@ -8230,7 +8225,7 @@ public class GroupMetadataManager {
|
||||||
topic.topicName(),
|
topic.topicName(),
|
||||||
topic.partitions().stream()
|
topic.partitions().stream()
|
||||||
.map(AlterShareGroupOffsetsRequestData.AlterShareGroupOffsetsRequestPartition::partitionIndex)
|
.map(AlterShareGroupOffsetsRequestData.AlterShareGroupOffsetsRequestPartition::partitionIndex)
|
||||||
.filter(existingPartitions::contains)
|
.filter(part -> part < topicMetadata.partitionCount())
|
||||||
.collect(Collectors.toSet()),
|
.collect(Collectors.toSet()),
|
||||||
currentTimeMs
|
currentTimeMs
|
||||||
));
|
));
|
||||||
|
|
|
@ -23,13 +23,9 @@ import org.apache.kafka.common.message.ConsumerGroupHeartbeatRequestData;
|
||||||
import org.apache.kafka.common.message.ConsumerProtocolAssignment;
|
import org.apache.kafka.common.message.ConsumerProtocolAssignment;
|
||||||
import org.apache.kafka.common.message.ConsumerProtocolSubscription;
|
import org.apache.kafka.common.message.ConsumerProtocolSubscription;
|
||||||
import org.apache.kafka.common.protocol.ApiMessage;
|
import org.apache.kafka.common.protocol.ApiMessage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.generated.ConsumerGroupCurrentMemberAssignmentValue;
|
import org.apache.kafka.coordinator.group.generated.ConsumerGroupCurrentMemberAssignmentValue;
|
||||||
import org.apache.kafka.coordinator.group.generated.ShareGroupCurrentMemberAssignmentValue;
|
import org.apache.kafka.coordinator.group.generated.ShareGroupCurrentMemberAssignmentValue;
|
||||||
import org.apache.kafka.image.ClusterImage;
|
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.image.TopicImage;
|
|
||||||
import org.apache.kafka.image.TopicsImage;
|
|
||||||
import org.apache.kafka.metadata.BrokerRegistration;
|
|
||||||
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
||||||
|
|
||||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||||
|
@ -141,22 +137,20 @@ public class Utils {
|
||||||
* Converts a map of topic id and partition set to a ConsumerProtocolAssignment.
|
* Converts a map of topic id and partition set to a ConsumerProtocolAssignment.
|
||||||
*
|
*
|
||||||
* @param assignment The map to convert.
|
* @param assignment The map to convert.
|
||||||
* @param topicsImage The TopicsImage.
|
* @param image The CoordinatorMetadataImage.
|
||||||
* @return The converted ConsumerProtocolAssignment.
|
* @return The converted ConsumerProtocolAssignment.
|
||||||
*/
|
*/
|
||||||
public static ConsumerProtocolAssignment toConsumerProtocolAssignment(
|
public static ConsumerProtocolAssignment toConsumerProtocolAssignment(
|
||||||
Map<Uuid, Set<Integer>> assignment,
|
Map<Uuid, Set<Integer>> assignment,
|
||||||
TopicsImage topicsImage
|
CoordinatorMetadataImage image
|
||||||
) {
|
) {
|
||||||
ConsumerProtocolAssignment.TopicPartitionCollection collection =
|
ConsumerProtocolAssignment.TopicPartitionCollection collection =
|
||||||
new ConsumerProtocolAssignment.TopicPartitionCollection();
|
new ConsumerProtocolAssignment.TopicPartitionCollection();
|
||||||
assignment.forEach((topicId, partitions) -> {
|
assignment.forEach((topicId, partitions) -> {
|
||||||
TopicImage topicImage = topicsImage.getTopic(topicId);
|
image.topicMetadata(topicId).ifPresent(topicMetadata ->
|
||||||
if (topicImage != null) {
|
|
||||||
collection.add(new ConsumerProtocolAssignment.TopicPartition()
|
collection.add(new ConsumerProtocolAssignment.TopicPartition()
|
||||||
.setTopic(topicImage.name())
|
.setTopic(topicMetadata.name())
|
||||||
.setPartitions(new ArrayList<>(partitions)));
|
.setPartitions(new ArrayList<>(partitions))));
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return new ConsumerProtocolAssignment()
|
return new ConsumerProtocolAssignment()
|
||||||
.setAssignedPartitions(collection);
|
.setAssignedPartitions(collection);
|
||||||
|
@ -166,19 +160,18 @@ public class Utils {
|
||||||
* Converts a map of topic id and partition set to a ConsumerProtocolAssignment.
|
* Converts a map of topic id and partition set to a ConsumerProtocolAssignment.
|
||||||
*
|
*
|
||||||
* @param consumerProtocolAssignment The ConsumerProtocolAssignment.
|
* @param consumerProtocolAssignment The ConsumerProtocolAssignment.
|
||||||
* @param topicsImage The TopicsImage.
|
* @param metadataImage The Metadata image.
|
||||||
* @return The converted map.
|
* @return The converted map.
|
||||||
*/
|
*/
|
||||||
public static Map<Uuid, Set<Integer>> toTopicPartitionMap(
|
public static Map<Uuid, Set<Integer>> toTopicPartitionMap(
|
||||||
ConsumerProtocolAssignment consumerProtocolAssignment,
|
ConsumerProtocolAssignment consumerProtocolAssignment,
|
||||||
TopicsImage topicsImage
|
CoordinatorMetadataImage metadataImage
|
||||||
) {
|
) {
|
||||||
Map<Uuid, Set<Integer>> topicPartitionMap = new HashMap<>();
|
Map<Uuid, Set<Integer>> topicPartitionMap = new HashMap<>();
|
||||||
consumerProtocolAssignment.assignedPartitions().forEach(topicPartition -> {
|
consumerProtocolAssignment.assignedPartitions().forEach(topicPartition -> {
|
||||||
TopicImage topicImage = topicsImage.getTopic(topicPartition.topic());
|
metadataImage.topicMetadata(topicPartition.topic()).ifPresent(topicMetadata -> {
|
||||||
if (topicImage != null) {
|
topicPartitionMap.put(topicMetadata.id(), new HashSet<>(topicPartition.partitions()));
|
||||||
topicPartitionMap.put(topicImage.id(), new HashSet<>(topicPartition.partitions()));
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return topicPartitionMap;
|
return topicPartitionMap;
|
||||||
}
|
}
|
||||||
|
@ -187,23 +180,22 @@ public class Utils {
|
||||||
* Converts a ConsumerProtocolSubscription.TopicPartitionCollection to a list of ConsumerGroupHeartbeatRequestData.TopicPartitions.
|
* Converts a ConsumerProtocolSubscription.TopicPartitionCollection to a list of ConsumerGroupHeartbeatRequestData.TopicPartitions.
|
||||||
*
|
*
|
||||||
* @param topicPartitionCollection The TopicPartitionCollection to convert.
|
* @param topicPartitionCollection The TopicPartitionCollection to convert.
|
||||||
* @param topicsImage The TopicsImage.
|
* @param metadataImage The Metadata image.
|
||||||
* @return a list of ConsumerGroupHeartbeatRequestData.TopicPartitions.
|
* @return a list of ConsumerGroupHeartbeatRequestData.TopicPartitions.
|
||||||
*/
|
*/
|
||||||
public static List<ConsumerGroupHeartbeatRequestData.TopicPartitions> toTopicPartitions(
|
public static List<ConsumerGroupHeartbeatRequestData.TopicPartitions> toTopicPartitions(
|
||||||
ConsumerProtocolSubscription.TopicPartitionCollection topicPartitionCollection,
|
ConsumerProtocolSubscription.TopicPartitionCollection topicPartitionCollection,
|
||||||
TopicsImage topicsImage
|
CoordinatorMetadataImage metadataImage
|
||||||
) {
|
) {
|
||||||
List<ConsumerGroupHeartbeatRequestData.TopicPartitions> res = new ArrayList<>();
|
List<ConsumerGroupHeartbeatRequestData.TopicPartitions> res = new ArrayList<>();
|
||||||
for (ConsumerProtocolSubscription.TopicPartition tp : topicPartitionCollection) {
|
for (ConsumerProtocolSubscription.TopicPartition tp : topicPartitionCollection) {
|
||||||
TopicImage topicImage = topicsImage.getTopic(tp.topic());
|
metadataImage.topicMetadata(tp.topic()).ifPresent(topicMetadata -> {
|
||||||
if (topicImage != null) {
|
|
||||||
res.add(
|
res.add(
|
||||||
new ConsumerGroupHeartbeatRequestData.TopicPartitions()
|
new ConsumerGroupHeartbeatRequestData.TopicPartitions()
|
||||||
.setTopicId(topicImage.id())
|
.setTopicId(topicMetadata.id())
|
||||||
.setPartitions(tp.partitions())
|
.setPartitions(tp.partitions())
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -398,38 +390,32 @@ public class Utils {
|
||||||
* 5. For each partition, write the partition ID and a sorted list of rack identifiers.
|
* 5. For each partition, write the partition ID and a sorted list of rack identifiers.
|
||||||
* - Rack identifiers are formatted as "<length1><value1><length2><value2>" to prevent issues with simple separators.
|
* - Rack identifiers are formatted as "<length1><value1><length2><value2>" to prevent issues with simple separators.
|
||||||
*
|
*
|
||||||
* @param topicName The topic image.
|
* @param topicName The topic name.
|
||||||
* @param metadataImage The cluster image.
|
* @param metadataImage The topic metadata.
|
||||||
* @return The hash of the topic.
|
* @return The hash of the topic.
|
||||||
*/
|
*/
|
||||||
public static long computeTopicHash(String topicName, MetadataImage metadataImage) {
|
public static long computeTopicHash(String topicName, CoordinatorMetadataImage metadataImage) {
|
||||||
TopicImage topicImage = metadataImage.topics().getTopic(topicName);
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicImage = metadataImage.topicMetadata(topicName);
|
||||||
if (topicImage == null) {
|
if (topicImage.isEmpty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CoordinatorMetadataImage.TopicMetadata topicMetadata = topicImage.get();
|
||||||
|
|
||||||
HashStream64 hasher = Hashing.xxh3_64().hashStream();
|
HashStream64 hasher = Hashing.xxh3_64().hashStream();
|
||||||
hasher = hasher
|
hasher = hasher
|
||||||
.putByte(TOPIC_HASH_MAGIC_BYTE)
|
.putByte(TOPIC_HASH_MAGIC_BYTE)
|
||||||
.putLong(topicImage.id().getMostSignificantBits())
|
.putLong(topicMetadata.id().getMostSignificantBits())
|
||||||
.putLong(topicImage.id().getLeastSignificantBits())
|
.putLong(topicMetadata.id().getLeastSignificantBits())
|
||||||
.putString(topicImage.name())
|
.putString(topicMetadata.name())
|
||||||
.putInt(topicImage.partitions().size());
|
.putInt(topicMetadata.partitionCount());
|
||||||
|
|
||||||
ClusterImage clusterImage = metadataImage.cluster();
|
for (int i = 0; i < topicMetadata.partitionCount(); i++) {
|
||||||
List<String> racks = new ArrayList<>();
|
|
||||||
for (int i = 0; i < topicImage.partitions().size(); i++) {
|
|
||||||
hasher = hasher.putInt(i);
|
hasher = hasher.putInt(i);
|
||||||
racks.clear(); // Clear the list for reuse
|
List<String> partitionRacks = topicMetadata.partitionRacks(i);
|
||||||
for (int replicaId : topicImage.partitions().get(i).replicas) {
|
Collections.sort(partitionRacks);
|
||||||
BrokerRegistration broker = clusterImage.broker(replicaId);
|
|
||||||
if (broker != null) {
|
|
||||||
broker.rack().ifPresent(racks::add);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Collections.sort(racks);
|
for (String rack : partitionRacks) {
|
||||||
for (String rack : racks) {
|
|
||||||
// Format: "<length><value>"
|
// Format: "<length><value>"
|
||||||
// The rack string combination cannot use simple separator like ",", because there is no limitation for rack character.
|
// The rack string combination cannot use simple separator like ",", because there is no limitation for rack character.
|
||||||
// If using simple separator like "," it may hit edge case like ",," and ",,," / ",,," and ",,".
|
// If using simple separator like "," it may hit edge case like ",," and ",,," / ",,," and ",,".
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.apache.kafka.common.protocol.types.SchemaException;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.Time;
|
import org.apache.kafka.common.utils.Time;
|
||||||
import org.apache.kafka.common.utils.Utils;
|
import org.apache.kafka.common.utils.Utils;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.group.Group;
|
import org.apache.kafka.coordinator.group.Group;
|
||||||
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
||||||
|
@ -40,7 +41,6 @@ import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
||||||
import org.apache.kafka.coordinator.group.OffsetExpirationConditionImpl;
|
import org.apache.kafka.coordinator.group.OffsetExpirationConditionImpl;
|
||||||
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroup;
|
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroup;
|
||||||
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroupMember;
|
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroupMember;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
@ -1349,7 +1349,7 @@ public class ClassicGroup implements Group {
|
||||||
* When not null, must have an instanceId that matches an existing member.
|
* When not null, must have an instanceId that matches an existing member.
|
||||||
* @param logContext The logContext to create the ClassicGroup.
|
* @param logContext The logContext to create the ClassicGroup.
|
||||||
* @param time The time to create the ClassicGroup.
|
* @param time The time to create the ClassicGroup.
|
||||||
* @param metadataImage The MetadataImage.
|
* @param image The MetadataImage.
|
||||||
* @return The created ClassicGroup.
|
* @return The created ClassicGroup.
|
||||||
*/
|
*/
|
||||||
public static ClassicGroup fromConsumerGroup(
|
public static ClassicGroup fromConsumerGroup(
|
||||||
|
@ -1358,7 +1358,7 @@ public class ClassicGroup implements Group {
|
||||||
ConsumerGroupMember joiningMember,
|
ConsumerGroupMember joiningMember,
|
||||||
LogContext logContext,
|
LogContext logContext,
|
||||||
Time time,
|
Time time,
|
||||||
MetadataImage metadataImage
|
CoordinatorMetadataImage image
|
||||||
) {
|
) {
|
||||||
ClassicGroup classicGroup = new ClassicGroup(
|
ClassicGroup classicGroup = new ClassicGroup(
|
||||||
logContext,
|
logContext,
|
||||||
|
@ -1427,7 +1427,7 @@ public class ClassicGroup implements Group {
|
||||||
byte[] assignment = Utils.toArray(ConsumerProtocol.serializeAssignment(
|
byte[] assignment = Utils.toArray(ConsumerProtocol.serializeAssignment(
|
||||||
toConsumerProtocolAssignment(
|
toConsumerProtocolAssignment(
|
||||||
consumerGroup.targetAssignment().get(memberId).partitions(),
|
consumerGroup.targetAssignment().get(memberId).partitions(),
|
||||||
metadataImage.topics()
|
image
|
||||||
),
|
),
|
||||||
ConsumerProtocol.deserializeVersion(
|
ConsumerProtocol.deserializeVersion(
|
||||||
ByteBuffer.wrap(classicGroupMember.metadata(classicGroup.protocolName().orElse("")))
|
ByteBuffer.wrap(classicGroupMember.metadata(classicGroup.protocolName().orElse("")))
|
||||||
|
|
|
@ -19,11 +19,10 @@ package org.apache.kafka.coordinator.group.modern;
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.common.errors.UnknownMemberIdException;
|
import org.apache.kafka.common.errors.UnknownMemberIdException;
|
||||||
import org.apache.kafka.common.message.ListGroupsResponseData;
|
import org.apache.kafka.common.message.ListGroupsResponseData;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.Group;
|
import org.apache.kafka.coordinator.group.Group;
|
||||||
import org.apache.kafka.coordinator.group.Utils;
|
import org.apache.kafka.coordinator.group.Utils;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.SubscriptionType;
|
import org.apache.kafka.coordinator.group.api.assignor.SubscriptionType;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.image.TopicImage;
|
|
||||||
import org.apache.kafka.timeline.SnapshotRegistry;
|
import org.apache.kafka.timeline.SnapshotRegistry;
|
||||||
import org.apache.kafka.timeline.TimelineHashMap;
|
import org.apache.kafka.timeline.TimelineHashMap;
|
||||||
import org.apache.kafka.timeline.TimelineInteger;
|
import org.apache.kafka.timeline.TimelineInteger;
|
||||||
|
@ -36,6 +35,7 @@ import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.apache.kafka.coordinator.group.api.assignor.SubscriptionType.HETEROGENEOUS;
|
import static org.apache.kafka.coordinator.group.api.assignor.SubscriptionType.HETEROGENEOUS;
|
||||||
import static org.apache.kafka.coordinator.group.api.assignor.SubscriptionType.HOMOGENEOUS;
|
import static org.apache.kafka.coordinator.group.api.assignor.SubscriptionType.HOMOGENEOUS;
|
||||||
|
@ -367,18 +367,13 @@ public abstract class ModernGroup<T extends ModernGroupMember> implements Group
|
||||||
public static long computeMetadataHash(
|
public static long computeMetadataHash(
|
||||||
Map<String, SubscriptionCount> subscribedTopicNames,
|
Map<String, SubscriptionCount> subscribedTopicNames,
|
||||||
Map<String, Long> topicHashCache,
|
Map<String, Long> topicHashCache,
|
||||||
MetadataImage metadataImage
|
CoordinatorMetadataImage metadataImage
|
||||||
) {
|
) {
|
||||||
Map<String, Long> topicHash = new HashMap<>(subscribedTopicNames.size());
|
Map<String, Long> topicHash = subscribedTopicNames.keySet().stream()
|
||||||
subscribedTopicNames.keySet().forEach(topicName -> {
|
.filter(topicName -> metadataImage.topicMetadata(topicName).isPresent())
|
||||||
TopicImage topicImage = metadataImage.topics().getTopic(topicName);
|
.collect(Collectors.toMap(
|
||||||
if (topicImage != null) {
|
topicName -> topicName,
|
||||||
topicHash.put(
|
topicName -> topicHashCache.computeIfAbsent(topicName, k -> Utils.computeTopicHash(k, metadataImage))));
|
||||||
topicName,
|
|
||||||
topicHashCache.computeIfAbsent(topicName, k -> Utils.computeTopicHash(topicName, metadataImage))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Utils.computeGroupHash(topicHash);
|
return Utils.computeGroupHash(topicHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,16 +17,14 @@
|
||||||
package org.apache.kafka.coordinator.group.modern;
|
package org.apache.kafka.coordinator.group.modern;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.PartitionAssignor;
|
import org.apache.kafka.coordinator.group.api.assignor.PartitionAssignor;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.SubscribedTopicDescriber;
|
import org.apache.kafka.coordinator.group.api.assignor.SubscribedTopicDescriber;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.image.TopicImage;
|
|
||||||
import org.apache.kafka.metadata.BrokerRegistration;
|
|
||||||
import org.apache.kafka.metadata.PartitionRegistration;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,9 +35,9 @@ public class SubscribedTopicDescriberImpl implements SubscribedTopicDescriber {
|
||||||
/**
|
/**
|
||||||
* The metadata image that contains the latest metadata information.
|
* The metadata image that contains the latest metadata information.
|
||||||
*/
|
*/
|
||||||
private final MetadataImage metadataImage;
|
private final CoordinatorMetadataImage metadataImage;
|
||||||
|
|
||||||
public SubscribedTopicDescriberImpl(MetadataImage metadataImage) {
|
public SubscribedTopicDescriberImpl(CoordinatorMetadataImage metadataImage) {
|
||||||
this.metadataImage = Objects.requireNonNull(metadataImage);
|
this.metadataImage = Objects.requireNonNull(metadataImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +50,7 @@ public class SubscribedTopicDescriberImpl implements SubscribedTopicDescriber {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int numPartitions(Uuid topicId) {
|
public int numPartitions(Uuid topicId) {
|
||||||
TopicImage topicImage = this.metadataImage.topics().getTopic(topicId);
|
return this.metadataImage.topicMetadata(topicId).map(CoordinatorMetadataImage.TopicMetadata::partitionCount).orElse(-1);
|
||||||
return topicImage == null ? -1 : topicImage.partitions().size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,24 +63,20 @@ public class SubscribedTopicDescriberImpl implements SubscribedTopicDescriber {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<String> racksForPartition(Uuid topicId, int partition) {
|
public Set<String> racksForPartition(Uuid topicId, int partition) {
|
||||||
TopicImage topic = metadataImage.topics().getTopic(topicId);
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadataOp = metadataImage.topicMetadata(topicId);
|
||||||
if (topic != null) {
|
if (topicMetadataOp.isEmpty()) {
|
||||||
PartitionRegistration partitionRegistration = topic.partitions().get(partition);
|
|
||||||
if (partitionRegistration != null) {
|
|
||||||
Set<String> racks = new HashSet<>();
|
|
||||||
for (int replica : partitionRegistration.replicas) {
|
|
||||||
// Only add the rack if it is available for the broker/replica.
|
|
||||||
BrokerRegistration brokerRegistration = metadataImage.cluster().broker(replica);
|
|
||||||
if (brokerRegistration != null) {
|
|
||||||
brokerRegistration.rack().ifPresent(racks::add);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableSet(racks);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Set.of();
|
return Set.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CoordinatorMetadataImage.TopicMetadata topicMetadata = topicMetadataOp.get();
|
||||||
|
List<String> racks = topicMetadata.partitionRacks(partition);
|
||||||
|
if (racks == null) {
|
||||||
|
return Set.of();
|
||||||
|
} else {
|
||||||
|
return new HashSet<>(racks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.apache.kafka.coordinator.group.modern;
|
package org.apache.kafka.coordinator.group.modern;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
||||||
|
@ -27,7 +28,6 @@ import org.apache.kafka.coordinator.group.api.assignor.SubscriptionType;
|
||||||
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroupMember;
|
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroupMember;
|
||||||
import org.apache.kafka.coordinator.group.modern.consumer.ResolvedRegularExpression;
|
import org.apache.kafka.coordinator.group.modern.consumer.ResolvedRegularExpression;
|
||||||
import org.apache.kafka.coordinator.group.modern.share.ShareGroupMember;
|
import org.apache.kafka.coordinator.group.modern.share.ShareGroupMember;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -269,7 +269,7 @@ public abstract class TargetAssignmentBuilder<T extends ModernGroupMember, U ext
|
||||||
/**
|
/**
|
||||||
* The metadata image.
|
* The metadata image.
|
||||||
*/
|
*/
|
||||||
private MetadataImage metadataImage = MetadataImage.EMPTY;
|
private CoordinatorMetadataImage metadataImage = CoordinatorMetadataImage.EMPTY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The members which have been updated or deleted. Deleted members
|
* The members which have been updated or deleted. Deleted members
|
||||||
|
@ -376,7 +376,7 @@ public abstract class TargetAssignmentBuilder<T extends ModernGroupMember, U ext
|
||||||
* @return This object.
|
* @return This object.
|
||||||
*/
|
*/
|
||||||
public U withMetadataImage(
|
public U withMetadataImage(
|
||||||
MetadataImage metadataImage
|
CoordinatorMetadataImage metadataImage
|
||||||
) {
|
) {
|
||||||
this.metadataImage = metadataImage;
|
this.metadataImage = metadataImage;
|
||||||
return self();
|
return self();
|
||||||
|
@ -427,7 +427,7 @@ public abstract class TargetAssignmentBuilder<T extends ModernGroupMember, U ext
|
||||||
*/
|
*/
|
||||||
public TargetAssignmentResult build() throws PartitionAssignorException {
|
public TargetAssignmentResult build() throws PartitionAssignorException {
|
||||||
Map<String, MemberSubscriptionAndAssignmentImpl> memberSpecs = new HashMap<>();
|
Map<String, MemberSubscriptionAndAssignmentImpl> memberSpecs = new HashMap<>();
|
||||||
TopicIds.TopicResolver topicResolver = new TopicIds.CachedTopicResolver(metadataImage.topics());
|
TopicIds.TopicResolver topicResolver = new TopicIds.CachedTopicResolver(metadataImage);
|
||||||
|
|
||||||
// Prepare the member spec for all members.
|
// Prepare the member spec for all members.
|
||||||
members.forEach((memberId, member) ->
|
members.forEach((memberId, member) ->
|
||||||
|
|
|
@ -17,8 +17,7 @@
|
||||||
package org.apache.kafka.coordinator.group.modern;
|
package org.apache.kafka.coordinator.group.modern;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.image.TopicImage;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.image.TopicsImage;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -40,7 +39,7 @@ public class TopicIds implements Set<Uuid> {
|
||||||
/**
|
/**
|
||||||
* @return The TopicsImage used by the resolver.
|
* @return The TopicsImage used by the resolver.
|
||||||
*/
|
*/
|
||||||
TopicsImage image();
|
CoordinatorMetadataImage image();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a topic id to a topic name.
|
* Converts a topic id to a topic name.
|
||||||
|
@ -70,31 +69,27 @@ public class TopicIds implements Set<Uuid> {
|
||||||
* A TopicResolver without any caching.
|
* A TopicResolver without any caching.
|
||||||
*/
|
*/
|
||||||
public static class DefaultTopicResolver implements TopicResolver {
|
public static class DefaultTopicResolver implements TopicResolver {
|
||||||
private final TopicsImage image;
|
private final CoordinatorMetadataImage image;
|
||||||
|
|
||||||
public DefaultTopicResolver(
|
public DefaultTopicResolver(
|
||||||
TopicsImage image
|
CoordinatorMetadataImage image
|
||||||
) {
|
) {
|
||||||
this.image = Objects.requireNonNull(image);
|
this.image = Objects.requireNonNull(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final TopicsImage image() {
|
public final CoordinatorMetadataImage image() {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String name(Uuid id) {
|
public String name(Uuid id) {
|
||||||
TopicImage topic = image.getTopic(id);
|
return image.topicMetadata(id).map(CoordinatorMetadataImage.TopicMetadata::name).orElse(null);
|
||||||
if (topic == null) return null;
|
|
||||||
return topic.name();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Uuid id(String name) {
|
public Uuid id(String name) {
|
||||||
TopicImage topic = image.getTopic(name);
|
return image.topicMetadata(name).map(CoordinatorMetadataImage.TopicMetadata::id).orElse(null);
|
||||||
if (topic == null) return null;
|
|
||||||
return topic.id();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -113,38 +108,30 @@ public class TopicIds implements Set<Uuid> {
|
||||||
* TargetAssignmentBuilder.build() call.
|
* TargetAssignmentBuilder.build() call.
|
||||||
*/
|
*/
|
||||||
public static class CachedTopicResolver implements TopicResolver {
|
public static class CachedTopicResolver implements TopicResolver {
|
||||||
private final TopicsImage image;
|
private final CoordinatorMetadataImage image;
|
||||||
|
|
||||||
private final Map<String, Uuid> topicIds = new HashMap<>();
|
private final Map<String, Uuid> topicIds = new HashMap<>();
|
||||||
private final Map<Uuid, String> topicNames = new HashMap<>();
|
private final Map<Uuid, String> topicNames = new HashMap<>();
|
||||||
|
|
||||||
public CachedTopicResolver(
|
public CachedTopicResolver(
|
||||||
TopicsImage image
|
CoordinatorMetadataImage image
|
||||||
) {
|
) {
|
||||||
this.image = Objects.requireNonNull(image);
|
this.image = Objects.requireNonNull(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final TopicsImage image() {
|
public final CoordinatorMetadataImage image() {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String name(Uuid id) {
|
public String name(Uuid id) {
|
||||||
return topicNames.computeIfAbsent(id, __ -> {
|
return topicNames.computeIfAbsent(id, __ -> image.topicMetadata(id).map(CoordinatorMetadataImage.TopicMetadata::name).orElse(null));
|
||||||
TopicImage topic = image.getTopic(id);
|
|
||||||
if (topic == null) return null;
|
|
||||||
return topic.name();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Uuid id(String name) {
|
public Uuid id(String name) {
|
||||||
return topicIds.computeIfAbsent(name, __ -> {
|
return topicIds.computeIfAbsent(name, __ -> image.topicMetadata(name).map(CoordinatorMetadataImage.TopicMetadata::id).orElse(null));
|
||||||
TopicImage topic = image.getTopic(name);
|
|
||||||
if (topic == null) return null;
|
|
||||||
return topic.id();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -164,7 +151,7 @@ public class TopicIds implements Set<Uuid> {
|
||||||
|
|
||||||
public TopicIds(
|
public TopicIds(
|
||||||
Set<String> topicNames,
|
Set<String> topicNames,
|
||||||
TopicsImage image
|
CoordinatorMetadataImage image
|
||||||
) {
|
) {
|
||||||
this.topicNames = Objects.requireNonNull(topicNames);
|
this.topicNames = Objects.requireNonNull(topicNames);
|
||||||
this.resolver = new DefaultTopicResolver(image);
|
this.resolver = new DefaultTopicResolver(image);
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.kafka.common.message.ConsumerProtocolSubscription;
|
||||||
import org.apache.kafka.common.protocol.Errors;
|
import org.apache.kafka.common.protocol.Errors;
|
||||||
import org.apache.kafka.common.protocol.types.SchemaException;
|
import org.apache.kafka.common.protocol.types.SchemaException;
|
||||||
import org.apache.kafka.common.requests.JoinGroupRequest;
|
import org.apache.kafka.common.requests.JoinGroupRequest;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
||||||
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
||||||
|
@ -43,8 +44,6 @@ import org.apache.kafka.coordinator.group.modern.MemberState;
|
||||||
import org.apache.kafka.coordinator.group.modern.ModernGroup;
|
import org.apache.kafka.coordinator.group.modern.ModernGroup;
|
||||||
import org.apache.kafka.coordinator.group.modern.ModernGroupMember;
|
import org.apache.kafka.coordinator.group.modern.ModernGroupMember;
|
||||||
import org.apache.kafka.coordinator.group.modern.SubscriptionCount;
|
import org.apache.kafka.coordinator.group.modern.SubscriptionCount;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.image.TopicsImage;
|
|
||||||
import org.apache.kafka.timeline.SnapshotRegistry;
|
import org.apache.kafka.timeline.SnapshotRegistry;
|
||||||
import org.apache.kafka.timeline.TimelineHashMap;
|
import org.apache.kafka.timeline.TimelineHashMap;
|
||||||
import org.apache.kafka.timeline.TimelineInteger;
|
import org.apache.kafka.timeline.TimelineInteger;
|
||||||
|
@ -1108,7 +1107,7 @@ public class ConsumerGroup extends ModernGroup<ConsumerGroupMember> {
|
||||||
public ConsumerGroupDescribeResponseData.DescribedGroup asDescribedGroup(
|
public ConsumerGroupDescribeResponseData.DescribedGroup asDescribedGroup(
|
||||||
long committedOffset,
|
long committedOffset,
|
||||||
String defaultAssignor,
|
String defaultAssignor,
|
||||||
TopicsImage topicsImage
|
CoordinatorMetadataImage image
|
||||||
) {
|
) {
|
||||||
ConsumerGroupDescribeResponseData.DescribedGroup describedGroup = new ConsumerGroupDescribeResponseData.DescribedGroup()
|
ConsumerGroupDescribeResponseData.DescribedGroup describedGroup = new ConsumerGroupDescribeResponseData.DescribedGroup()
|
||||||
.setGroupId(groupId)
|
.setGroupId(groupId)
|
||||||
|
@ -1120,7 +1119,7 @@ public class ConsumerGroup extends ModernGroup<ConsumerGroupMember> {
|
||||||
entry -> describedGroup.members().add(
|
entry -> describedGroup.members().add(
|
||||||
entry.getValue().asConsumerGroupDescribeMember(
|
entry.getValue().asConsumerGroupDescribeMember(
|
||||||
targetAssignment.get(entry.getValue().memberId(), committedOffset),
|
targetAssignment.get(entry.getValue().memberId(), committedOffset),
|
||||||
topicsImage
|
image
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -1145,7 +1144,7 @@ public class ConsumerGroup extends ModernGroup<ConsumerGroupMember> {
|
||||||
GroupCoordinatorMetricsShard metrics,
|
GroupCoordinatorMetricsShard metrics,
|
||||||
ClassicGroup classicGroup,
|
ClassicGroup classicGroup,
|
||||||
Map<String, Long> topicHashCache,
|
Map<String, Long> topicHashCache,
|
||||||
MetadataImage metadataImage
|
CoordinatorMetadataImage metadataImage
|
||||||
) {
|
) {
|
||||||
String groupId = classicGroup.groupId();
|
String groupId = classicGroup.groupId();
|
||||||
ConsumerGroup consumerGroup = new ConsumerGroup(snapshotRegistry, groupId, metrics);
|
ConsumerGroup consumerGroup = new ConsumerGroup(snapshotRegistry, groupId, metrics);
|
||||||
|
@ -1165,7 +1164,7 @@ public class ConsumerGroup extends ModernGroup<ConsumerGroupMember> {
|
||||||
if (assignment.userData() != null && assignment.userData().hasRemaining()) {
|
if (assignment.userData() != null && assignment.userData().hasRemaining()) {
|
||||||
throw new UnsupportedVersionException("userData from a custom assignor would be lost");
|
throw new UnsupportedVersionException("userData from a custom assignor would be lost");
|
||||||
}
|
}
|
||||||
assignedPartitions = toTopicPartitionMap(assignment, metadataImage.topics());
|
assignedPartitions = toTopicPartitionMap(assignment, metadataImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every member is guaranteed to have metadata set when it joins,
|
// Every member is guaranteed to have metadata set when it joins,
|
||||||
|
|
|
@ -19,14 +19,13 @@ package org.apache.kafka.coordinator.group.modern.consumer;
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.common.message.ConsumerGroupDescribeResponseData;
|
import org.apache.kafka.common.message.ConsumerGroupDescribeResponseData;
|
||||||
import org.apache.kafka.common.message.JoinGroupRequestData;
|
import org.apache.kafka.common.message.JoinGroupRequestData;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.Utils;
|
import org.apache.kafka.coordinator.group.Utils;
|
||||||
import org.apache.kafka.coordinator.group.generated.ConsumerGroupCurrentMemberAssignmentValue;
|
import org.apache.kafka.coordinator.group.generated.ConsumerGroupCurrentMemberAssignmentValue;
|
||||||
import org.apache.kafka.coordinator.group.generated.ConsumerGroupMemberMetadataValue;
|
import org.apache.kafka.coordinator.group.generated.ConsumerGroupMemberMetadataValue;
|
||||||
import org.apache.kafka.coordinator.group.modern.Assignment;
|
import org.apache.kafka.coordinator.group.modern.Assignment;
|
||||||
import org.apache.kafka.coordinator.group.modern.MemberState;
|
import org.apache.kafka.coordinator.group.modern.MemberState;
|
||||||
import org.apache.kafka.coordinator.group.modern.ModernGroupMember;
|
import org.apache.kafka.coordinator.group.modern.ModernGroupMember;
|
||||||
import org.apache.kafka.image.TopicImage;
|
|
||||||
import org.apache.kafka.image.TopicsImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -385,22 +384,22 @@ public class ConsumerGroupMember extends ModernGroupMember {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param targetAssignment The target assignment of this member in the corresponding group.
|
* @param targetAssignment The target assignment of this member in the corresponding group.
|
||||||
*
|
* @param image
|
||||||
* @return The ConsumerGroupMember mapped as ConsumerGroupDescribeResponseData.Member.
|
* @return The ConsumerGroupMember mapped as ConsumerGroupDescribeResponseData.Member.
|
||||||
*/
|
*/
|
||||||
public ConsumerGroupDescribeResponseData.Member asConsumerGroupDescribeMember(
|
public ConsumerGroupDescribeResponseData.Member asConsumerGroupDescribeMember(
|
||||||
Assignment targetAssignment,
|
Assignment targetAssignment,
|
||||||
TopicsImage topicsImage
|
CoordinatorMetadataImage image
|
||||||
) {
|
) {
|
||||||
return new ConsumerGroupDescribeResponseData.Member()
|
return new ConsumerGroupDescribeResponseData.Member()
|
||||||
.setMemberEpoch(memberEpoch)
|
.setMemberEpoch(memberEpoch)
|
||||||
.setMemberId(memberId)
|
.setMemberId(memberId)
|
||||||
.setAssignment(new ConsumerGroupDescribeResponseData.Assignment()
|
.setAssignment(new ConsumerGroupDescribeResponseData.Assignment()
|
||||||
.setTopicPartitions(topicPartitionsFromMap(assignedPartitions, topicsImage)))
|
.setTopicPartitions(topicPartitionsFromMap(assignedPartitions, image)))
|
||||||
.setTargetAssignment(new ConsumerGroupDescribeResponseData.Assignment()
|
.setTargetAssignment(new ConsumerGroupDescribeResponseData.Assignment()
|
||||||
.setTopicPartitions(topicPartitionsFromMap(
|
.setTopicPartitions(topicPartitionsFromMap(
|
||||||
targetAssignment != null ? targetAssignment.partitions() : Map.of(),
|
targetAssignment != null ? targetAssignment.partitions() : Map.of(),
|
||||||
topicsImage
|
image
|
||||||
)))
|
)))
|
||||||
.setClientHost(clientHost)
|
.setClientHost(clientHost)
|
||||||
.setClientId(clientId)
|
.setClientId(clientId)
|
||||||
|
@ -413,17 +412,14 @@ public class ConsumerGroupMember extends ModernGroupMember {
|
||||||
|
|
||||||
private static List<ConsumerGroupDescribeResponseData.TopicPartitions> topicPartitionsFromMap(
|
private static List<ConsumerGroupDescribeResponseData.TopicPartitions> topicPartitionsFromMap(
|
||||||
Map<Uuid, Set<Integer>> partitions,
|
Map<Uuid, Set<Integer>> partitions,
|
||||||
TopicsImage topicsImage
|
CoordinatorMetadataImage image
|
||||||
) {
|
) {
|
||||||
List<ConsumerGroupDescribeResponseData.TopicPartitions> topicPartitions = new ArrayList<>();
|
List<ConsumerGroupDescribeResponseData.TopicPartitions> topicPartitions = new ArrayList<>();
|
||||||
partitions.forEach((topicId, partitionSet) -> {
|
partitions.forEach((topicId, partitionSet) -> {
|
||||||
TopicImage topicImage = topicsImage.getTopic(topicId);
|
image.topicMetadata(topicId).ifPresent(topicMetadata -> topicPartitions.add(new ConsumerGroupDescribeResponseData.TopicPartitions()
|
||||||
if (topicImage != null) {
|
|
||||||
topicPartitions.add(new ConsumerGroupDescribeResponseData.TopicPartitions()
|
|
||||||
.setTopicId(topicId)
|
.setTopicId(topicId)
|
||||||
.setTopicName(topicImage.name())
|
.setTopicName(topicMetadata.name())
|
||||||
.setPartitions(new ArrayList<>(partitionSet)));
|
.setPartitions(new ArrayList<>(partitionSet))));
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return topicPartitions;
|
return topicPartitions;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,11 @@ import org.apache.kafka.common.errors.GroupIdNotFoundException;
|
||||||
import org.apache.kafka.common.errors.UnknownMemberIdException;
|
import org.apache.kafka.common.errors.UnknownMemberIdException;
|
||||||
import org.apache.kafka.common.message.ShareGroupDescribeResponseData;
|
import org.apache.kafka.common.message.ShareGroupDescribeResponseData;
|
||||||
import org.apache.kafka.common.protocol.Errors;
|
import org.apache.kafka.common.protocol.Errors;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
||||||
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
||||||
import org.apache.kafka.coordinator.group.modern.ModernGroup;
|
import org.apache.kafka.coordinator.group.modern.ModernGroup;
|
||||||
import org.apache.kafka.image.TopicsImage;
|
|
||||||
import org.apache.kafka.timeline.SnapshotRegistry;
|
import org.apache.kafka.timeline.SnapshotRegistry;
|
||||||
import org.apache.kafka.timeline.TimelineObject;
|
import org.apache.kafka.timeline.TimelineObject;
|
||||||
|
|
||||||
|
@ -309,7 +309,7 @@ public class ShareGroup extends ModernGroup<ShareGroupMember> {
|
||||||
public ShareGroupDescribeResponseData.DescribedGroup asDescribedGroup(
|
public ShareGroupDescribeResponseData.DescribedGroup asDescribedGroup(
|
||||||
long committedOffset,
|
long committedOffset,
|
||||||
String defaultAssignor,
|
String defaultAssignor,
|
||||||
TopicsImage topicsImage
|
CoordinatorMetadataImage image
|
||||||
) {
|
) {
|
||||||
ShareGroupDescribeResponseData.DescribedGroup describedGroup = new ShareGroupDescribeResponseData.DescribedGroup()
|
ShareGroupDescribeResponseData.DescribedGroup describedGroup = new ShareGroupDescribeResponseData.DescribedGroup()
|
||||||
.setGroupId(groupId)
|
.setGroupId(groupId)
|
||||||
|
@ -320,7 +320,7 @@ public class ShareGroup extends ModernGroup<ShareGroupMember> {
|
||||||
members.entrySet(committedOffset).forEach(
|
members.entrySet(committedOffset).forEach(
|
||||||
entry -> describedGroup.members().add(
|
entry -> describedGroup.members().add(
|
||||||
entry.getValue().asShareGroupDescribeMember(
|
entry.getValue().asShareGroupDescribeMember(
|
||||||
topicsImage
|
image
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -18,13 +18,12 @@ package org.apache.kafka.coordinator.group.modern.share;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.common.message.ShareGroupDescribeResponseData;
|
import org.apache.kafka.common.message.ShareGroupDescribeResponseData;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.Utils;
|
import org.apache.kafka.coordinator.group.Utils;
|
||||||
import org.apache.kafka.coordinator.group.generated.ShareGroupCurrentMemberAssignmentValue;
|
import org.apache.kafka.coordinator.group.generated.ShareGroupCurrentMemberAssignmentValue;
|
||||||
import org.apache.kafka.coordinator.group.generated.ShareGroupMemberMetadataValue;
|
import org.apache.kafka.coordinator.group.generated.ShareGroupMemberMetadataValue;
|
||||||
import org.apache.kafka.coordinator.group.modern.MemberState;
|
import org.apache.kafka.coordinator.group.modern.MemberState;
|
||||||
import org.apache.kafka.coordinator.group.modern.ModernGroupMember;
|
import org.apache.kafka.coordinator.group.modern.ModernGroupMember;
|
||||||
import org.apache.kafka.image.TopicImage;
|
|
||||||
import org.apache.kafka.image.TopicsImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -198,18 +197,17 @@ public class ShareGroupMember extends ModernGroupMember {
|
||||||
/**
|
/**
|
||||||
* Converts this ShareGroupMember to a ShareGroupDescribeResponseData.Member.
|
* Converts this ShareGroupMember to a ShareGroupDescribeResponseData.Member.
|
||||||
*
|
*
|
||||||
* @param topicsImage: Topics image object to search for a specific topic id
|
* @param image : Topics image object to search for a specific topic id
|
||||||
*
|
|
||||||
* @return The ShareGroupMember mapped as ShareGroupDescribeResponseData.Member.
|
* @return The ShareGroupMember mapped as ShareGroupDescribeResponseData.Member.
|
||||||
*/
|
*/
|
||||||
public ShareGroupDescribeResponseData.Member asShareGroupDescribeMember(
|
public ShareGroupDescribeResponseData.Member asShareGroupDescribeMember(
|
||||||
TopicsImage topicsImage
|
CoordinatorMetadataImage image
|
||||||
) {
|
) {
|
||||||
return new ShareGroupDescribeResponseData.Member()
|
return new ShareGroupDescribeResponseData.Member()
|
||||||
.setMemberEpoch(memberEpoch)
|
.setMemberEpoch(memberEpoch)
|
||||||
.setMemberId(memberId)
|
.setMemberId(memberId)
|
||||||
.setAssignment(new ShareGroupDescribeResponseData.Assignment()
|
.setAssignment(new ShareGroupDescribeResponseData.Assignment()
|
||||||
.setTopicPartitions(topicPartitionsFromMap(assignedPartitions, topicsImage)))
|
.setTopicPartitions(topicPartitionsFromMap(assignedPartitions, image)))
|
||||||
.setClientHost(clientHost)
|
.setClientHost(clientHost)
|
||||||
.setClientId(clientId)
|
.setClientId(clientId)
|
||||||
.setRackId(rackId)
|
.setRackId(rackId)
|
||||||
|
@ -218,17 +216,14 @@ public class ShareGroupMember extends ModernGroupMember {
|
||||||
|
|
||||||
private static List<ShareGroupDescribeResponseData.TopicPartitions> topicPartitionsFromMap(
|
private static List<ShareGroupDescribeResponseData.TopicPartitions> topicPartitionsFromMap(
|
||||||
Map<Uuid, Set<Integer>> partitions,
|
Map<Uuid, Set<Integer>> partitions,
|
||||||
TopicsImage topicsImage
|
CoordinatorMetadataImage image
|
||||||
) {
|
) {
|
||||||
List<ShareGroupDescribeResponseData.TopicPartitions> topicPartitions = new ArrayList<>();
|
List<ShareGroupDescribeResponseData.TopicPartitions> topicPartitions = new ArrayList<>();
|
||||||
partitions.forEach((topicId, partitionSet) -> {
|
partitions.forEach((topicId, partitionSet) -> {
|
||||||
TopicImage topicImage = topicsImage.getTopic(topicId);
|
image.topicMetadata(topicId).ifPresent(topicMetadata -> topicPartitions.add(new ShareGroupDescribeResponseData.TopicPartitions()
|
||||||
if (topicImage != null) {
|
|
||||||
topicPartitions.add(new ShareGroupDescribeResponseData.TopicPartitions()
|
|
||||||
.setTopicId(topicId)
|
.setTopicId(topicId)
|
||||||
.setTopicName(topicImage.name())
|
.setTopicName(topicMetadata.name())
|
||||||
.setPartitions(new ArrayList<>(partitionSet)));
|
.setPartitions(new ArrayList<>(partitionSet))));
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return topicPartitions;
|
return topicPartitions;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.apache.kafka.common.message.StreamsGroupDescribeResponseData;
|
||||||
import org.apache.kafka.common.protocol.Errors;
|
import org.apache.kafka.common.protocol.Errors;
|
||||||
import org.apache.kafka.common.requests.JoinGroupRequest;
|
import org.apache.kafka.common.requests.JoinGroupRequest;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.group.Group;
|
import org.apache.kafka.coordinator.group.Group;
|
||||||
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
||||||
|
@ -33,8 +34,6 @@ import org.apache.kafka.coordinator.group.Utils;
|
||||||
import org.apache.kafka.coordinator.group.metrics.GroupCoordinatorMetricsShard;
|
import org.apache.kafka.coordinator.group.metrics.GroupCoordinatorMetricsShard;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredSubtopology;
|
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredSubtopology;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredTopology;
|
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredTopology;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.image.TopicImage;
|
|
||||||
import org.apache.kafka.timeline.SnapshotRegistry;
|
import org.apache.kafka.timeline.SnapshotRegistry;
|
||||||
import org.apache.kafka.timeline.TimelineHashMap;
|
import org.apache.kafka.timeline.TimelineHashMap;
|
||||||
import org.apache.kafka.timeline.TimelineInteger;
|
import org.apache.kafka.timeline.TimelineInteger;
|
||||||
|
@ -618,7 +617,7 @@ public class StreamsGroup implements Group {
|
||||||
* @return The metadata hash.
|
* @return The metadata hash.
|
||||||
*/
|
*/
|
||||||
public long computeMetadataHash(
|
public long computeMetadataHash(
|
||||||
MetadataImage metadataImage,
|
CoordinatorMetadataImage metadataImage,
|
||||||
Map<String, Long> topicHashCache,
|
Map<String, Long> topicHashCache,
|
||||||
StreamsTopology topology
|
StreamsTopology topology
|
||||||
) {
|
) {
|
||||||
|
@ -626,13 +625,11 @@ public class StreamsGroup implements Group {
|
||||||
|
|
||||||
Map<String, Long> topicHash = new HashMap<>(requiredTopicNames.size());
|
Map<String, Long> topicHash = new HashMap<>(requiredTopicNames.size());
|
||||||
requiredTopicNames.forEach(topicName -> {
|
requiredTopicNames.forEach(topicName -> {
|
||||||
TopicImage topicImage = metadataImage.topics().getTopic(topicName);
|
metadataImage.topicMetadata(topicName).ifPresent(__ ->
|
||||||
if (topicImage != null) {
|
|
||||||
topicHash.put(
|
topicHash.put(
|
||||||
topicName,
|
topicName,
|
||||||
topicHashCache.computeIfAbsent(topicName, k -> Utils.computeTopicHash(topicName, metadataImage))
|
topicHashCache.computeIfAbsent(topicName, k -> Utils.computeTopicHash(topicName, metadataImage))
|
||||||
);
|
));
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return Utils.computeGroupHash(topicHash);
|
return Utils.computeGroupHash(topicHash);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.kafka.coordinator.group.streams;
|
package org.apache.kafka.coordinator.group.streams;
|
||||||
|
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.group.streams.assignor.AssignmentMemberSpec;
|
import org.apache.kafka.coordinator.group.streams.assignor.AssignmentMemberSpec;
|
||||||
import org.apache.kafka.coordinator.group.streams.assignor.GroupAssignment;
|
import org.apache.kafka.coordinator.group.streams.assignor.GroupAssignment;
|
||||||
|
@ -24,7 +25,6 @@ import org.apache.kafka.coordinator.group.streams.assignor.MemberAssignment;
|
||||||
import org.apache.kafka.coordinator.group.streams.assignor.TaskAssignor;
|
import org.apache.kafka.coordinator.group.streams.assignor.TaskAssignor;
|
||||||
import org.apache.kafka.coordinator.group.streams.assignor.TaskAssignorException;
|
import org.apache.kafka.coordinator.group.streams.assignor.TaskAssignorException;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredTopology;
|
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredTopology;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -78,7 +78,7 @@ public class TargetAssignmentBuilder {
|
||||||
/**
|
/**
|
||||||
* The metadata image.
|
* The metadata image.
|
||||||
*/
|
*/
|
||||||
private MetadataImage metadataImage = MetadataImage.EMPTY;
|
private CoordinatorMetadataImage metadataImage = CoordinatorMetadataImage.EMPTY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The existing target assignment.
|
* The existing target assignment.
|
||||||
|
@ -164,7 +164,7 @@ public class TargetAssignmentBuilder {
|
||||||
* @return This object.
|
* @return This object.
|
||||||
*/
|
*/
|
||||||
public TargetAssignmentBuilder withMetadataImage(
|
public TargetAssignmentBuilder withMetadataImage(
|
||||||
MetadataImage metadataImage
|
CoordinatorMetadataImage metadataImage
|
||||||
) {
|
) {
|
||||||
this.metadataImage = metadataImage;
|
this.metadataImage = metadataImage;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.kafka.coordinator.group.streams;
|
package org.apache.kafka.coordinator.group.streams;
|
||||||
|
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.streams.assignor.TopologyDescriber;
|
import org.apache.kafka.coordinator.group.streams.assignor.TopologyDescriber;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredSubtopology;
|
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredSubtopology;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -33,7 +33,7 @@ import java.util.SortedMap;
|
||||||
* @param metadataImage The metadata image
|
* @param metadataImage The metadata image
|
||||||
* @param subtopologyMap The configured subtopologies
|
* @param subtopologyMap The configured subtopologies
|
||||||
*/
|
*/
|
||||||
public record TopologyMetadata(MetadataImage metadataImage, SortedMap<String, ConfiguredSubtopology> subtopologyMap) implements TopologyDescriber {
|
public record TopologyMetadata(CoordinatorMetadataImage metadataImage, SortedMap<String, ConfiguredSubtopology> subtopologyMap) implements TopologyDescriber {
|
||||||
|
|
||||||
public TopologyMetadata {
|
public TopologyMetadata {
|
||||||
metadataImage = Objects.requireNonNull(metadataImage);
|
metadataImage = Objects.requireNonNull(metadataImage);
|
||||||
|
|
|
@ -18,16 +18,16 @@
|
||||||
package org.apache.kafka.coordinator.group.streams.topics;
|
package org.apache.kafka.coordinator.group.streams.topics;
|
||||||
|
|
||||||
import org.apache.kafka.common.message.StreamsGroupHeartbeatResponseData;
|
import org.apache.kafka.common.message.StreamsGroupHeartbeatResponseData;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsGroup;
|
import org.apache.kafka.coordinator.group.streams.StreamsGroup;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsGroupMember;
|
import org.apache.kafka.coordinator.group.streams.StreamsGroupMember;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.image.TopicImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class EndpointToPartitionsManager {
|
public class EndpointToPartitionsManager {
|
||||||
|
@ -38,7 +38,7 @@ public class EndpointToPartitionsManager {
|
||||||
public static StreamsGroupHeartbeatResponseData.EndpointToPartitions endpointToPartitions(final StreamsGroupMember streamsGroupMember,
|
public static StreamsGroupHeartbeatResponseData.EndpointToPartitions endpointToPartitions(final StreamsGroupMember streamsGroupMember,
|
||||||
final StreamsGroupHeartbeatResponseData.Endpoint responseEndpoint,
|
final StreamsGroupHeartbeatResponseData.Endpoint responseEndpoint,
|
||||||
final StreamsGroup streamsGroup,
|
final StreamsGroup streamsGroup,
|
||||||
final MetadataImage metadataImage) {
|
final CoordinatorMetadataImage metadataImage) {
|
||||||
StreamsGroupHeartbeatResponseData.EndpointToPartitions endpointToPartitions = new StreamsGroupHeartbeatResponseData.EndpointToPartitions();
|
StreamsGroupHeartbeatResponseData.EndpointToPartitions endpointToPartitions = new StreamsGroupHeartbeatResponseData.EndpointToPartitions();
|
||||||
Map<String, Set<Integer>> activeTasks = streamsGroupMember.assignedTasks().activeTasks();
|
Map<String, Set<Integer>> activeTasks = streamsGroupMember.assignedTasks().activeTasks();
|
||||||
Map<String, Set<Integer>> standbyTasks = streamsGroupMember.assignedTasks().standbyTasks();
|
Map<String, Set<Integer>> standbyTasks = streamsGroupMember.assignedTasks().standbyTasks();
|
||||||
|
@ -53,7 +53,7 @@ public class EndpointToPartitionsManager {
|
||||||
|
|
||||||
private static List<StreamsGroupHeartbeatResponseData.TopicPartition> topicPartitions(final Map<String, Set<Integer>> tasks,
|
private static List<StreamsGroupHeartbeatResponseData.TopicPartition> topicPartitions(final Map<String, Set<Integer>> tasks,
|
||||||
final Map<String, ConfiguredSubtopology> configuredSubtopologies,
|
final Map<String, ConfiguredSubtopology> configuredSubtopologies,
|
||||||
final MetadataImage metadataImage) {
|
final CoordinatorMetadataImage metadataImage) {
|
||||||
List<StreamsGroupHeartbeatResponseData.TopicPartition> topicPartitionsForTasks = new ArrayList<>();
|
List<StreamsGroupHeartbeatResponseData.TopicPartition> topicPartitionsForTasks = new ArrayList<>();
|
||||||
for (Map.Entry<String, Set<Integer>> taskEntry : tasks.entrySet()) {
|
for (Map.Entry<String, Set<Integer>> taskEntry : tasks.entrySet()) {
|
||||||
String subtopologyId = taskEntry.getKey();
|
String subtopologyId = taskEntry.getKey();
|
||||||
|
@ -70,13 +70,13 @@ public class EndpointToPartitionsManager {
|
||||||
|
|
||||||
private static List<StreamsGroupHeartbeatResponseData.TopicPartition> topicPartitionListForTask(final Set<Integer> taskSet,
|
private static List<StreamsGroupHeartbeatResponseData.TopicPartition> topicPartitionListForTask(final Set<Integer> taskSet,
|
||||||
final Set<String> topicNames,
|
final Set<String> topicNames,
|
||||||
final MetadataImage metadataImage) {
|
final CoordinatorMetadataImage metadataImage) {
|
||||||
return topicNames.stream().map(topic -> {
|
return topicNames.stream().map(topic -> {
|
||||||
TopicImage topicImage = metadataImage.topics().getTopic(topic);
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadata = metadataImage.topicMetadata(topic);
|
||||||
if (topicImage == null) {
|
if (topicMetadata.isEmpty()) {
|
||||||
throw new IllegalStateException("Topic " + topic + " not found in metadata image");
|
throw new IllegalStateException("Topic " + topic + " not found in metadata image");
|
||||||
}
|
}
|
||||||
int numPartitionsForTopic = topicImage.partitions().size();
|
int numPartitionsForTopic = topicMetadata.get().partitionCount();
|
||||||
StreamsGroupHeartbeatResponseData.TopicPartition tp = new StreamsGroupHeartbeatResponseData.TopicPartition();
|
StreamsGroupHeartbeatResponseData.TopicPartition tp = new StreamsGroupHeartbeatResponseData.TopicPartition();
|
||||||
tp.setTopic(topic);
|
tp.setTopic(topic);
|
||||||
List<Integer> tpPartitions = new ArrayList<>(taskSet);
|
List<Integer> tpPartitions = new ArrayList<>(taskSet);
|
||||||
|
|
|
@ -20,10 +20,9 @@ import org.apache.kafka.common.message.CreateTopicsRequestData.CreatableTopic;
|
||||||
import org.apache.kafka.common.message.CreateTopicsRequestData.CreatableTopicConfig;
|
import org.apache.kafka.common.message.CreateTopicsRequestData.CreatableTopicConfig;
|
||||||
import org.apache.kafka.common.message.CreateTopicsRequestData.CreatableTopicConfigCollection;
|
import org.apache.kafka.common.message.CreateTopicsRequestData.CreatableTopicConfigCollection;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.generated.StreamsGroupTopologyValue;
|
import org.apache.kafka.coordinator.group.generated.StreamsGroupTopologyValue;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsTopology;
|
import org.apache.kafka.coordinator.group.streams.StreamsTopology;
|
||||||
import org.apache.kafka.image.TopicImage;
|
|
||||||
import org.apache.kafka.image.TopicsImage;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
@ -47,19 +46,19 @@ import java.util.stream.Stream;
|
||||||
public class InternalTopicManager {
|
public class InternalTopicManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the internal topics for the given topology. Given a topology and the topics image, this method determines the number of
|
* Configures the internal topics for the given topology. Given a topology and the metadata image, this method determines the number of
|
||||||
* partitions for all internal topics and returns a {@link ConfiguredTopology} object.
|
* partitions for all internal topics and returns a {@link ConfiguredTopology} object.
|
||||||
*
|
*
|
||||||
* @param logContext The log context.
|
* @param logContext The log context.
|
||||||
* @param metadataHash The metadata hash of the group.
|
* @param metadataHash The metadata hash of the group.
|
||||||
* @param topology The topology.
|
* @param topology The topology.
|
||||||
* @param topicsImage The topics image.
|
* @param metadataImage The metadata image.
|
||||||
* @return The configured topology.
|
* @return The configured topology.
|
||||||
*/
|
*/
|
||||||
public static ConfiguredTopology configureTopics(LogContext logContext,
|
public static ConfiguredTopology configureTopics(LogContext logContext,
|
||||||
long metadataHash,
|
long metadataHash,
|
||||||
StreamsTopology topology,
|
StreamsTopology topology,
|
||||||
TopicsImage topicsImage) {
|
CoordinatorMetadataImage metadataImage) {
|
||||||
final Logger log = logContext.logger(InternalTopicManager.class);
|
final Logger log = logContext.logger(InternalTopicManager.class);
|
||||||
final Collection<StreamsGroupTopologyValue.Subtopology> subtopologies = topology.subtopologies().values();
|
final Collection<StreamsGroupTopologyValue.Subtopology> subtopologies = topology.subtopologies().values();
|
||||||
|
|
||||||
|
@ -73,23 +72,23 @@ public class InternalTopicManager {
|
||||||
try {
|
try {
|
||||||
Optional<TopicConfigurationException> topicConfigurationException = Optional.empty();
|
Optional<TopicConfigurationException> topicConfigurationException = Optional.empty();
|
||||||
|
|
||||||
throwOnMissingSourceTopics(topology, topicsImage);
|
throwOnMissingSourceTopics(topology, metadataImage);
|
||||||
|
|
||||||
Map<String, Integer> decidedPartitionCountsForInternalTopics =
|
Map<String, Integer> decidedPartitionCountsForInternalTopics =
|
||||||
decidePartitionCounts(logContext, topology, topicsImage, copartitionGroupsBySubtopology, log);
|
decidePartitionCounts(logContext, topology, metadataImage, copartitionGroupsBySubtopology, log);
|
||||||
|
|
||||||
final SortedMap<String, ConfiguredSubtopology> configuredSubtopologies =
|
final SortedMap<String, ConfiguredSubtopology> configuredSubtopologies =
|
||||||
subtopologies.stream()
|
subtopologies.stream()
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
StreamsGroupTopologyValue.Subtopology::subtopologyId,
|
StreamsGroupTopologyValue.Subtopology::subtopologyId,
|
||||||
x -> fromPersistedSubtopology(x, topicsImage, decidedPartitionCountsForInternalTopics),
|
x -> fromPersistedSubtopology(x, metadataImage, decidedPartitionCountsForInternalTopics),
|
||||||
(v1, v2) -> {
|
(v1, v2) -> {
|
||||||
throw new RuntimeException(String.format("Duplicate key for values %s and %s", v1, v2));
|
throw new RuntimeException(String.format("Duplicate key for values %s and %s", v1, v2));
|
||||||
},
|
},
|
||||||
TreeMap::new
|
TreeMap::new
|
||||||
));
|
));
|
||||||
|
|
||||||
Map<String, CreatableTopic> internalTopicsToCreate = missingInternalTopics(configuredSubtopologies, topology, topicsImage);
|
Map<String, CreatableTopic> internalTopicsToCreate = missingInternalTopics(configuredSubtopologies, topology, metadataImage);
|
||||||
if (!internalTopicsToCreate.isEmpty()) {
|
if (!internalTopicsToCreate.isEmpty()) {
|
||||||
topicConfigurationException = Optional.of(TopicConfigurationException.missingInternalTopics(
|
topicConfigurationException = Optional.of(TopicConfigurationException.missingInternalTopics(
|
||||||
"Internal topics are missing: " + internalTopicsToCreate.keySet()
|
"Internal topics are missing: " + internalTopicsToCreate.keySet()
|
||||||
|
@ -122,11 +121,11 @@ public class InternalTopicManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void throwOnMissingSourceTopics(final StreamsTopology topology,
|
private static void throwOnMissingSourceTopics(final StreamsTopology topology,
|
||||||
final TopicsImage topicsImage) {
|
final CoordinatorMetadataImage metadataImage) {
|
||||||
TreeSet<String> sortedMissingTopics = new TreeSet<>();
|
TreeSet<String> sortedMissingTopics = new TreeSet<>();
|
||||||
for (StreamsGroupTopologyValue.Subtopology subtopology : topology.subtopologies().values()) {
|
for (StreamsGroupTopologyValue.Subtopology subtopology : topology.subtopologies().values()) {
|
||||||
for (String sourceTopic : subtopology.sourceTopics()) {
|
for (String sourceTopic : subtopology.sourceTopics()) {
|
||||||
if (topicsImage.getTopic(sourceTopic) == null) {
|
if (metadataImage.topicMetadata(sourceTopic).isEmpty()) {
|
||||||
sortedMissingTopics.add(sourceTopic);
|
sortedMissingTopics.add(sourceTopic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,12 +138,12 @@ public class InternalTopicManager {
|
||||||
|
|
||||||
private static Map<String, Integer> decidePartitionCounts(final LogContext logContext,
|
private static Map<String, Integer> decidePartitionCounts(final LogContext logContext,
|
||||||
final StreamsTopology topology,
|
final StreamsTopology topology,
|
||||||
final TopicsImage topicsImage,
|
final CoordinatorMetadataImage metadataImage,
|
||||||
final Map<String, Collection<Set<String>>> copartitionGroupsBySubtopology,
|
final Map<String, Collection<Set<String>>> copartitionGroupsBySubtopology,
|
||||||
final Logger log) {
|
final Logger log) {
|
||||||
final Map<String, Integer> decidedPartitionCountsForInternalTopics = new HashMap<>();
|
final Map<String, Integer> decidedPartitionCountsForInternalTopics = new HashMap<>();
|
||||||
final Function<String, OptionalInt> topicPartitionCountProvider =
|
final Function<String, OptionalInt> topicPartitionCountProvider =
|
||||||
topic -> getPartitionCount(topicsImage, topic, decidedPartitionCountsForInternalTopics);
|
topic -> getPartitionCount(metadataImage, topic, decidedPartitionCountsForInternalTopics);
|
||||||
final RepartitionTopics repartitionTopics = new RepartitionTopics(
|
final RepartitionTopics repartitionTopics = new RepartitionTopics(
|
||||||
logContext,
|
logContext,
|
||||||
topology.subtopologies().values(),
|
topology.subtopologies().values(),
|
||||||
|
@ -196,7 +195,7 @@ public class InternalTopicManager {
|
||||||
|
|
||||||
private static Map<String, CreatableTopic> missingInternalTopics(Map<String, ConfiguredSubtopology> subtopologyMap,
|
private static Map<String, CreatableTopic> missingInternalTopics(Map<String, ConfiguredSubtopology> subtopologyMap,
|
||||||
StreamsTopology topology,
|
StreamsTopology topology,
|
||||||
TopicsImage topicsImage) {
|
CoordinatorMetadataImage metadataImage) {
|
||||||
|
|
||||||
final Map<String, CreatableTopic> topicsToCreate = new HashMap<>();
|
final Map<String, CreatableTopic> topicsToCreate = new HashMap<>();
|
||||||
for (ConfiguredSubtopology subtopology : subtopologyMap.values()) {
|
for (ConfiguredSubtopology subtopology : subtopologyMap.values()) {
|
||||||
|
@ -206,33 +205,31 @@ public class InternalTopicManager {
|
||||||
.forEach(x -> topicsToCreate.put(x.name(), toCreatableTopic(x)));
|
.forEach(x -> topicsToCreate.put(x.name(), toCreatableTopic(x)));
|
||||||
}
|
}
|
||||||
for (String topic : topology.requiredTopics()) {
|
for (String topic : topology.requiredTopics()) {
|
||||||
TopicImage topicImage = topicsImage.getTopic(topic);
|
metadataImage.topicMetadata(topic).ifPresent(topicMetadata -> {
|
||||||
if (topicImage == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final CreatableTopic expectedTopic = topicsToCreate.remove(topic);
|
final CreatableTopic expectedTopic = topicsToCreate.remove(topic);
|
||||||
if (expectedTopic != null) {
|
if (expectedTopic != null) {
|
||||||
if (topicImage.partitions().size() != expectedTopic.numPartitions()) {
|
if (topicMetadata.partitionCount() != expectedTopic.numPartitions()) {
|
||||||
throw TopicConfigurationException.incorrectlyPartitionedTopics("Existing topic " + topic + " has different"
|
throw TopicConfigurationException.incorrectlyPartitionedTopics("Existing topic " + topic + " has different"
|
||||||
+ " number of partitions: expected " + expectedTopic.numPartitions() + ", found " + topicImage.partitions().size());
|
+ " number of partitions: expected " + expectedTopic.numPartitions() + ", found " + topicMetadata.partitionCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return topicsToCreate;
|
return topicsToCreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OptionalInt getPartitionCount(TopicsImage topicsImage,
|
private static OptionalInt getPartitionCount(CoordinatorMetadataImage metadataImage,
|
||||||
String topic,
|
String topic,
|
||||||
Map<String, Integer> decidedPartitionCountsForInternalTopics) {
|
Map<String, Integer> decidedPartitionCountsForInternalTopics) {
|
||||||
final TopicImage topicImage = topicsImage.getTopic(topic);
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadata = metadataImage.topicMetadata(topic);
|
||||||
if (topicImage == null) {
|
if (topicMetadata.isEmpty()) {
|
||||||
if (decidedPartitionCountsForInternalTopics.containsKey(topic)) {
|
if (decidedPartitionCountsForInternalTopics.containsKey(topic)) {
|
||||||
return OptionalInt.of(decidedPartitionCountsForInternalTopics.get(topic));
|
return OptionalInt.of(decidedPartitionCountsForInternalTopics.get(topic));
|
||||||
} else {
|
} else {
|
||||||
return OptionalInt.empty();
|
return OptionalInt.empty();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return OptionalInt.of(topicImage.partitions().size());
|
return OptionalInt.of(topicMetadata.get().partitionCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,11 +261,11 @@ public class InternalTopicManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ConfiguredSubtopology fromPersistedSubtopology(final StreamsGroupTopologyValue.Subtopology subtopology,
|
private static ConfiguredSubtopology fromPersistedSubtopology(final StreamsGroupTopologyValue.Subtopology subtopology,
|
||||||
final TopicsImage topicsImage,
|
final CoordinatorMetadataImage metadataImage,
|
||||||
final Map<String, Integer> decidedPartitionCountsForInternalTopics
|
final Map<String, Integer> decidedPartitionCountsForInternalTopics
|
||||||
) {
|
) {
|
||||||
return new ConfiguredSubtopology(
|
return new ConfiguredSubtopology(
|
||||||
computeNumberOfTasks(subtopology, topicsImage, decidedPartitionCountsForInternalTopics),
|
computeNumberOfTasks(subtopology, metadataImage, decidedPartitionCountsForInternalTopics),
|
||||||
new HashSet<>(subtopology.sourceTopics()),
|
new HashSet<>(subtopology.sourceTopics()),
|
||||||
subtopology.repartitionSourceTopics().stream()
|
subtopology.repartitionSourceTopics().stream()
|
||||||
.map(x -> fromPersistedTopicInfo(x, decidedPartitionCountsForInternalTopics))
|
.map(x -> fromPersistedTopicInfo(x, decidedPartitionCountsForInternalTopics))
|
||||||
|
@ -281,13 +278,13 @@ public class InternalTopicManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int computeNumberOfTasks(final StreamsGroupTopologyValue.Subtopology subtopology,
|
private static int computeNumberOfTasks(final StreamsGroupTopologyValue.Subtopology subtopology,
|
||||||
final TopicsImage topicsImage,
|
final CoordinatorMetadataImage metadataImage,
|
||||||
final Map<String, Integer> decidedPartitionCountsForInternalTopics) {
|
final Map<String, Integer> decidedPartitionCountsForInternalTopics) {
|
||||||
return Stream.concat(
|
return Stream.concat(
|
||||||
subtopology.sourceTopics().stream(),
|
subtopology.sourceTopics().stream(),
|
||||||
subtopology.repartitionSourceTopics().stream().map(StreamsGroupTopologyValue.TopicInfo::name)
|
subtopology.repartitionSourceTopics().stream().map(StreamsGroupTopologyValue.TopicInfo::name)
|
||||||
).map(
|
).map(
|
||||||
topic -> getPartitionCount(topicsImage, topic, decidedPartitionCountsForInternalTopics).orElseThrow(
|
topic -> getPartitionCount(metadataImage, topic, decidedPartitionCountsForInternalTopics).orElseThrow(
|
||||||
() -> new IllegalStateException("Number of partitions must be set for topic " + topic)
|
() -> new IllegalStateException("Number of partitions must be set for topic " + topic)
|
||||||
)
|
)
|
||||||
).max(Integer::compareTo).orElseThrow(
|
).max(Integer::compareTo).orElseThrow(
|
||||||
|
|
|
@ -87,13 +87,16 @@ import org.apache.kafka.common.security.auth.SecurityProtocol;
|
||||||
import org.apache.kafka.common.utils.BufferSupplier;
|
import org.apache.kafka.common.utils.BufferSupplier;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.Utils;
|
import org.apache.kafka.common.utils.Utils;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRuntime;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRuntime;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataDelta;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.metrics.GroupCoordinatorMetrics;
|
import org.apache.kafka.coordinator.group.metrics.GroupCoordinatorMetrics;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsGroupHeartbeatResult;
|
import org.apache.kafka.coordinator.group.streams.StreamsGroupHeartbeatResult;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
import org.apache.kafka.image.MetadataDelta;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
import org.apache.kafka.image.MetadataImage;
|
||||||
import org.apache.kafka.image.TopicsImage;
|
|
||||||
import org.apache.kafka.server.authorizer.AuthorizableRequestContext;
|
import org.apache.kafka.server.authorizer.AuthorizableRequestContext;
|
||||||
import org.apache.kafka.server.record.BrokerCompressionType;
|
import org.apache.kafka.server.record.BrokerCompressionType;
|
||||||
import org.apache.kafka.server.share.persister.DefaultStatePersister;
|
import org.apache.kafka.server.share.persister.DefaultStatePersister;
|
||||||
|
@ -3152,7 +3155,7 @@ public class GroupCoordinatorServiceTest {
|
||||||
.addTopic(Uuid.randomUuid(), "foo", 1)
|
.addTopic(Uuid.randomUuid(), "foo", 1)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
service.onNewMetadataImage(image, new MetadataDelta(image));
|
service.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), new KRaftCoordinatorMetadataDelta(new MetadataDelta(image)));
|
||||||
|
|
||||||
when(runtime.scheduleWriteAllOperation(
|
when(runtime.scheduleWriteAllOperation(
|
||||||
ArgumentMatchers.eq("on-partition-deleted"),
|
ArgumentMatchers.eq("on-partition-deleted"),
|
||||||
|
@ -3210,7 +3213,7 @@ public class GroupCoordinatorServiceTest {
|
||||||
.addTopic(Uuid.randomUuid(), "foo", 1)
|
.addTopic(Uuid.randomUuid(), "foo", 1)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
service.onNewMetadataImage(image, new MetadataDelta(image));
|
service.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), new KRaftCoordinatorMetadataDelta(new MetadataDelta(image)));
|
||||||
|
|
||||||
// No error in partition deleted callback
|
// No error in partition deleted callback
|
||||||
when(runtime.scheduleWriteAllOperation(
|
when(runtime.scheduleWriteAllOperation(
|
||||||
|
@ -3257,10 +3260,10 @@ public class GroupCoordinatorServiceTest {
|
||||||
.build();
|
.build();
|
||||||
service.startup(() -> 3);
|
service.startup(() -> 3);
|
||||||
|
|
||||||
MetadataImage image = new MetadataImageBuilder()
|
CoordinatorMetadataImage image = new MetadataImageBuilder()
|
||||||
.addTopic(Uuid.randomUuid(), "bar", 1)
|
.addTopic(Uuid.randomUuid(), "bar", 1)
|
||||||
.build();
|
.buildCoordinatorMetadataImage();
|
||||||
service.onNewMetadataImage(image, new MetadataDelta(image));
|
service.onNewMetadataImage(image, image.emptyDelta());
|
||||||
|
|
||||||
// No error in partition deleted callback
|
// No error in partition deleted callback
|
||||||
when(runtime.scheduleWriteAllOperation(
|
when(runtime.scheduleWriteAllOperation(
|
||||||
|
@ -3307,8 +3310,8 @@ public class GroupCoordinatorServiceTest {
|
||||||
.build();
|
.build();
|
||||||
service.startup(() -> 3);
|
service.startup(() -> 3);
|
||||||
|
|
||||||
MetadataImage image = MetadataImage.EMPTY;
|
CoordinatorMetadataImage image = CoordinatorMetadataImage.EMPTY;
|
||||||
service.onNewMetadataImage(image, new MetadataDelta(image));
|
service.onNewMetadataImage(image, image.emptyDelta());
|
||||||
|
|
||||||
// No error in partition deleted callback
|
// No error in partition deleted callback
|
||||||
when(runtime.scheduleWriteAllOperation(
|
when(runtime.scheduleWriteAllOperation(
|
||||||
|
@ -3971,7 +3974,7 @@ public class GroupCoordinatorServiceTest {
|
||||||
.addTopic(TOPIC_ID, TOPIC_NAME, 3)
|
.addTopic(TOPIC_ID, TOPIC_NAME, 3)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
service.onNewMetadataImage(image, null);
|
service.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
|
|
||||||
int partition = 1;
|
int partition = 1;
|
||||||
|
|
||||||
|
@ -4040,7 +4043,7 @@ public class GroupCoordinatorServiceTest {
|
||||||
.addTopic(TOPIC_ID, TOPIC_NAME, 3)
|
.addTopic(TOPIC_ID, TOPIC_NAME, 3)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
service.onNewMetadataImage(image, null);
|
service.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
|
|
||||||
int partition = 1;
|
int partition = 1;
|
||||||
|
|
||||||
|
@ -4076,7 +4079,7 @@ public class GroupCoordinatorServiceTest {
|
||||||
.addTopic(TOPIC_ID, TOPIC_NAME, 3)
|
.addTopic(TOPIC_ID, TOPIC_NAME, 3)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
service.onNewMetadataImage(image, null);
|
service.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
|
|
||||||
int partition = 1;
|
int partition = 1;
|
||||||
|
|
||||||
|
@ -5204,7 +5207,7 @@ public class GroupCoordinatorServiceTest {
|
||||||
.addTopic(topicId, "topic-name", 3)
|
.addTopic(topicId, "topic-name", 3)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
service.onNewMetadataImage(image, null);
|
service.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
|
|
||||||
when(mockPersister.initializeState(ArgumentMatchers.any())).thenReturn(CompletableFuture.completedFuture(
|
when(mockPersister.initializeState(ArgumentMatchers.any())).thenReturn(CompletableFuture.completedFuture(
|
||||||
new InitializeShareGroupStateResult.Builder()
|
new InitializeShareGroupStateResult.Builder()
|
||||||
|
@ -5379,7 +5382,7 @@ public class GroupCoordinatorServiceTest {
|
||||||
.addTopic(topicId, "topic-name", 3)
|
.addTopic(topicId, "topic-name", 3)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
service.onNewMetadataImage(image, null);
|
service.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
|
|
||||||
when(mockPersister.initializeState(ArgumentMatchers.any())).thenReturn(CompletableFuture.completedFuture(
|
when(mockPersister.initializeState(ArgumentMatchers.any())).thenReturn(CompletableFuture.completedFuture(
|
||||||
new InitializeShareGroupStateResult.Builder()
|
new InitializeShareGroupStateResult.Builder()
|
||||||
|
@ -5597,7 +5600,7 @@ public class GroupCoordinatorServiceTest {
|
||||||
.addTopic(topicId, "topic-name", 1)
|
.addTopic(topicId, "topic-name", 1)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
service.onNewMetadataImage(image, null);
|
service.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
|
|
||||||
when(mockPersister.initializeState(ArgumentMatchers.any())).thenReturn(CompletableFuture.completedFuture(
|
when(mockPersister.initializeState(ArgumentMatchers.any())).thenReturn(CompletableFuture.completedFuture(
|
||||||
new InitializeShareGroupStateResult.Builder()
|
new InitializeShareGroupStateResult.Builder()
|
||||||
|
@ -5646,7 +5649,7 @@ public class GroupCoordinatorServiceTest {
|
||||||
private CoordinatorRuntime<GroupCoordinatorShard, CoordinatorRecord> runtime;
|
private CoordinatorRuntime<GroupCoordinatorShard, CoordinatorRecord> runtime;
|
||||||
private GroupCoordinatorMetrics metrics = new GroupCoordinatorMetrics();
|
private GroupCoordinatorMetrics metrics = new GroupCoordinatorMetrics();
|
||||||
private Persister persister = new NoOpStatePersister();
|
private Persister persister = new NoOpStatePersister();
|
||||||
private MetadataImage metadataImage = null;
|
private CoordinatorMetadataImage metadataImage = null;
|
||||||
|
|
||||||
GroupCoordinatorService build() {
|
GroupCoordinatorService build() {
|
||||||
return build(false);
|
return build(false);
|
||||||
|
@ -5654,7 +5657,7 @@ public class GroupCoordinatorServiceTest {
|
||||||
|
|
||||||
GroupCoordinatorService build(boolean serviceStartup) {
|
GroupCoordinatorService build(boolean serviceStartup) {
|
||||||
if (metadataImage == null) {
|
if (metadataImage == null) {
|
||||||
metadataImage = mock(MetadataImage.class);
|
metadataImage = mock(CoordinatorMetadataImage.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupCoordinatorService service = new GroupCoordinatorService(
|
GroupCoordinatorService service = new GroupCoordinatorService(
|
||||||
|
@ -5671,9 +5674,12 @@ public class GroupCoordinatorServiceTest {
|
||||||
service.startup(() -> 1);
|
service.startup(() -> 1);
|
||||||
service.onNewMetadataImage(metadataImage, null);
|
service.onNewMetadataImage(metadataImage, null);
|
||||||
}
|
}
|
||||||
when(metadataImage.topics()).thenReturn(mock(TopicsImage.class));
|
when(metadataImage.topicNames()).thenReturn(Set.of(TOPIC_NAME));
|
||||||
when(metadataImage.topics().topicIdToNameView()).thenReturn(Map.of(TOPIC_ID, TOPIC_NAME));
|
var topicMetadata = mock(CoordinatorMetadataImage.TopicMetadata.class);
|
||||||
when(metadataImage.topics().topicNameToIdView()).thenReturn(Map.of(TOPIC_NAME, TOPIC_ID));
|
when(topicMetadata.name()).thenReturn(TOPIC_NAME);
|
||||||
|
when(topicMetadata.id()).thenReturn(TOPIC_ID);
|
||||||
|
when(metadataImage.topicMetadata(TOPIC_ID)).thenReturn(Optional.of(topicMetadata));
|
||||||
|
when(metadataImage.topicMetadata(TOPIC_NAME)).thenReturn(Optional.of(topicMetadata));
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ import org.apache.kafka.common.requests.TransactionResult;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.MockTime;
|
import org.apache.kafka.common.utils.MockTime;
|
||||||
import org.apache.kafka.common.utils.Time;
|
import org.apache.kafka.common.utils.Time;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetrics;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetrics;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetricsShard;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetricsShard;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
|
@ -87,7 +88,6 @@ import org.apache.kafka.coordinator.group.metrics.GroupCoordinatorMetricsShard;
|
||||||
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroup;
|
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroup;
|
||||||
import org.apache.kafka.coordinator.group.modern.share.ShareGroup;
|
import org.apache.kafka.coordinator.group.modern.share.ShareGroup;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsGroupHeartbeatResult;
|
import org.apache.kafka.coordinator.group.streams.StreamsGroupHeartbeatResult;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
||||||
import org.apache.kafka.server.share.persister.DeleteShareGroupStateParameters;
|
import org.apache.kafka.server.share.persister.DeleteShareGroupStateParameters;
|
||||||
import org.apache.kafka.server.share.persister.GroupTopicPartitionData;
|
import org.apache.kafka.server.share.persister.GroupTopicPartitionData;
|
||||||
|
@ -1248,7 +1248,7 @@ public class GroupCoordinatorShardTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnLoaded() {
|
public void testOnLoaded() {
|
||||||
MetadataImage image = MetadataImage.EMPTY;
|
CoordinatorMetadataImage image = CoordinatorMetadataImage.EMPTY;
|
||||||
GroupMetadataManager groupMetadataManager = mock(GroupMetadataManager.class);
|
GroupMetadataManager groupMetadataManager = mock(GroupMetadataManager.class);
|
||||||
OffsetMetadataManager offsetMetadataManager = mock(OffsetMetadataManager.class);
|
OffsetMetadataManager offsetMetadataManager = mock(OffsetMetadataManager.class);
|
||||||
CoordinatorMetrics coordinatorMetrics = mock(CoordinatorMetrics.class);
|
CoordinatorMetrics coordinatorMetrics = mock(CoordinatorMetrics.class);
|
||||||
|
@ -1344,7 +1344,7 @@ public class GroupCoordinatorShardTest {
|
||||||
mock(CoordinatorMetrics.class),
|
mock(CoordinatorMetrics.class),
|
||||||
mock(CoordinatorMetricsShard.class)
|
mock(CoordinatorMetricsShard.class)
|
||||||
);
|
);
|
||||||
MetadataImage image = MetadataImage.EMPTY;
|
CoordinatorMetadataImage image = CoordinatorMetadataImage.EMPTY;
|
||||||
|
|
||||||
// Confirm the cleanup is scheduled when the coordinator is initially loaded.
|
// Confirm the cleanup is scheduled when the coordinator is initially loaded.
|
||||||
coordinator.onLoaded(image);
|
coordinator.onLoaded(image);
|
||||||
|
@ -1479,7 +1479,7 @@ public class GroupCoordinatorShardTest {
|
||||||
coordinatorMetrics,
|
coordinatorMetrics,
|
||||||
metricsShard
|
metricsShard
|
||||||
);
|
);
|
||||||
coordinator.onLoaded(MetadataImage.EMPTY);
|
coordinator.onLoaded(CoordinatorMetadataImage.EMPTY);
|
||||||
|
|
||||||
// The counter is scheduled.
|
// The counter is scheduled.
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -53,6 +53,7 @@ import org.apache.kafka.common.security.auth.KafkaPrincipal;
|
||||||
import org.apache.kafka.common.security.auth.SecurityProtocol;
|
import org.apache.kafka.common.security.auth.SecurityProtocol;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.MockTime;
|
import org.apache.kafka.common.utils.MockTime;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorResult;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorResult;
|
||||||
import org.apache.kafka.coordinator.common.runtime.MockCoordinatorExecutor;
|
import org.apache.kafka.coordinator.common.runtime.MockCoordinatorExecutor;
|
||||||
|
@ -115,7 +116,6 @@ import org.apache.kafka.coordinator.group.streams.StreamsGroupMember;
|
||||||
import org.apache.kafka.coordinator.group.streams.TasksTuple;
|
import org.apache.kafka.coordinator.group.streams.TasksTuple;
|
||||||
import org.apache.kafka.coordinator.group.streams.assignor.TaskAssignor;
|
import org.apache.kafka.coordinator.group.streams.assignor.TaskAssignor;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.InternalTopicManager;
|
import org.apache.kafka.coordinator.group.streams.topics.InternalTopicManager;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.server.authorizer.Authorizer;
|
import org.apache.kafka.server.authorizer.Authorizer;
|
||||||
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
||||||
import org.apache.kafka.server.share.persister.InitializeShareGroupStateParameters;
|
import org.apache.kafka.server.share.persister.InitializeShareGroupStateParameters;
|
||||||
|
@ -462,7 +462,7 @@ public class GroupMetadataManagerTestContext {
|
||||||
private final MockCoordinatorExecutor<CoordinatorRecord> executor = new MockCoordinatorExecutor<>();
|
private final MockCoordinatorExecutor<CoordinatorRecord> executor = new MockCoordinatorExecutor<>();
|
||||||
private final LogContext logContext = new LogContext();
|
private final LogContext logContext = new LogContext();
|
||||||
private final SnapshotRegistry snapshotRegistry = new SnapshotRegistry(logContext);
|
private final SnapshotRegistry snapshotRegistry = new SnapshotRegistry(logContext);
|
||||||
private MetadataImage metadataImage;
|
private CoordinatorMetadataImage metadataImage;
|
||||||
private GroupConfigManager groupConfigManager;
|
private GroupConfigManager groupConfigManager;
|
||||||
private final List<ConsumerGroupBuilder> consumerGroupBuilders = new ArrayList<>();
|
private final List<ConsumerGroupBuilder> consumerGroupBuilders = new ArrayList<>();
|
||||||
private final List<StreamsGroupBuilder> streamsGroupBuilders = new ArrayList<>();
|
private final List<StreamsGroupBuilder> streamsGroupBuilders = new ArrayList<>();
|
||||||
|
@ -478,7 +478,7 @@ public class GroupMetadataManagerTestContext {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder withMetadataImage(MetadataImage metadataImage) {
|
public Builder withMetadataImage(CoordinatorMetadataImage metadataImage) {
|
||||||
this.metadataImage = metadataImage;
|
this.metadataImage = metadataImage;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -519,7 +519,7 @@ public class GroupMetadataManagerTestContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupMetadataManagerTestContext build() {
|
public GroupMetadataManagerTestContext build() {
|
||||||
if (metadataImage == null) metadataImage = MetadataImage.EMPTY;
|
if (metadataImage == null) metadataImage = CoordinatorMetadataImage.EMPTY;
|
||||||
if (groupConfigManager == null) groupConfigManager = createConfigManager();
|
if (groupConfigManager == null) groupConfigManager = createConfigManager();
|
||||||
|
|
||||||
config.putIfAbsent(
|
config.putIfAbsent(
|
||||||
|
@ -554,7 +554,7 @@ public class GroupMetadataManagerTestContext {
|
||||||
);
|
);
|
||||||
|
|
||||||
consumerGroupBuilders.forEach(builder -> builder.build().forEach(context::replay));
|
consumerGroupBuilders.forEach(builder -> builder.build().forEach(context::replay));
|
||||||
shareGroupBuilders.forEach(builder -> builder.build(metadataImage.topics()).forEach(context::replay));
|
shareGroupBuilders.forEach(builder -> builder.build().forEach(context::replay));
|
||||||
streamsGroupBuilders.forEach(builder -> {
|
streamsGroupBuilders.forEach(builder -> {
|
||||||
builder.build().forEach(context::replay);
|
builder.build().forEach(context::replay);
|
||||||
StreamsGroup group = context.groupMetadataManager.getStreamsGroupOrThrow(builder.groupId());
|
StreamsGroup group = context.groupMetadataManager.getStreamsGroupOrThrow(builder.groupId());
|
||||||
|
@ -563,7 +563,7 @@ public class GroupMetadataManagerTestContext {
|
||||||
new LogContext(),
|
new LogContext(),
|
||||||
0,
|
0,
|
||||||
group.topology().get(),
|
group.topology().get(),
|
||||||
metadataImage.topics())
|
metadataImage)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -49,6 +49,7 @@ import org.apache.kafka.common.utils.MockTime;
|
||||||
import org.apache.kafka.common.utils.annotation.ApiKeyVersionsSource;
|
import org.apache.kafka.common.utils.annotation.ApiKeyVersionsSource;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorResult;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorResult;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.MockCoordinatorExecutor;
|
import org.apache.kafka.coordinator.common.runtime.MockCoordinatorExecutor;
|
||||||
import org.apache.kafka.coordinator.common.runtime.MockCoordinatorTimer;
|
import org.apache.kafka.coordinator.common.runtime.MockCoordinatorTimer;
|
||||||
import org.apache.kafka.coordinator.group.classic.ClassicGroup;
|
import org.apache.kafka.coordinator.group.classic.ClassicGroup;
|
||||||
|
@ -140,7 +141,7 @@ public class OffsetMetadataManagerTest {
|
||||||
.withExecutor(executor)
|
.withExecutor(executor)
|
||||||
.withSnapshotRegistry(snapshotRegistry)
|
.withSnapshotRegistry(snapshotRegistry)
|
||||||
.withLogContext(logContext)
|
.withLogContext(logContext)
|
||||||
.withMetadataImage(metadataImage)
|
.withMetadataImage(new KRaftCoordinatorMetadataImage(metadataImage))
|
||||||
.withGroupCoordinatorMetricsShard(metrics)
|
.withGroupCoordinatorMetricsShard(metrics)
|
||||||
.withGroupConfigManager(configManager)
|
.withGroupConfigManager(configManager)
|
||||||
.withConfig(GroupCoordinatorConfig.fromProps(Map.of()))
|
.withConfig(GroupCoordinatorConfig.fromProps(Map.of()))
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
package org.apache.kafka.coordinator.group;
|
package org.apache.kafka.coordinator.group;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
|
|
||||||
import com.dynatrace.hash4j.hashing.Hashing;
|
import com.dynatrace.hash4j.hashing.Hashing;
|
||||||
|
|
||||||
|
@ -38,10 +39,10 @@ public class UtilsTest {
|
||||||
private static final String FOO_TOPIC_NAME = "foo";
|
private static final String FOO_TOPIC_NAME = "foo";
|
||||||
private static final String BAR_TOPIC_NAME = "bar";
|
private static final String BAR_TOPIC_NAME = "bar";
|
||||||
private static final int FOO_NUM_PARTITIONS = 2;
|
private static final int FOO_NUM_PARTITIONS = 2;
|
||||||
private static final MetadataImage FOO_METADATA_IMAGE = new MetadataImageBuilder()
|
private static final CoordinatorMetadataImage FOO_METADATA_IMAGE = new MetadataImageBuilder()
|
||||||
.addTopic(FOO_TOPIC_ID, FOO_TOPIC_NAME, FOO_NUM_PARTITIONS)
|
.addTopic(FOO_TOPIC_ID, FOO_TOPIC_NAME, FOO_NUM_PARTITIONS)
|
||||||
.addRacks()
|
.addRacks()
|
||||||
.build();
|
.buildCoordinatorMetadataImage();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testNonExistingTopicName() {
|
void testNonExistingTopicName() {
|
||||||
|
@ -170,7 +171,7 @@ public class UtilsTest {
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("differentFieldGenerator")
|
@MethodSource("differentFieldGenerator")
|
||||||
void testComputeTopicHashWithDifferentField(MetadataImage differentImage) {
|
void testComputeTopicHashWithDifferentField(CoordinatorMetadataImage differentImage) {
|
||||||
long result = Utils.computeTopicHash(FOO_TOPIC_NAME, FOO_METADATA_IMAGE);
|
long result = Utils.computeTopicHash(FOO_TOPIC_NAME, FOO_METADATA_IMAGE);
|
||||||
|
|
||||||
assertNotEquals(
|
assertNotEquals(
|
||||||
|
@ -185,21 +186,21 @@ public class UtilsTest {
|
||||||
new MetadataImageBuilder() // different topic id
|
new MetadataImageBuilder() // different topic id
|
||||||
.addTopic(Uuid.randomUuid(), FOO_TOPIC_NAME, FOO_NUM_PARTITIONS)
|
.addTopic(Uuid.randomUuid(), FOO_TOPIC_NAME, FOO_NUM_PARTITIONS)
|
||||||
.addRacks()
|
.addRacks()
|
||||||
.build()
|
.buildCoordinatorMetadataImage()
|
||||||
),
|
),
|
||||||
Arguments.of(new MetadataImageBuilder() // different topic name
|
Arguments.of(new MetadataImageBuilder() // different topic name
|
||||||
.addTopic(FOO_TOPIC_ID, "bar", FOO_NUM_PARTITIONS)
|
.addTopic(FOO_TOPIC_ID, "bar", FOO_NUM_PARTITIONS)
|
||||||
.addRacks()
|
.addRacks()
|
||||||
.build()
|
.buildCoordinatorMetadataImage()
|
||||||
),
|
),
|
||||||
Arguments.of(new MetadataImageBuilder() // different partitions
|
Arguments.of(new MetadataImageBuilder() // different partitions
|
||||||
.addTopic(FOO_TOPIC_ID, FOO_TOPIC_NAME, 1)
|
.addTopic(FOO_TOPIC_ID, FOO_TOPIC_NAME, 1)
|
||||||
.addRacks()
|
.addRacks()
|
||||||
.build()
|
.buildCoordinatorMetadataImage()
|
||||||
),
|
),
|
||||||
Arguments.of(new MetadataImageBuilder() // different racks
|
Arguments.of(new MetadataImageBuilder() // different racks
|
||||||
.addTopic(FOO_TOPIC_ID, FOO_TOPIC_NAME, FOO_NUM_PARTITIONS)
|
.addTopic(FOO_TOPIC_ID, FOO_TOPIC_NAME, FOO_NUM_PARTITIONS)
|
||||||
.build()
|
.buildCoordinatorMetadataImage()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
package org.apache.kafka.coordinator.group.assignor;
|
package org.apache.kafka.coordinator.group.assignor;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.PartitionAssignorException;
|
import org.apache.kafka.coordinator.group.api.assignor.PartitionAssignorException;
|
||||||
|
@ -66,7 +67,7 @@ public class OptimizedUniformAssignmentBuilderTest {
|
||||||
.addTopic(topic1Uuid, topic1Name, 3)
|
.addTopic(topic1Uuid, topic1Name, 3)
|
||||||
.build();
|
.build();
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
||||||
|
@ -99,7 +100,7 @@ public class OptimizedUniformAssignmentBuilderTest {
|
||||||
.addTopic(topic1Uuid, topic1Name, 3)
|
.addTopic(topic1Uuid, topic1Name, 3)
|
||||||
.build();
|
.build();
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
||||||
|
@ -159,7 +160,7 @@ public class OptimizedUniformAssignmentBuilderTest {
|
||||||
Map.of()
|
Map.of()
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -218,7 +219,7 @@ public class OptimizedUniformAssignmentBuilderTest {
|
||||||
Map.of()
|
Map.of()
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -257,7 +258,7 @@ public class OptimizedUniformAssignmentBuilderTest {
|
||||||
Map.of()
|
Map.of()
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -313,7 +314,7 @@ public class OptimizedUniformAssignmentBuilderTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -371,7 +372,7 @@ public class OptimizedUniformAssignmentBuilderTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -438,7 +439,7 @@ public class OptimizedUniformAssignmentBuilderTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -497,7 +498,7 @@ public class OptimizedUniformAssignmentBuilderTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -553,7 +554,7 @@ public class OptimizedUniformAssignmentBuilderTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -620,7 +621,7 @@ public class OptimizedUniformAssignmentBuilderTest {
|
||||||
HOMOGENEOUS,
|
HOMOGENEOUS,
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(metadataImage);
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(new KRaftCoordinatorMetadataImage(metadataImage));
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
groupSpec,
|
groupSpec,
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
package org.apache.kafka.coordinator.group.assignor;
|
package org.apache.kafka.coordinator.group.assignor;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
||||||
|
@ -62,7 +64,7 @@ public class RangeAssignorTest {
|
||||||
@Test
|
@Test
|
||||||
public void testOneMemberNoTopic() {
|
public void testOneMemberNoTopic() {
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
MetadataImage.EMPTY
|
CoordinatorMetadataImage.EMPTY
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
||||||
|
@ -100,7 +102,7 @@ public class RangeAssignorTest {
|
||||||
.addTopic(topic1Uuid, topic1Name, 3)
|
.addTopic(topic1Uuid, topic1Name, 3)
|
||||||
.build();
|
.build();
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
||||||
|
@ -152,7 +154,7 @@ public class RangeAssignorTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -210,7 +212,7 @@ public class RangeAssignorTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -270,7 +272,7 @@ public class RangeAssignorTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -301,7 +303,7 @@ public class RangeAssignorTest {
|
||||||
.addTopic(topic1Uuid, topic1Name, 3)
|
.addTopic(topic1Uuid, topic1Name, 3)
|
||||||
.build();
|
.build();
|
||||||
SubscribedTopicDescriber subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriber subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, MemberSubscriptionAndAssignmentImpl> members = new TreeMap<>();
|
Map<String, MemberSubscriptionAndAssignmentImpl> members = new TreeMap<>();
|
||||||
|
@ -367,7 +369,7 @@ public class RangeAssignorTest {
|
||||||
.addTopic(topic1Uuid, topic1Name, 5)
|
.addTopic(topic1Uuid, topic1Name, 5)
|
||||||
.build();
|
.build();
|
||||||
SubscribedTopicDescriber subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriber subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize members with instance Ids.
|
// Initialize members with instance Ids.
|
||||||
|
@ -484,7 +486,7 @@ public class RangeAssignorTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -543,7 +545,7 @@ public class RangeAssignorTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -607,7 +609,7 @@ public class RangeAssignorTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -676,7 +678,7 @@ public class RangeAssignorTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -727,7 +729,7 @@ public class RangeAssignorTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -791,7 +793,7 @@ public class RangeAssignorTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
package org.apache.kafka.coordinator.group.assignor;
|
package org.apache.kafka.coordinator.group.assignor;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
||||||
|
@ -70,7 +72,7 @@ public class SimpleAssignorTest {
|
||||||
@Test
|
@Test
|
||||||
public void testAssignWithEmptyMembers() {
|
public void testAssignWithEmptyMembers() {
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
MetadataImage.EMPTY
|
CoordinatorMetadataImage.EMPTY
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupSpec groupSpec = new GroupSpecImpl(
|
GroupSpec groupSpec = new GroupSpecImpl(
|
||||||
|
@ -104,7 +106,7 @@ public class SimpleAssignorTest {
|
||||||
.addTopic(TOPIC_1_UUID, TOPIC_1_NAME, 3)
|
.addTopic(TOPIC_1_UUID, TOPIC_1_NAME, 3)
|
||||||
.build();
|
.build();
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
||||||
|
@ -137,7 +139,7 @@ public class SimpleAssignorTest {
|
||||||
.addTopic(TOPIC_1_UUID, TOPIC_1_NAME, 3)
|
.addTopic(TOPIC_1_UUID, TOPIC_1_NAME, 3)
|
||||||
.build();
|
.build();
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
Map<String, MemberSubscriptionAndAssignmentImpl> members = Map.of(
|
||||||
|
@ -193,7 +195,7 @@ public class SimpleAssignorTest {
|
||||||
Map.of()
|
Map.of()
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -243,7 +245,7 @@ public class SimpleAssignorTest {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -291,7 +293,7 @@ public class SimpleAssignorTest {
|
||||||
);
|
);
|
||||||
|
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -345,7 +347,7 @@ public class SimpleAssignorTest {
|
||||||
Map.of()
|
Map.of()
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -408,7 +410,7 @@ public class SimpleAssignorTest {
|
||||||
);
|
);
|
||||||
|
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -470,7 +472,7 @@ public class SimpleAssignorTest {
|
||||||
);
|
);
|
||||||
|
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -524,7 +526,7 @@ public class SimpleAssignorTest {
|
||||||
Map.of()
|
Map.of()
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -553,7 +555,7 @@ public class SimpleAssignorTest {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
Set<Uuid> topicsSubscription = new LinkedHashSet<>();
|
Set<Uuid> topicsSubscription = new LinkedHashSet<>();
|
||||||
|
@ -600,7 +602,7 @@ public class SimpleAssignorTest {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
Set<Uuid> topicsSubscription = new LinkedHashSet<>();
|
Set<Uuid> topicsSubscription = new LinkedHashSet<>();
|
||||||
|
@ -705,7 +707,7 @@ public class SimpleAssignorTest {
|
||||||
Map.of()
|
Map.of()
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata1 = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata1 = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage1
|
new KRaftCoordinatorMetadataImage(metadataImage1)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment1 = assignor.assign(
|
GroupAssignment computedAssignment1 = assignor.assign(
|
||||||
|
@ -759,7 +761,7 @@ public class SimpleAssignorTest {
|
||||||
);
|
);
|
||||||
|
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata2 = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata2 = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage2
|
new KRaftCoordinatorMetadataImage(metadataImage2)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment2 = assignor.assign(
|
GroupAssignment computedAssignment2 = assignor.assign(
|
||||||
|
@ -775,11 +777,11 @@ public class SimpleAssignorTest {
|
||||||
final int numPartitions = 24;
|
final int numPartitions = 24;
|
||||||
final int numMembers = 101;
|
final int numMembers = 101;
|
||||||
|
|
||||||
MetadataImage metadataImage = new MetadataImageBuilder()
|
CoordinatorMetadataImage metadataImage = new MetadataImageBuilder()
|
||||||
.addTopic(TOPIC_1_UUID, TOPIC_1_NAME, numPartitions / 2)
|
.addTopic(TOPIC_1_UUID, TOPIC_1_NAME, numPartitions / 2)
|
||||||
.addTopic(TOPIC_2_UUID, TOPIC_2_NAME, numPartitions / 3)
|
.addTopic(TOPIC_2_UUID, TOPIC_2_NAME, numPartitions / 3)
|
||||||
.addTopic(TOPIC_3_UUID, TOPIC_3_NAME, numPartitions / 6)
|
.addTopic(TOPIC_3_UUID, TOPIC_3_NAME, numPartitions / 6)
|
||||||
.build();
|
.buildCoordinatorMetadataImage();
|
||||||
|
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
metadataImage
|
||||||
|
@ -843,11 +845,11 @@ public class SimpleAssignorTest {
|
||||||
final int numPartitions = 24;
|
final int numPartitions = 24;
|
||||||
final int numMembers = 101;
|
final int numMembers = 101;
|
||||||
|
|
||||||
MetadataImage metadataImage = new MetadataImageBuilder()
|
CoordinatorMetadataImage metadataImage = new MetadataImageBuilder()
|
||||||
.addTopic(TOPIC_1_UUID, TOPIC_1_NAME, numPartitions / 2)
|
.addTopic(TOPIC_1_UUID, TOPIC_1_NAME, numPartitions / 2)
|
||||||
.addTopic(TOPIC_2_UUID, TOPIC_2_NAME, numPartitions / 3)
|
.addTopic(TOPIC_2_UUID, TOPIC_2_NAME, numPartitions / 3)
|
||||||
.addTopic(TOPIC_3_UUID, TOPIC_3_NAME, numPartitions / 6)
|
.addTopic(TOPIC_3_UUID, TOPIC_3_NAME, numPartitions / 6)
|
||||||
.build();
|
.buildCoordinatorMetadataImage();
|
||||||
|
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
metadataImage
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
package org.apache.kafka.coordinator.group.assignor;
|
package org.apache.kafka.coordinator.group.assignor;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.PartitionAssignorException;
|
import org.apache.kafka.coordinator.group.api.assignor.PartitionAssignorException;
|
||||||
|
@ -94,7 +95,7 @@ public class UniformHeterogeneousAssignmentBuilderTest {
|
||||||
.addTopic(topic1Uuid, topic1Name, 3)
|
.addTopic(topic1Uuid, topic1Name, 3)
|
||||||
.build();
|
.build();
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, MemberSubscriptionAndAssignmentImpl> members = new TreeMap<>();
|
Map<String, MemberSubscriptionAndAssignmentImpl> members = new TreeMap<>();
|
||||||
|
@ -131,7 +132,7 @@ public class UniformHeterogeneousAssignmentBuilderTest {
|
||||||
.addTopic(topic1Uuid, topic1Name, 3)
|
.addTopic(topic1Uuid, topic1Name, 3)
|
||||||
.build();
|
.build();
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, MemberSubscriptionAndAssignmentImpl> members = new TreeMap<>();
|
Map<String, MemberSubscriptionAndAssignmentImpl> members = new TreeMap<>();
|
||||||
|
@ -188,7 +189,7 @@ public class UniformHeterogeneousAssignmentBuilderTest {
|
||||||
Map.of()
|
Map.of()
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -244,7 +245,7 @@ public class UniformHeterogeneousAssignmentBuilderTest {
|
||||||
Map.of()
|
Map.of()
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -313,7 +314,7 @@ public class UniformHeterogeneousAssignmentBuilderTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -377,7 +378,7 @@ public class UniformHeterogeneousAssignmentBuilderTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -442,7 +443,7 @@ public class UniformHeterogeneousAssignmentBuilderTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -502,7 +503,7 @@ public class UniformHeterogeneousAssignmentBuilderTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -558,7 +559,7 @@ public class UniformHeterogeneousAssignmentBuilderTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -617,7 +618,7 @@ public class UniformHeterogeneousAssignmentBuilderTest {
|
||||||
invertedTargetAssignment(members)
|
invertedTargetAssignment(members)
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
@ -666,7 +667,7 @@ public class UniformHeterogeneousAssignmentBuilderTest {
|
||||||
Map.of()
|
Map.of()
|
||||||
);
|
);
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
GroupAssignment computedAssignment = assignor.assign(
|
GroupAssignment computedAssignment = assignor.assign(
|
||||||
|
|
|
@ -39,7 +39,8 @@ import org.apache.kafka.common.utils.MockTime;
|
||||||
import org.apache.kafka.common.utils.Time;
|
import org.apache.kafka.common.utils.Time;
|
||||||
import org.apache.kafka.common.utils.Utils;
|
import org.apache.kafka.common.utils.Utils;
|
||||||
import org.apache.kafka.common.utils.annotation.ApiKeyVersionsSource;
|
import org.apache.kafka.common.utils.annotation.ApiKeyVersionsSource;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.OffsetAndMetadata;
|
import org.apache.kafka.coordinator.group.OffsetAndMetadata;
|
||||||
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
||||||
import org.apache.kafka.coordinator.group.OffsetExpirationConditionImpl;
|
import org.apache.kafka.coordinator.group.OffsetExpirationConditionImpl;
|
||||||
|
@ -1461,7 +1462,7 @@ public class ClassicGroupTest {
|
||||||
newMember2,
|
newMember2,
|
||||||
logContext,
|
logContext,
|
||||||
time,
|
time,
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
ClassicGroup expectedClassicGroup = new ClassicGroup(
|
ClassicGroup expectedClassicGroup = new ClassicGroup(
|
||||||
|
@ -1592,7 +1593,7 @@ public class ClassicGroupTest {
|
||||||
null,
|
null,
|
||||||
logContext,
|
logContext,
|
||||||
time,
|
time,
|
||||||
metadataImage
|
new KRaftCoordinatorMetadataImage(metadataImage)
|
||||||
);
|
);
|
||||||
|
|
||||||
ClassicGroup expectedClassicGroup = new ClassicGroup(
|
ClassicGroup expectedClassicGroup = new ClassicGroup(
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
package org.apache.kafka.coordinator.group.modern;
|
package org.apache.kafka.coordinator.group.modern;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -32,7 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
public class SubscribedTopicMetadataTest {
|
public class SubscribedTopicMetadataTest {
|
||||||
|
|
||||||
private SubscribedTopicDescriberImpl subscribedTopicMetadata;
|
private SubscribedTopicDescriberImpl subscribedTopicMetadata;
|
||||||
private MetadataImage metadataImage;
|
private CoordinatorMetadataImage metadataImage;
|
||||||
private final int numPartitions = 5;
|
private final int numPartitions = 5;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
|
@ -43,7 +43,7 @@ public class SubscribedTopicMetadataTest {
|
||||||
String topicName = "topic" + i;
|
String topicName = "topic" + i;
|
||||||
metadataImageBuilder.addTopic(topicId, topicName, numPartitions);
|
metadataImageBuilder.addTopic(topicId, topicName, numPartitions);
|
||||||
}
|
}
|
||||||
metadataImage = metadataImageBuilder.addRacks().build();
|
metadataImage = metadataImageBuilder.addRacks().buildCoordinatorMetadataImage();
|
||||||
|
|
||||||
subscribedTopicMetadata = new SubscribedTopicDescriberImpl(metadataImage);
|
subscribedTopicMetadata = new SubscribedTopicDescriberImpl(metadataImage);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ public class SubscribedTopicMetadataTest {
|
||||||
assertEquals(-1, subscribedTopicMetadata.numPartitions(topicId));
|
assertEquals(-1, subscribedTopicMetadata.numPartitions(topicId));
|
||||||
|
|
||||||
// Test that the correct number of partitions are returned for a given topic ID.
|
// Test that the correct number of partitions are returned for a given topic ID.
|
||||||
metadataImage.topics().topicsById().forEach((id, name) ->
|
metadataImage.topicIds().forEach(id ->
|
||||||
// Test that the correct number of partitions are returned for a given topic ID.
|
// Test that the correct number of partitions are returned for a given topic ID.
|
||||||
assertEquals(numPartitions, subscribedTopicMetadata.numPartitions(id))
|
assertEquals(numPartitions, subscribedTopicMetadata.numPartitions(id))
|
||||||
);
|
);
|
||||||
|
@ -73,7 +73,7 @@ public class SubscribedTopicMetadataTest {
|
||||||
|
|
||||||
// Test empty set is returned when the topic ID doesn't exist.
|
// Test empty set is returned when the topic ID doesn't exist.
|
||||||
assertEquals(Set.of(), subscribedTopicMetadata.racksForPartition(topicId, 0));
|
assertEquals(Set.of(), subscribedTopicMetadata.racksForPartition(topicId, 0));
|
||||||
metadataImage.topics().topicsById().forEach((id, name) -> {
|
metadataImage.topicIds().forEach(id -> {
|
||||||
// Test empty set is returned when the partition ID doesn't exist.
|
// Test empty set is returned when the partition ID doesn't exist.
|
||||||
assertEquals(Set.of(), subscribedTopicMetadata.racksForPartition(id, 10));
|
assertEquals(Set.of(), subscribedTopicMetadata.racksForPartition(id, 10));
|
||||||
|
|
||||||
|
@ -87,10 +87,10 @@ public class SubscribedTopicMetadataTest {
|
||||||
assertEquals(new SubscribedTopicDescriberImpl(metadataImage), subscribedTopicMetadata);
|
assertEquals(new SubscribedTopicDescriberImpl(metadataImage), subscribedTopicMetadata);
|
||||||
|
|
||||||
Uuid topicId = Uuid.randomUuid();
|
Uuid topicId = Uuid.randomUuid();
|
||||||
MetadataImage metadataImage2 = new MetadataImageBuilder()
|
CoordinatorMetadataImage metadataImage2 = new MetadataImageBuilder()
|
||||||
.addTopic(topicId, "newTopic", 5)
|
.addTopic(topicId, "newTopic", 5)
|
||||||
.addRacks()
|
.addRacks()
|
||||||
.build();
|
.buildCoordinatorMetadataImage();
|
||||||
assertNotEquals(new SubscribedTopicDescriberImpl(metadataImage2), subscribedTopicMetadata);
|
assertNotEquals(new SubscribedTopicDescriberImpl(metadataImage2), subscribedTopicMetadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,16 @@
|
||||||
package org.apache.kafka.coordinator.group.modern;
|
package org.apache.kafka.coordinator.group.modern;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.AssignmentTestUtil;
|
import org.apache.kafka.coordinator.group.AssignmentTestUtil;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.PartitionAssignor;
|
import org.apache.kafka.coordinator.group.api.assignor.PartitionAssignor;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.SubscriptionType;
|
import org.apache.kafka.coordinator.group.api.assignor.SubscriptionType;
|
||||||
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroupMember;
|
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroupMember;
|
||||||
import org.apache.kafka.coordinator.group.modern.consumer.ResolvedRegularExpression;
|
import org.apache.kafka.coordinator.group.modern.consumer.ResolvedRegularExpression;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -212,8 +213,8 @@ public class TargetAssignmentBuilderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TargetAssignmentBuilder.TargetAssignmentResult build() {
|
public TargetAssignmentBuilder.TargetAssignmentResult build() {
|
||||||
MetadataImage metadataImage = metadataImageBuilder.build();
|
CoordinatorMetadataImage cooridnatorMetadataImage = new KRaftCoordinatorMetadataImage(metadataImageBuilder.build());
|
||||||
TopicIds.TopicResolver topicResolver = new TopicIds.CachedTopicResolver(metadataImage.topics());
|
TopicIds.TopicResolver topicResolver = new TopicIds.CachedTopicResolver(cooridnatorMetadataImage);
|
||||||
// Prepare expected member specs.
|
// Prepare expected member specs.
|
||||||
Map<String, MemberSubscriptionAndAssignmentImpl> memberSubscriptions = new HashMap<>();
|
Map<String, MemberSubscriptionAndAssignmentImpl> memberSubscriptions = new HashMap<>();
|
||||||
|
|
||||||
|
@ -251,7 +252,7 @@ public class TargetAssignmentBuilderTest {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Prepare the expected subscription topic metadata.
|
// Prepare the expected subscription topic metadata.
|
||||||
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(metadataImage);
|
SubscribedTopicDescriberImpl subscribedTopicMetadata = new SubscribedTopicDescriberImpl(cooridnatorMetadataImage);
|
||||||
SubscriptionType subscriptionType = HOMOGENEOUS;
|
SubscriptionType subscriptionType = HOMOGENEOUS;
|
||||||
|
|
||||||
// Prepare the member assignments per topic partition.
|
// Prepare the member assignments per topic partition.
|
||||||
|
@ -278,7 +279,7 @@ public class TargetAssignmentBuilderTest {
|
||||||
.withSubscriptionType(subscriptionType)
|
.withSubscriptionType(subscriptionType)
|
||||||
.withTargetAssignment(targetAssignment)
|
.withTargetAssignment(targetAssignment)
|
||||||
.withInvertedTargetAssignment(invertedTargetAssignment)
|
.withInvertedTargetAssignment(invertedTargetAssignment)
|
||||||
.withMetadataImage(metadataImage)
|
.withMetadataImage(cooridnatorMetadataImage)
|
||||||
.withResolvedRegularExpressions(resolvedRegularExpressions);
|
.withResolvedRegularExpressions(resolvedRegularExpressions);
|
||||||
|
|
||||||
// Add the updated members or delete the deleted members.
|
// Add the updated members or delete the deleted members.
|
||||||
|
|
|
@ -17,8 +17,9 @@
|
||||||
package org.apache.kafka.coordinator.group.modern;
|
package org.apache.kafka.coordinator.group.modern;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.image.TopicsImage;
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -34,12 +35,12 @@ public class TopicIdsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTopicNamesCannotBeNull() {
|
public void testTopicNamesCannotBeNull() {
|
||||||
assertThrows(NullPointerException.class, () -> new TopicIds(null, TopicsImage.EMPTY));
|
assertThrows(NullPointerException.class, () -> new TopicIds(null, CoordinatorMetadataImage.EMPTY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTopicsImageCannotBeNull() {
|
public void testTopicsImageCannotBeNull() {
|
||||||
assertThrows(NullPointerException.class, () -> new TopicIds(Set.of(), (TopicsImage) null));
|
assertThrows(NullPointerException.class, () -> new TopicIds(Set.of(), (CoordinatorMetadataImage) null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -50,14 +51,14 @@ public class TopicIdsTest {
|
||||||
@Test
|
@Test
|
||||||
public void testSize() {
|
public void testSize() {
|
||||||
Set<String> topicNames = Set.of("foo", "bar", "baz");
|
Set<String> topicNames = Set.of("foo", "bar", "baz");
|
||||||
Set<Uuid> topicIds = new TopicIds(topicNames, TopicsImage.EMPTY);
|
Set<Uuid> topicIds = new TopicIds(topicNames, CoordinatorMetadataImage.EMPTY);
|
||||||
assertEquals(topicNames.size(), topicIds.size());
|
assertEquals(topicNames.size(), topicIds.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsEmpty() {
|
public void testIsEmpty() {
|
||||||
Set<String> topicNames = Set.of();
|
Set<String> topicNames = Set.of();
|
||||||
Set<Uuid> topicIds = new TopicIds(topicNames, TopicsImage.EMPTY);
|
Set<Uuid> topicIds = new TopicIds(topicNames, CoordinatorMetadataImage.EMPTY);
|
||||||
assertEquals(topicNames.size(), topicIds.size());
|
assertEquals(topicNames.size(), topicIds.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,14 +68,13 @@ public class TopicIdsTest {
|
||||||
Uuid barUuid = Uuid.randomUuid();
|
Uuid barUuid = Uuid.randomUuid();
|
||||||
Uuid bazUuid = Uuid.randomUuid();
|
Uuid bazUuid = Uuid.randomUuid();
|
||||||
Uuid quxUuid = Uuid.randomUuid();
|
Uuid quxUuid = Uuid.randomUuid();
|
||||||
TopicsImage topicsImage = new MetadataImageBuilder()
|
CoordinatorMetadataImage metadataImage = new KRaftCoordinatorMetadataImage(new MetadataImageBuilder()
|
||||||
.addTopic(fooUuid, "foo", 3)
|
.addTopic(fooUuid, "foo", 3)
|
||||||
.addTopic(barUuid, "bar", 3)
|
.addTopic(barUuid, "bar", 3)
|
||||||
.addTopic(bazUuid, "qux", 3)
|
.addTopic(bazUuid, "qux", 3)
|
||||||
.build()
|
.build());
|
||||||
.topics();
|
|
||||||
|
|
||||||
Set<Uuid> topicIds = new TopicIds(Set.of("foo", "bar", "baz"), topicsImage);
|
Set<Uuid> topicIds = new TopicIds(Set.of("foo", "bar", "baz"), metadataImage);
|
||||||
|
|
||||||
assertTrue(topicIds.contains(fooUuid));
|
assertTrue(topicIds.contains(fooUuid));
|
||||||
assertTrue(topicIds.contains(barUuid));
|
assertTrue(topicIds.contains(barUuid));
|
||||||
|
@ -88,15 +88,14 @@ public class TopicIdsTest {
|
||||||
Uuid barUuid = Uuid.randomUuid();
|
Uuid barUuid = Uuid.randomUuid();
|
||||||
Uuid bazUuid = Uuid.randomUuid();
|
Uuid bazUuid = Uuid.randomUuid();
|
||||||
Uuid quxUuid = Uuid.randomUuid();
|
Uuid quxUuid = Uuid.randomUuid();
|
||||||
TopicsImage topicsImage = new MetadataImageBuilder()
|
CoordinatorMetadataImage metadataImage = new KRaftCoordinatorMetadataImage(new MetadataImageBuilder()
|
||||||
.addTopic(fooUuid, "foo", 3)
|
.addTopic(fooUuid, "foo", 3)
|
||||||
.addTopic(barUuid, "bar", 3)
|
.addTopic(barUuid, "bar", 3)
|
||||||
.addTopic(bazUuid, "baz", 3)
|
.addTopic(bazUuid, "baz", 3)
|
||||||
.addTopic(quxUuid, "qux", 3)
|
.addTopic(quxUuid, "qux", 3)
|
||||||
.build()
|
.build());
|
||||||
.topics();
|
|
||||||
|
|
||||||
Set<Uuid> topicIds = new TopicIds(Set.of("foo", "bar", "baz", "qux"), topicsImage);
|
Set<Uuid> topicIds = new TopicIds(Set.of("foo", "bar", "baz", "qux"), metadataImage);
|
||||||
|
|
||||||
assertTrue(topicIds.contains(fooUuid));
|
assertTrue(topicIds.contains(fooUuid));
|
||||||
assertTrue(topicIds.contains(barUuid));
|
assertTrue(topicIds.contains(barUuid));
|
||||||
|
@ -112,14 +111,13 @@ public class TopicIdsTest {
|
||||||
Uuid barUuid = Uuid.randomUuid();
|
Uuid barUuid = Uuid.randomUuid();
|
||||||
Uuid bazUuid = Uuid.randomUuid();
|
Uuid bazUuid = Uuid.randomUuid();
|
||||||
Uuid quxUuid = Uuid.randomUuid();
|
Uuid quxUuid = Uuid.randomUuid();
|
||||||
TopicsImage topicsImage = new MetadataImageBuilder()
|
CoordinatorMetadataImage metadataImage = new KRaftCoordinatorMetadataImage(new MetadataImageBuilder()
|
||||||
.addTopic(fooUuid, "foo", 3)
|
.addTopic(fooUuid, "foo", 3)
|
||||||
.addTopic(barUuid, "bar", 3)
|
.addTopic(barUuid, "bar", 3)
|
||||||
.addTopic(bazUuid, "baz", 3)
|
.addTopic(bazUuid, "baz", 3)
|
||||||
.build()
|
.build());
|
||||||
.topics();
|
|
||||||
|
|
||||||
Set<Uuid> topicIds = new TopicIds(Set.of("foo", "bar", "baz", "qux"), topicsImage);
|
Set<Uuid> topicIds = new TopicIds(Set.of("foo", "bar", "baz", "qux"), metadataImage);
|
||||||
|
|
||||||
assertTrue(topicIds.contains(fooUuid));
|
assertTrue(topicIds.contains(fooUuid));
|
||||||
assertTrue(topicIds.contains(barUuid));
|
assertTrue(topicIds.contains(barUuid));
|
||||||
|
@ -134,15 +132,14 @@ public class TopicIdsTest {
|
||||||
Uuid barUuid = Uuid.randomUuid();
|
Uuid barUuid = Uuid.randomUuid();
|
||||||
Uuid bazUuid = Uuid.randomUuid();
|
Uuid bazUuid = Uuid.randomUuid();
|
||||||
Uuid quxUuid = Uuid.randomUuid();
|
Uuid quxUuid = Uuid.randomUuid();
|
||||||
TopicsImage topicsImage = new MetadataImageBuilder()
|
CoordinatorMetadataImage metadataImage = new KRaftCoordinatorMetadataImage(new MetadataImageBuilder()
|
||||||
.addTopic(fooUuid, "foo", 3)
|
.addTopic(fooUuid, "foo", 3)
|
||||||
.addTopic(barUuid, "bar", 3)
|
.addTopic(barUuid, "bar", 3)
|
||||||
.addTopic(bazUuid, "baz", 3)
|
.addTopic(bazUuid, "baz", 3)
|
||||||
.addTopic(quxUuid, "qux", 3)
|
.addTopic(quxUuid, "qux", 3)
|
||||||
.build()
|
.build());
|
||||||
.topics();
|
|
||||||
|
|
||||||
Set<Uuid> topicIds = new TopicIds(Set.of("foo", "bar", "baz", "qux"), topicsImage);
|
Set<Uuid> topicIds = new TopicIds(Set.of("foo", "bar", "baz", "qux"), metadataImage);
|
||||||
Set<Uuid> expectedIds = Set.of(fooUuid, barUuid, bazUuid, quxUuid);
|
Set<Uuid> expectedIds = Set.of(fooUuid, barUuid, bazUuid, quxUuid);
|
||||||
Set<Uuid> actualIds = new HashSet<>(topicIds);
|
Set<Uuid> actualIds = new HashSet<>(topicIds);
|
||||||
|
|
||||||
|
@ -157,15 +154,14 @@ public class TopicIdsTest {
|
||||||
Uuid barUuid = Uuid.randomUuid();
|
Uuid barUuid = Uuid.randomUuid();
|
||||||
Uuid bazUuid = Uuid.randomUuid();
|
Uuid bazUuid = Uuid.randomUuid();
|
||||||
Uuid qux = Uuid.randomUuid();
|
Uuid qux = Uuid.randomUuid();
|
||||||
TopicsImage topicsImage = new MetadataImageBuilder()
|
CoordinatorMetadataImage metadataImage = new KRaftCoordinatorMetadataImage(new MetadataImageBuilder()
|
||||||
.addTopic(fooUuid, "foo", 3)
|
.addTopic(fooUuid, "foo", 3)
|
||||||
.addTopic(barUuid, "bar", 3)
|
.addTopic(barUuid, "bar", 3)
|
||||||
.addTopic(bazUuid, "baz", 3)
|
.addTopic(bazUuid, "baz", 3)
|
||||||
.addTopic(qux, "qux", 3)
|
.addTopic(qux, "qux", 3)
|
||||||
.build()
|
.build());
|
||||||
.topics();
|
|
||||||
|
|
||||||
Set<Uuid> topicIds = new TopicIds(Set.of("foo", "bar", "baz", "quux"), topicsImage);
|
Set<Uuid> topicIds = new TopicIds(Set.of("foo", "bar", "baz", "quux"), metadataImage);
|
||||||
Set<Uuid> expectedIds = Set.of(fooUuid, barUuid, bazUuid);
|
Set<Uuid> expectedIds = Set.of(fooUuid, barUuid, bazUuid);
|
||||||
Set<Uuid> actualIds = new HashSet<>(topicIds);
|
Set<Uuid> actualIds = new HashSet<>(topicIds);
|
||||||
|
|
||||||
|
@ -175,19 +171,12 @@ public class TopicIdsTest {
|
||||||
@Test
|
@Test
|
||||||
public void testEquals() {
|
public void testEquals() {
|
||||||
Uuid topicId = Uuid.randomUuid();
|
Uuid topicId = Uuid.randomUuid();
|
||||||
TopicIds topicIds1 = new TopicIds(Set.of("topic"),
|
KRaftCoordinatorMetadataImage metadataImage = new KRaftCoordinatorMetadataImage(new MetadataImageBuilder()
|
||||||
new MetadataImageBuilder()
|
|
||||||
.addTopic(topicId, "topicId", 3)
|
.addTopic(topicId, "topicId", 3)
|
||||||
.build()
|
.build());
|
||||||
.topics()
|
|
||||||
);
|
|
||||||
|
|
||||||
TopicIds topicIds2 = new TopicIds(Set.of("topic"),
|
TopicIds topicIds1 = new TopicIds(Set.of("topic"), metadataImage);
|
||||||
new MetadataImageBuilder()
|
TopicIds topicIds2 = new TopicIds(Set.of("topic"), metadataImage);
|
||||||
.addTopic(topicId, "topicId", 3)
|
|
||||||
.build()
|
|
||||||
.topics()
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEquals(topicIds1, topicIds2);
|
assertEquals(topicIds1, topicIds2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,8 @@ package org.apache.kafka.coordinator.group.modern.consumer;
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.common.message.ConsumerGroupDescribeResponseData;
|
import org.apache.kafka.common.message.ConsumerGroupDescribeResponseData;
|
||||||
import org.apache.kafka.common.message.JoinGroupRequestData;
|
import org.apache.kafka.common.message.JoinGroupRequestData;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.generated.ConsumerGroupCurrentMemberAssignmentValue;
|
import org.apache.kafka.coordinator.group.generated.ConsumerGroupCurrentMemberAssignmentValue;
|
||||||
import org.apache.kafka.coordinator.group.generated.ConsumerGroupMemberMetadataValue;
|
import org.apache.kafka.coordinator.group.generated.ConsumerGroupMemberMetadataValue;
|
||||||
import org.apache.kafka.coordinator.group.modern.Assignment;
|
import org.apache.kafka.coordinator.group.modern.Assignment;
|
||||||
|
@ -292,7 +293,7 @@ public class ConsumerGroupMemberTest {
|
||||||
.setSupportedProtocols(toClassicProtocolCollection("range")) : null)
|
.setSupportedProtocols(toClassicProtocolCollection("range")) : null)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ConsumerGroupDescribeResponseData.Member actual = member.asConsumerGroupDescribeMember(targetAssignment, metadataImage.topics());
|
ConsumerGroupDescribeResponseData.Member actual = member.asConsumerGroupDescribeMember(targetAssignment, new KRaftCoordinatorMetadataImage(metadataImage));
|
||||||
ConsumerGroupDescribeResponseData.Member expected = new ConsumerGroupDescribeResponseData.Member()
|
ConsumerGroupDescribeResponseData.Member expected = new ConsumerGroupDescribeResponseData.Member()
|
||||||
.setMemberId(memberId)
|
.setMemberId(memberId)
|
||||||
.setMemberEpoch(epoch)
|
.setMemberEpoch(epoch)
|
||||||
|
@ -330,7 +331,7 @@ public class ConsumerGroupMemberTest {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ConsumerGroupDescribeResponseData.Member consumerGroupDescribeMember = member.asConsumerGroupDescribeMember(
|
ConsumerGroupDescribeResponseData.Member consumerGroupDescribeMember = member.asConsumerGroupDescribeMember(
|
||||||
null, new MetadataImageBuilder().build().topics());
|
null, new KRaftCoordinatorMetadataImage(new MetadataImageBuilder().build()));
|
||||||
|
|
||||||
assertEquals(new ConsumerGroupDescribeResponseData.Assignment(), consumerGroupDescribeMember.targetAssignment());
|
assertEquals(new ConsumerGroupDescribeResponseData.Assignment(), consumerGroupDescribeMember.targetAssignment());
|
||||||
}
|
}
|
||||||
|
@ -351,9 +352,9 @@ public class ConsumerGroupMemberTest {
|
||||||
.setSubscribedTopicRegex("")
|
.setSubscribedTopicRegex("")
|
||||||
.setMemberType((byte) 1);
|
.setMemberType((byte) 1);
|
||||||
ConsumerGroupDescribeResponseData.Member actual = member.asConsumerGroupDescribeMember(null,
|
ConsumerGroupDescribeResponseData.Member actual = member.asConsumerGroupDescribeMember(null,
|
||||||
new MetadataImageBuilder()
|
new KRaftCoordinatorMetadataImage(new MetadataImageBuilder()
|
||||||
.addTopic(Uuid.randomUuid(), "foo", 3)
|
.addTopic(Uuid.randomUuid(), "foo", 3)
|
||||||
.build().topics()
|
.build())
|
||||||
);
|
);
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,12 @@ import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.MockTime;
|
import org.apache.kafka.common.utils.MockTime;
|
||||||
import org.apache.kafka.common.utils.Utils;
|
import org.apache.kafka.common.utils.Utils;
|
||||||
import org.apache.kafka.common.utils.annotation.ApiKeyVersionsSource;
|
import org.apache.kafka.common.utils.annotation.ApiKeyVersionsSource;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.Group;
|
import org.apache.kafka.coordinator.group.Group;
|
||||||
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
|
||||||
import org.apache.kafka.coordinator.group.OffsetAndMetadata;
|
import org.apache.kafka.coordinator.group.OffsetAndMetadata;
|
||||||
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
||||||
import org.apache.kafka.coordinator.group.OffsetExpirationConditionImpl;
|
import org.apache.kafka.coordinator.group.OffsetExpirationConditionImpl;
|
||||||
|
@ -48,7 +50,6 @@ import org.apache.kafka.coordinator.group.modern.Assignment;
|
||||||
import org.apache.kafka.coordinator.group.modern.MemberState;
|
import org.apache.kafka.coordinator.group.modern.MemberState;
|
||||||
import org.apache.kafka.coordinator.group.modern.ModernGroup;
|
import org.apache.kafka.coordinator.group.modern.ModernGroup;
|
||||||
import org.apache.kafka.coordinator.group.modern.SubscriptionCount;
|
import org.apache.kafka.coordinator.group.modern.SubscriptionCount;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.timeline.SnapshotRegistry;
|
import org.apache.kafka.timeline.SnapshotRegistry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -1062,7 +1063,7 @@ public class ConsumerGroupTest {
|
||||||
.setMemberType((byte) 1)
|
.setMemberType((byte) 1)
|
||||||
));
|
));
|
||||||
ConsumerGroupDescribeResponseData.DescribedGroup actual = group.asDescribedGroup(1, "",
|
ConsumerGroupDescribeResponseData.DescribedGroup actual = group.asDescribedGroup(1, "",
|
||||||
new MetadataImageBuilder().build().topics());
|
new KRaftCoordinatorMetadataImage(new MetadataImageBuilder().build()));
|
||||||
|
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
@ -1261,11 +1262,11 @@ public class ConsumerGroupTest {
|
||||||
Uuid barTopicId = Uuid.randomUuid();
|
Uuid barTopicId = Uuid.randomUuid();
|
||||||
String barTopicName = "bar";
|
String barTopicName = "bar";
|
||||||
|
|
||||||
MetadataImage metadataImage = new MetadataImageBuilder()
|
CoordinatorMetadataImage metadataImage = new MetadataImageBuilder()
|
||||||
.addTopic(fooTopicId, fooTopicName, 1)
|
.addTopic(fooTopicId, fooTopicName, 1)
|
||||||
.addTopic(barTopicId, barTopicName, 1)
|
.addTopic(barTopicId, barTopicName, 1)
|
||||||
.addRacks()
|
.addRacks()
|
||||||
.build();
|
.buildCoordinatorMetadataImage();
|
||||||
|
|
||||||
ClassicGroup classicGroup = new ClassicGroup(
|
ClassicGroup classicGroup = new ClassicGroup(
|
||||||
logContext,
|
logContext,
|
||||||
|
@ -2040,11 +2041,11 @@ public class ConsumerGroupTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComputeMetadataHash() {
|
public void testComputeMetadataHash() {
|
||||||
MetadataImage metadataImage = new MetadataImageBuilder()
|
CoordinatorMetadataImage metadataImage = new MetadataImageBuilder()
|
||||||
.addTopic(Uuid.randomUuid(), "foo", 1)
|
.addTopic(Uuid.randomUuid(), "foo", 1)
|
||||||
.addTopic(Uuid.randomUuid(), "bar", 1)
|
.addTopic(Uuid.randomUuid(), "bar", 1)
|
||||||
.addRacks()
|
.addRacks()
|
||||||
.build();
|
.buildCoordinatorMetadataImage();
|
||||||
Map<String, Long> cache = new HashMap<>();
|
Map<String, Long> cache = new HashMap<>();
|
||||||
assertEquals(
|
assertEquals(
|
||||||
computeGroupHash(Map.of(
|
computeGroupHash(Map.of(
|
||||||
|
@ -2084,11 +2085,11 @@ public class ConsumerGroupTest {
|
||||||
"bar", new SubscriptionCount(1, 0)
|
"bar", new SubscriptionCount(1, 0)
|
||||||
),
|
),
|
||||||
cache,
|
cache,
|
||||||
new MetadataImageBuilder()
|
new KRaftCoordinatorMetadataImage(new MetadataImageBuilder()
|
||||||
.addTopic(Uuid.randomUuid(), "foo", 1)
|
.addTopic(Uuid.randomUuid(), "foo", 1)
|
||||||
.addTopic(Uuid.randomUuid(), "bar", 1)
|
.addTopic(Uuid.randomUuid(), "bar", 1)
|
||||||
.addRacks()
|
.addRacks()
|
||||||
.build()
|
.build())
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -2120,11 +2121,11 @@ public class ConsumerGroupTest {
|
||||||
"bar", new SubscriptionCount(1, 0)
|
"bar", new SubscriptionCount(1, 0)
|
||||||
),
|
),
|
||||||
cache,
|
cache,
|
||||||
new MetadataImageBuilder()
|
new KRaftCoordinatorMetadataImage(new MetadataImageBuilder()
|
||||||
.addTopic(Uuid.randomUuid(), "foo", 1)
|
.addTopic(Uuid.randomUuid(), "foo", 1)
|
||||||
.addTopic(Uuid.randomUuid(), "bar", 1)
|
.addTopic(Uuid.randomUuid(), "bar", 1)
|
||||||
.addRacks()
|
.addRacks()
|
||||||
.build()
|
.build())
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
import org.apache.kafka.coordinator.group.GroupCoordinatorRecordHelpers;
|
||||||
import org.apache.kafka.coordinator.group.modern.Assignment;
|
import org.apache.kafka.coordinator.group.modern.Assignment;
|
||||||
import org.apache.kafka.image.TopicsImage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -62,7 +61,7 @@ public class ShareGroupBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CoordinatorRecord> build(TopicsImage topicsImage) {
|
public List<CoordinatorRecord> build() {
|
||||||
List<CoordinatorRecord> records = new ArrayList<>();
|
List<CoordinatorRecord> records = new ArrayList<>();
|
||||||
|
|
||||||
// Add subscription records for members.
|
// Add subscription records for members.
|
||||||
|
|
|
@ -18,7 +18,8 @@ package org.apache.kafka.coordinator.group.modern.share;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.common.message.ShareGroupDescribeResponseData;
|
import org.apache.kafka.common.message.ShareGroupDescribeResponseData;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.generated.ShareGroupMemberMetadataValue;
|
import org.apache.kafka.coordinator.group.generated.ShareGroupMemberMetadataValue;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
import org.apache.kafka.image.MetadataImage;
|
||||||
|
|
||||||
|
@ -169,7 +170,7 @@ public class ShareGroupMemberTest {
|
||||||
mkTopicAssignment(topicId1, 0, 1, 2)))
|
mkTopicAssignment(topicId1, 0, 1, 2)))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ShareGroupDescribeResponseData.Member actual = member.asShareGroupDescribeMember(metadataImage.topics());
|
ShareGroupDescribeResponseData.Member actual = member.asShareGroupDescribeMember(new KRaftCoordinatorMetadataImage(metadataImage));
|
||||||
ShareGroupDescribeResponseData.Member expected = new ShareGroupDescribeResponseData.Member()
|
ShareGroupDescribeResponseData.Member expected = new ShareGroupDescribeResponseData.Member()
|
||||||
.setMemberId(memberId)
|
.setMemberId(memberId)
|
||||||
.setMemberEpoch(epoch)
|
.setMemberEpoch(epoch)
|
||||||
|
|
|
@ -25,8 +25,9 @@ import org.apache.kafka.common.protocol.ApiKeys;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.MockTime;
|
import org.apache.kafka.common.utils.MockTime;
|
||||||
import org.apache.kafka.common.utils.annotation.ApiKeyVersionsSource;
|
import org.apache.kafka.common.utils.annotation.ApiKeyVersionsSource;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.Group;
|
import org.apache.kafka.coordinator.group.Group;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
|
||||||
import org.apache.kafka.coordinator.group.modern.Assignment;
|
import org.apache.kafka.coordinator.group.modern.Assignment;
|
||||||
import org.apache.kafka.coordinator.group.modern.MemberState;
|
import org.apache.kafka.coordinator.group.modern.MemberState;
|
||||||
import org.apache.kafka.coordinator.group.modern.share.ShareGroup.ShareGroupState;
|
import org.apache.kafka.coordinator.group.modern.share.ShareGroup.ShareGroupState;
|
||||||
|
@ -462,7 +463,7 @@ public class ShareGroupTest {
|
||||||
new ShareGroupDescribeResponseData.Member().setMemberId("member2")
|
new ShareGroupDescribeResponseData.Member().setMemberId("member2")
|
||||||
));
|
));
|
||||||
ShareGroupDescribeResponseData.DescribedGroup actual = shareGroup.asDescribedGroup(1, "assignorName",
|
ShareGroupDescribeResponseData.DescribedGroup actual = shareGroup.asDescribedGroup(1, "assignorName",
|
||||||
new MetadataImageBuilder().build().topics());
|
new KRaftCoordinatorMetadataImage(new MetadataImageBuilder().build()));
|
||||||
|
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,8 @@ import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.MockTime;
|
import org.apache.kafka.common.utils.MockTime;
|
||||||
import org.apache.kafka.common.utils.annotation.ApiKeyVersionsSource;
|
import org.apache.kafka.common.utils.annotation.ApiKeyVersionsSource;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.OffsetAndMetadata;
|
import org.apache.kafka.coordinator.group.OffsetAndMetadata;
|
||||||
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
import org.apache.kafka.coordinator.group.OffsetExpirationCondition;
|
||||||
import org.apache.kafka.coordinator.group.OffsetExpirationConditionImpl;
|
import org.apache.kafka.coordinator.group.OffsetExpirationConditionImpl;
|
||||||
|
@ -921,7 +922,7 @@ public class StreamsGroupTest {
|
||||||
StreamsTopology topology = mock(StreamsTopology.class);
|
StreamsTopology topology = mock(StreamsTopology.class);
|
||||||
when(topology.requiredTopics()).thenReturn(Set.of("topic1"));
|
when(topology.requiredTopics()).thenReturn(Set.of("topic1"));
|
||||||
|
|
||||||
long metadataHash = streamsGroup.computeMetadataHash(metadataImage, new HashMap<>(), topology);
|
long metadataHash = streamsGroup.computeMetadataHash(new KRaftCoordinatorMetadataImage(metadataImage), new HashMap<>(), topology);
|
||||||
// The metadata hash means no topic.
|
// The metadata hash means no topic.
|
||||||
assertNotEquals(0, metadataHash);
|
assertNotEquals(0, metadataHash);
|
||||||
}
|
}
|
||||||
|
@ -988,7 +989,7 @@ public class StreamsGroupTest {
|
||||||
.addTopic(Uuid.randomUuid(), "test-topic2", 1)
|
.addTopic(Uuid.randomUuid(), "test-topic2", 1)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
streamsGroup.setConfiguredTopology(InternalTopicManager.configureTopics(logContext, 0, topology, metadataImage.topics()));
|
streamsGroup.setConfiguredTopology(InternalTopicManager.configureTopics(logContext, 0, topology, new KRaftCoordinatorMetadataImage(metadataImage)));
|
||||||
|
|
||||||
assertTrue(streamsGroup.isSubscribedToTopic("test-topic1"));
|
assertTrue(streamsGroup.isSubscribedToTopic("test-topic1"));
|
||||||
assertTrue(streamsGroup.isSubscribedToTopic("test-topic2"));
|
assertTrue(streamsGroup.isSubscribedToTopic("test-topic2"));
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
package org.apache.kafka.coordinator.group.streams;
|
package org.apache.kafka.coordinator.group.streams;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.generated.StreamsGroupMemberMetadataValue;
|
import org.apache.kafka.coordinator.group.generated.StreamsGroupMemberMetadataValue;
|
||||||
import org.apache.kafka.coordinator.group.streams.TaskAssignmentTestUtil.TaskRole;
|
import org.apache.kafka.coordinator.group.streams.TaskAssignmentTestUtil.TaskRole;
|
||||||
import org.apache.kafka.coordinator.group.streams.assignor.AssignmentMemberSpec;
|
import org.apache.kafka.coordinator.group.streams.assignor.AssignmentMemberSpec;
|
||||||
|
@ -28,7 +30,6 @@ import org.apache.kafka.coordinator.group.streams.assignor.MemberAssignment;
|
||||||
import org.apache.kafka.coordinator.group.streams.assignor.TaskAssignor;
|
import org.apache.kafka.coordinator.group.streams.assignor.TaskAssignor;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredSubtopology;
|
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredSubtopology;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredTopology;
|
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredTopology;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
@ -801,7 +802,7 @@ public class TargetAssignmentBuilderTest {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
MetadataImage metadataImage = topicsImageBuilder.build();
|
CoordinatorMetadataImage metadataImage = new KRaftCoordinatorMetadataImage(topicsImageBuilder.build());
|
||||||
|
|
||||||
// Prepare the expected topology metadata.
|
// Prepare the expected topology metadata.
|
||||||
TopologyMetadata topologyMetadata = new TopologyMetadata(metadataImage, subtopologies);
|
TopologyMetadata topologyMetadata = new TopologyMetadata(metadataImage, subtopologies);
|
||||||
|
|
|
@ -17,10 +17,11 @@
|
||||||
package org.apache.kafka.coordinator.group.streams;
|
package org.apache.kafka.coordinator.group.streams;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredInternalTopic;
|
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredInternalTopic;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredSubtopology;
|
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredSubtopology;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -41,16 +42,16 @@ import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
class TopologyMetadataTest {
|
class TopologyMetadataTest {
|
||||||
|
|
||||||
private MetadataImage metadataImage;
|
private CoordinatorMetadataImage metadataImage;
|
||||||
private SortedMap<String, ConfiguredSubtopology> subtopologyMap;
|
private SortedMap<String, ConfiguredSubtopology> subtopologyMap;
|
||||||
private TopologyMetadata topologyMetadata;
|
private TopologyMetadata topologyMetadata;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
metadataImage = new MetadataImageBuilder()
|
metadataImage = new KRaftCoordinatorMetadataImage(new MetadataImageBuilder()
|
||||||
.addTopic(Uuid.randomUuid(), "source_topic", 3)
|
.addTopic(Uuid.randomUuid(), "source_topic", 3)
|
||||||
.addTopic(Uuid.randomUuid(), "repartition_source_topic", 4)
|
.addTopic(Uuid.randomUuid(), "repartition_source_topic", 4)
|
||||||
.build();
|
.build());
|
||||||
subtopologyMap = new TreeMap<>();
|
subtopologyMap = new TreeMap<>();
|
||||||
topologyMetadata = new TopologyMetadata(metadataImage, subtopologyMap);
|
topologyMetadata = new TopologyMetadata(metadataImage, subtopologyMap);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,8 @@ package org.apache.kafka.coordinator.group.streams.topics;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.common.message.StreamsGroupHeartbeatResponseData;
|
import org.apache.kafka.common.message.StreamsGroupHeartbeatResponseData;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsGroup;
|
import org.apache.kafka.coordinator.group.streams.StreamsGroup;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsGroupMember;
|
import org.apache.kafka.coordinator.group.streams.StreamsGroupMember;
|
||||||
import org.apache.kafka.coordinator.group.streams.TasksTuple;
|
import org.apache.kafka.coordinator.group.streams.TasksTuple;
|
||||||
|
@ -97,7 +98,7 @@ class EndpointToPartitionsManagerTest {
|
||||||
when(configuredTopology.subtopologies()).thenReturn(Optional.of(configuredSubtopologyMap));
|
when(configuredTopology.subtopologies()).thenReturn(Optional.of(configuredSubtopologyMap));
|
||||||
|
|
||||||
StreamsGroupHeartbeatResponseData.EndpointToPartitions result =
|
StreamsGroupHeartbeatResponseData.EndpointToPartitions result =
|
||||||
EndpointToPartitionsManager.endpointToPartitions(streamsGroupMember, responseEndpoint, streamsGroup, metadataImage);
|
EndpointToPartitionsManager.endpointToPartitions(streamsGroupMember, responseEndpoint, streamsGroup, new KRaftCoordinatorMetadataImage(metadataImage));
|
||||||
|
|
||||||
assertEquals(responseEndpoint, result.userEndpoint());
|
assertEquals(responseEndpoint, result.userEndpoint());
|
||||||
assertEquals(1, result.activePartitions().size());
|
assertEquals(1, result.activePartitions().size());
|
||||||
|
@ -137,7 +138,7 @@ class EndpointToPartitionsManagerTest {
|
||||||
configuredSubtopologyOneMap.put("0", configuredSubtopologyOne);
|
configuredSubtopologyOneMap.put("0", configuredSubtopologyOne);
|
||||||
when(configuredTopology.subtopologies()).thenReturn(Optional.of(configuredSubtopologyOneMap));
|
when(configuredTopology.subtopologies()).thenReturn(Optional.of(configuredSubtopologyOneMap));
|
||||||
|
|
||||||
StreamsGroupHeartbeatResponseData.EndpointToPartitions result = EndpointToPartitionsManager.endpointToPartitions(streamsGroupMember, responseEndpoint, streamsGroup, metadataImage);
|
StreamsGroupHeartbeatResponseData.EndpointToPartitions result = EndpointToPartitionsManager.endpointToPartitions(streamsGroupMember, responseEndpoint, streamsGroup, new KRaftCoordinatorMetadataImage(metadataImage));
|
||||||
|
|
||||||
assertEquals(responseEndpoint, result.userEndpoint());
|
assertEquals(responseEndpoint, result.userEndpoint());
|
||||||
assertEquals(2, result.activePartitions().size());
|
assertEquals(2, result.activePartitions().size());
|
||||||
|
|
|
@ -22,7 +22,8 @@ import org.apache.kafka.common.message.CreateTopicsRequestData.CreatableTopicCon
|
||||||
import org.apache.kafka.common.message.CreateTopicsRequestData.CreatableTopicConfigCollection;
|
import org.apache.kafka.common.message.CreateTopicsRequestData.CreatableTopicConfigCollection;
|
||||||
import org.apache.kafka.common.requests.StreamsGroupHeartbeatResponse.Status;
|
import org.apache.kafka.common.requests.StreamsGroupHeartbeatResponse.Status;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.coordinator.group.MetadataImageBuilder;
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.MetadataImageBuilder;
|
||||||
import org.apache.kafka.coordinator.group.generated.StreamsGroupTopologyValue;
|
import org.apache.kafka.coordinator.group.generated.StreamsGroupTopologyValue;
|
||||||
import org.apache.kafka.coordinator.group.generated.StreamsGroupTopologyValue.Subtopology;
|
import org.apache.kafka.coordinator.group.generated.StreamsGroupTopologyValue.Subtopology;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsTopology;
|
import org.apache.kafka.coordinator.group.streams.StreamsTopology;
|
||||||
|
@ -60,7 +61,7 @@ class InternalTopicManagerTest {
|
||||||
// SOURCE_TOPIC_2 is missing from topicMetadata
|
// SOURCE_TOPIC_2 is missing from topicMetadata
|
||||||
StreamsTopology topology = makeTestTopology();
|
StreamsTopology topology = makeTestTopology();
|
||||||
|
|
||||||
final ConfiguredTopology configuredTopology = InternalTopicManager.configureTopics(new LogContext(), 0, topology, metadataImage.topics());
|
final ConfiguredTopology configuredTopology = InternalTopicManager.configureTopics(new LogContext(), 0, topology, new KRaftCoordinatorMetadataImage(metadataImage));
|
||||||
|
|
||||||
assertEquals(Optional.empty(), configuredTopology.subtopologies());
|
assertEquals(Optional.empty(), configuredTopology.subtopologies());
|
||||||
assertTrue(configuredTopology.topicConfigurationException().isPresent());
|
assertTrue(configuredTopology.topicConfigurationException().isPresent());
|
||||||
|
@ -77,7 +78,7 @@ class InternalTopicManagerTest {
|
||||||
.build();
|
.build();
|
||||||
StreamsTopology topology = makeTestTopology();
|
StreamsTopology topology = makeTestTopology();
|
||||||
|
|
||||||
ConfiguredTopology configuredTopology = InternalTopicManager.configureTopics(new LogContext(), 0, topology, metadataImage.topics());
|
ConfiguredTopology configuredTopology = InternalTopicManager.configureTopics(new LogContext(), 0, topology, new KRaftCoordinatorMetadataImage(metadataImage));
|
||||||
final Map<String, CreatableTopic> internalTopicsToBeCreated = configuredTopology.internalTopicsToBeCreated();
|
final Map<String, CreatableTopic> internalTopicsToBeCreated = configuredTopology.internalTopicsToBeCreated();
|
||||||
|
|
||||||
assertEquals(2, internalTopicsToBeCreated.size());
|
assertEquals(2, internalTopicsToBeCreated.size());
|
||||||
|
|
|
@ -19,6 +19,8 @@ package org.apache.kafka.jmh.assignor;
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.common.metadata.PartitionRecord;
|
import org.apache.kafka.common.metadata.PartitionRecord;
|
||||||
import org.apache.kafka.common.metadata.TopicRecord;
|
import org.apache.kafka.common.metadata.TopicRecord;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
||||||
|
@ -94,7 +96,7 @@ public class AssignorBenchmarkUtils {
|
||||||
* @return A TopicsImage containing the topic ids, names and partition counts from the
|
* @return A TopicsImage containing the topic ids, names and partition counts from the
|
||||||
* subscription metadata.
|
* subscription metadata.
|
||||||
*/
|
*/
|
||||||
public static MetadataImage createMetadataImage(
|
public static CoordinatorMetadataImage createMetadataImage(
|
||||||
List<String> allTopicNames,
|
List<String> allTopicNames,
|
||||||
int partitionsPerTopic
|
int partitionsPerTopic
|
||||||
) {
|
) {
|
||||||
|
@ -109,7 +111,7 @@ public class AssignorBenchmarkUtils {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return delta.apply(MetadataProvenance.EMPTY);
|
return new KRaftCoordinatorMetadataImage(delta.apply(MetadataProvenance.EMPTY));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.apache.kafka.jmh.assignor;
|
package org.apache.kafka.jmh.assignor;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
||||||
|
@ -32,7 +33,6 @@ import org.apache.kafka.coordinator.group.modern.MemberSubscriptionAndAssignment
|
||||||
import org.apache.kafka.coordinator.group.modern.SubscribedTopicDescriberImpl;
|
import org.apache.kafka.coordinator.group.modern.SubscribedTopicDescriberImpl;
|
||||||
import org.apache.kafka.coordinator.group.modern.TopicIds;
|
import org.apache.kafka.coordinator.group.modern.TopicIds;
|
||||||
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroupMember;
|
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroupMember;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
@ -122,7 +122,7 @@ public class ServerSideAssignorBenchmark {
|
||||||
|
|
||||||
private List<String> allTopicNames = List.of();
|
private List<String> allTopicNames = List.of();
|
||||||
|
|
||||||
private MetadataImage metadataImage = MetadataImage.EMPTY;
|
private CoordinatorMetadataImage metadataImage = CoordinatorMetadataImage.EMPTY;
|
||||||
|
|
||||||
private TopicIds.TopicResolver topicResolver;
|
private TopicIds.TopicResolver topicResolver;
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ public class ServerSideAssignorBenchmark {
|
||||||
int partitionsPerTopic = (memberCount * partitionsToMemberRatio) / topicCount;
|
int partitionsPerTopic = (memberCount * partitionsToMemberRatio) / topicCount;
|
||||||
|
|
||||||
metadataImage = AssignorBenchmarkUtils.createMetadataImage(allTopicNames, partitionsPerTopic);
|
metadataImage = AssignorBenchmarkUtils.createMetadataImage(allTopicNames, partitionsPerTopic);
|
||||||
topicResolver = new TopicIds.CachedTopicResolver(metadataImage.topics());
|
topicResolver = new TopicIds.CachedTopicResolver(metadataImage);
|
||||||
|
|
||||||
subscribedTopicDescriber = new SubscribedTopicDescriberImpl(metadataImage);
|
subscribedTopicDescriber = new SubscribedTopicDescriberImpl(metadataImage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.apache.kafka.jmh.assignor;
|
package org.apache.kafka.jmh.assignor;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
||||||
|
@ -31,7 +32,6 @@ import org.apache.kafka.coordinator.group.modern.MemberSubscriptionAndAssignment
|
||||||
import org.apache.kafka.coordinator.group.modern.SubscribedTopicDescriberImpl;
|
import org.apache.kafka.coordinator.group.modern.SubscribedTopicDescriberImpl;
|
||||||
import org.apache.kafka.coordinator.group.modern.TopicIds;
|
import org.apache.kafka.coordinator.group.modern.TopicIds;
|
||||||
import org.apache.kafka.coordinator.group.modern.share.ShareGroupMember;
|
import org.apache.kafka.coordinator.group.modern.share.ShareGroupMember;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
@ -136,8 +136,8 @@ public class ShareGroupAssignorBenchmark {
|
||||||
private void setupTopics() {
|
private void setupTopics() {
|
||||||
allTopicNames = AssignorBenchmarkUtils.createTopicNames(topicCount);
|
allTopicNames = AssignorBenchmarkUtils.createTopicNames(topicCount);
|
||||||
|
|
||||||
MetadataImage metadataImage = AssignorBenchmarkUtils.createMetadataImage(allTopicNames, partitionCount);
|
CoordinatorMetadataImage metadataImage = AssignorBenchmarkUtils.createMetadataImage(allTopicNames, partitionCount);
|
||||||
topicResolver = new TopicIds.CachedTopicResolver(metadataImage.topics());
|
topicResolver = new TopicIds.CachedTopicResolver(metadataImage);
|
||||||
|
|
||||||
subscribedTopicDescriber = new SubscribedTopicDescriberImpl(metadataImage);
|
subscribedTopicDescriber = new SubscribedTopicDescriberImpl(metadataImage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.kafka.jmh.assignor;
|
package org.apache.kafka.jmh.assignor;
|
||||||
|
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.streams.StreamsGroupMember;
|
import org.apache.kafka.coordinator.group.streams.StreamsGroupMember;
|
||||||
import org.apache.kafka.coordinator.group.streams.TopologyMetadata;
|
import org.apache.kafka.coordinator.group.streams.TopologyMetadata;
|
||||||
import org.apache.kafka.coordinator.group.streams.assignor.AssignmentMemberSpec;
|
import org.apache.kafka.coordinator.group.streams.assignor.AssignmentMemberSpec;
|
||||||
|
@ -27,7 +28,6 @@ import org.apache.kafka.coordinator.group.streams.assignor.StickyTaskAssignor;
|
||||||
import org.apache.kafka.coordinator.group.streams.assignor.TaskAssignor;
|
import org.apache.kafka.coordinator.group.streams.assignor.TaskAssignor;
|
||||||
import org.apache.kafka.coordinator.group.streams.assignor.TopologyDescriber;
|
import org.apache.kafka.coordinator.group.streams.assignor.TopologyDescriber;
|
||||||
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredSubtopology;
|
import org.apache.kafka.coordinator.group.streams.topics.ConfiguredSubtopology;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
@ -100,7 +100,7 @@ public class StreamsStickyAssignorBenchmark {
|
||||||
|
|
||||||
SortedMap<String, ConfiguredSubtopology> subtopologyMap = StreamsAssignorBenchmarkUtils.createSubtopologyMap(partitionCount, allTopicNames);
|
SortedMap<String, ConfiguredSubtopology> subtopologyMap = StreamsAssignorBenchmarkUtils.createSubtopologyMap(partitionCount, allTopicNames);
|
||||||
|
|
||||||
MetadataImage metadataImage = AssignorBenchmarkUtils.createMetadataImage(allTopicNames, partitionCount);
|
CoordinatorMetadataImage metadataImage = AssignorBenchmarkUtils.createMetadataImage(allTopicNames, partitionCount);
|
||||||
|
|
||||||
topologyDescriber = new TopologyMetadata(metadataImage, subtopologyMap);
|
topologyDescriber = new TopologyMetadata(metadataImage, subtopologyMap);
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.apache.kafka.jmh.assignor;
|
package org.apache.kafka.jmh.assignor;
|
||||||
|
|
||||||
import org.apache.kafka.common.Uuid;
|
import org.apache.kafka.common.Uuid;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupAssignment;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
import org.apache.kafka.coordinator.group.api.assignor.GroupSpec;
|
||||||
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
import org.apache.kafka.coordinator.group.api.assignor.MemberAssignment;
|
||||||
|
@ -29,7 +30,6 @@ import org.apache.kafka.coordinator.group.modern.SubscribedTopicDescriberImpl;
|
||||||
import org.apache.kafka.coordinator.group.modern.TargetAssignmentBuilder;
|
import org.apache.kafka.coordinator.group.modern.TargetAssignmentBuilder;
|
||||||
import org.apache.kafka.coordinator.group.modern.TopicIds;
|
import org.apache.kafka.coordinator.group.modern.TopicIds;
|
||||||
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroupMember;
|
import org.apache.kafka.coordinator.group.modern.consumer.ConsumerGroupMember;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
@ -91,7 +91,7 @@ public class TargetAssignmentBuilderBenchmark {
|
||||||
|
|
||||||
private List<String> allTopicNames = List.of();
|
private List<String> allTopicNames = List.of();
|
||||||
|
|
||||||
private MetadataImage metadataImage;
|
private CoordinatorMetadataImage metadataImage;
|
||||||
|
|
||||||
private TopicIds.TopicResolver topicResolver;
|
private TopicIds.TopicResolver topicResolver;
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ public class TargetAssignmentBuilderBenchmark {
|
||||||
int partitionsPerTopic = (memberCount * partitionsToMemberRatio) / topicCount;
|
int partitionsPerTopic = (memberCount * partitionsToMemberRatio) / topicCount;
|
||||||
|
|
||||||
metadataImage = AssignorBenchmarkUtils.createMetadataImage(allTopicNames, partitionsPerTopic);
|
metadataImage = AssignorBenchmarkUtils.createMetadataImage(allTopicNames, partitionsPerTopic);
|
||||||
topicResolver = new TopicIds.CachedTopicResolver(metadataImage.topics());
|
topicResolver = new TopicIds.CachedTopicResolver(metadataImage);
|
||||||
|
|
||||||
subscribedTopicDescriber = new SubscribedTopicDescriberImpl(metadataImage);
|
subscribedTopicDescriber = new SubscribedTopicDescriberImpl(metadataImage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.apache.kafka.common.Uuid;
|
||||||
import org.apache.kafka.common.metadata.TopicRecord;
|
import org.apache.kafka.common.metadata.TopicRecord;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.Time;
|
import org.apache.kafka.common.utils.Time;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.group.GroupMetadataManager;
|
import org.apache.kafka.coordinator.group.GroupMetadataManager;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
import org.apache.kafka.image.MetadataDelta;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
import org.apache.kafka.image.MetadataImage;
|
||||||
|
@ -123,7 +124,7 @@ public class RegexResolutionBenchmark {
|
||||||
GROUP_ID,
|
GROUP_ID,
|
||||||
LOG,
|
LOG,
|
||||||
TIME,
|
TIME,
|
||||||
image,
|
new KRaftCoordinatorMetadataImage(image),
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
regexes
|
regexes
|
||||||
);
|
);
|
||||||
|
|
|
@ -893,5 +893,8 @@ public class TopicsImageTest {
|
||||||
assertEquals(expectedNames, names);
|
assertEquals(expectedNames, names);
|
||||||
assertThrows(UnsupportedOperationException.class, () -> map.remove(FOO_UUID));
|
assertThrows(UnsupportedOperationException.class, () -> map.remove(FOO_UUID));
|
||||||
assertThrows(UnsupportedOperationException.class, () -> map.put(FOO_UUID, "bar"));
|
assertThrows(UnsupportedOperationException.class, () -> map.put(FOO_UUID, "bar"));
|
||||||
|
|
||||||
|
var result = IMAGE1.topicIdToNameView().get("zar");
|
||||||
|
assertNull(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,9 @@ import org.apache.kafka.common.message.WriteShareGroupStateRequestData;
|
||||||
import org.apache.kafka.common.message.WriteShareGroupStateResponseData;
|
import org.apache.kafka.common.message.WriteShareGroupStateResponseData;
|
||||||
import org.apache.kafka.common.requests.RequestContext;
|
import org.apache.kafka.common.requests.RequestContext;
|
||||||
import org.apache.kafka.common.utils.BufferSupplier;
|
import org.apache.kafka.common.utils.BufferSupplier;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataDelta;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
|
import org.apache.kafka.image.FeaturesImage;
|
||||||
import org.apache.kafka.server.share.SharePartitionKey;
|
import org.apache.kafka.server.share.SharePartitionKey;
|
||||||
|
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
|
@ -136,10 +137,11 @@ public interface ShareCoordinator {
|
||||||
* A new metadata image is available.
|
* A new metadata image is available.
|
||||||
*
|
*
|
||||||
* @param newImage The new metadata image.
|
* @param newImage The new metadata image.
|
||||||
|
* @param newFeaturesImage The features image.
|
||||||
* @param delta The metadata delta.
|
* @param delta The metadata delta.
|
||||||
*/
|
*/
|
||||||
void onNewMetadataImage(
|
void onNewMetadataImage(
|
||||||
MetadataImage newImage,
|
CoordinatorMetadataImage newImage,
|
||||||
MetadataDelta delta
|
FeaturesImage newFeaturesImage, CoordinatorMetadataDelta delta
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,8 @@ import org.apache.kafka.common.utils.Time;
|
||||||
import org.apache.kafka.common.utils.Utils;
|
import org.apache.kafka.common.utils.Utils;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorEventProcessor;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorEventProcessor;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorLoader;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorLoader;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataDelta;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRuntime;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRuntime;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRuntimeMetrics;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRuntimeMetrics;
|
||||||
|
@ -52,8 +54,7 @@ import org.apache.kafka.coordinator.common.runtime.CoordinatorShardBuilderSuppli
|
||||||
import org.apache.kafka.coordinator.common.runtime.MultiThreadedEventProcessor;
|
import org.apache.kafka.coordinator.common.runtime.MultiThreadedEventProcessor;
|
||||||
import org.apache.kafka.coordinator.common.runtime.PartitionWriter;
|
import org.apache.kafka.coordinator.common.runtime.PartitionWriter;
|
||||||
import org.apache.kafka.coordinator.share.metrics.ShareCoordinatorMetrics;
|
import org.apache.kafka.coordinator.share.metrics.ShareCoordinatorMetrics;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
import org.apache.kafka.image.FeaturesImage;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.server.common.ShareVersion;
|
import org.apache.kafka.server.common.ShareVersion;
|
||||||
import org.apache.kafka.server.record.BrokerCompressionType;
|
import org.apache.kafka.server.record.BrokerCompressionType;
|
||||||
import org.apache.kafka.server.share.SharePartitionKey;
|
import org.apache.kafka.server.share.SharePartitionKey;
|
||||||
|
@ -1096,10 +1097,10 @@ public class ShareCoordinatorService implements ShareCoordinator {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNewMetadataImage(MetadataImage newImage, MetadataDelta delta) {
|
public void onNewMetadataImage(CoordinatorMetadataImage newImage, FeaturesImage newFeaturesImage, CoordinatorMetadataDelta delta) {
|
||||||
throwIfNotActive();
|
throwIfNotActive();
|
||||||
this.runtime.onNewMetadataImage(newImage, delta);
|
this.runtime.onNewMetadataImage(newImage, delta);
|
||||||
boolean enabled = isShareGroupsEnabled(newImage);
|
boolean enabled = isShareGroupsEnabled(newFeaturesImage);
|
||||||
// enabled shouldRunJob result (XOR)
|
// enabled shouldRunJob result (XOR)
|
||||||
// 0 0 no op on flag, do not call jobs
|
// 0 0 no op on flag, do not call jobs
|
||||||
// 0 1 disable flag, do not call jobs => action
|
// 0 1 disable flag, do not call jobs => action
|
||||||
|
@ -1127,9 +1128,9 @@ public class ShareCoordinatorService implements ShareCoordinator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isShareGroupsEnabled(MetadataImage image) {
|
private boolean isShareGroupsEnabled(FeaturesImage image) {
|
||||||
return shareGroupConfigEnabledSupplier.get() || ShareVersion.fromFeatureLevel(
|
return shareGroupConfigEnabledSupplier.get() || ShareVersion.fromFeatureLevel(
|
||||||
image.features().finalizedVersions().getOrDefault(ShareVersion.FEATURE_NAME, (short) 0)
|
image.finalizedVersions().getOrDefault(ShareVersion.FEATURE_NAME, (short) 0)
|
||||||
).supportsShareGroups();
|
).supportsShareGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ import org.apache.kafka.common.requests.WriteShareGroupStateResponse;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.Time;
|
import org.apache.kafka.common.utils.Time;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorExecutor;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorExecutor;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataDelta;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetrics;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetrics;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetricsShard;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetricsShard;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
|
@ -55,8 +57,6 @@ import org.apache.kafka.coordinator.share.generated.ShareUpdateKey;
|
||||||
import org.apache.kafka.coordinator.share.generated.ShareUpdateValue;
|
import org.apache.kafka.coordinator.share.generated.ShareUpdateValue;
|
||||||
import org.apache.kafka.coordinator.share.metrics.ShareCoordinatorMetrics;
|
import org.apache.kafka.coordinator.share.metrics.ShareCoordinatorMetrics;
|
||||||
import org.apache.kafka.coordinator.share.metrics.ShareCoordinatorMetricsShard;
|
import org.apache.kafka.coordinator.share.metrics.ShareCoordinatorMetricsShard;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
||||||
import org.apache.kafka.server.share.SharePartitionKey;
|
import org.apache.kafka.server.share.SharePartitionKey;
|
||||||
import org.apache.kafka.server.share.persister.PartitionFactory;
|
import org.apache.kafka.server.share.persister.PartitionFactory;
|
||||||
|
@ -83,7 +83,7 @@ public class ShareCoordinatorShard implements CoordinatorShard<CoordinatorRecord
|
||||||
private final TimelineHashMap<SharePartitionKey, Integer> leaderEpochMap;
|
private final TimelineHashMap<SharePartitionKey, Integer> leaderEpochMap;
|
||||||
private final TimelineHashMap<SharePartitionKey, Integer> snapshotUpdateCount;
|
private final TimelineHashMap<SharePartitionKey, Integer> snapshotUpdateCount;
|
||||||
private final TimelineHashMap<SharePartitionKey, Integer> stateEpochMap;
|
private final TimelineHashMap<SharePartitionKey, Integer> stateEpochMap;
|
||||||
private MetadataImage metadataImage;
|
private CoordinatorMetadataImage metadataImage;
|
||||||
private final ShareCoordinatorOffsetsManager offsetsManager;
|
private final ShareCoordinatorOffsetsManager offsetsManager;
|
||||||
private final Time time;
|
private final Time time;
|
||||||
|
|
||||||
|
@ -206,13 +206,13 @@ public class ShareCoordinatorShard implements CoordinatorShard<CoordinatorRecord
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaded(MetadataImage newImage) {
|
public void onLoaded(CoordinatorMetadataImage newImage) {
|
||||||
this.metadataImage = newImage;
|
this.metadataImage = newImage;
|
||||||
coordinatorMetrics.activateMetricsShard(metricsShard);
|
coordinatorMetrics.activateMetricsShard(metricsShard);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNewMetadataImage(MetadataImage newImage, MetadataDelta delta) {
|
public void onNewMetadataImage(CoordinatorMetadataImage newImage, CoordinatorMetadataDelta delta) {
|
||||||
this.metadataImage = newImage;
|
this.metadataImage = newImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,8 +769,9 @@ public class ShareCoordinatorShard implements CoordinatorShard<CoordinatorRecord
|
||||||
log.error("Metadata image is null");
|
log.error("Metadata image is null");
|
||||||
return Optional.of(getWriteErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
return Optional.of(getWriteErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
||||||
}
|
}
|
||||||
if (metadataImage.topics().getTopic(topicId) == null ||
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadataOp = metadataImage.topicMetadata(topicId);
|
||||||
metadataImage.topics().getPartition(topicId, partitionId) == null) {
|
if (topicMetadataOp.isEmpty() ||
|
||||||
|
topicMetadataOp.get().partitionCount() <= partitionId) {
|
||||||
log.error("Topic/TopicPartition not found in metadata image.");
|
log.error("Topic/TopicPartition not found in metadata image.");
|
||||||
return Optional.of(getWriteErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
return Optional.of(getWriteErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
||||||
}
|
}
|
||||||
|
@ -816,8 +817,9 @@ public class ShareCoordinatorShard implements CoordinatorShard<CoordinatorRecord
|
||||||
return Optional.of(ReadShareGroupStateResponse.toErrorResponseData(topicId, partitionId, Errors.UNKNOWN_TOPIC_OR_PARTITION, Errors.UNKNOWN_TOPIC_OR_PARTITION.message()));
|
return Optional.of(ReadShareGroupStateResponse.toErrorResponseData(topicId, partitionId, Errors.UNKNOWN_TOPIC_OR_PARTITION, Errors.UNKNOWN_TOPIC_OR_PARTITION.message()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadataImage.topics().getTopic(topicId) == null ||
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadataOp = metadataImage.topicMetadata(topicId);
|
||||||
metadataImage.topics().getPartition(topicId, partitionId) == null) {
|
if (topicMetadataOp.isEmpty() ||
|
||||||
|
topicMetadataOp.get().partitionCount() <= partitionId) {
|
||||||
log.error("Topic/TopicPartition not found in metadata image.");
|
log.error("Topic/TopicPartition not found in metadata image.");
|
||||||
return Optional.of(ReadShareGroupStateResponse.toErrorResponseData(topicId, partitionId, Errors.UNKNOWN_TOPIC_OR_PARTITION, Errors.UNKNOWN_TOPIC_OR_PARTITION.message()));
|
return Optional.of(ReadShareGroupStateResponse.toErrorResponseData(topicId, partitionId, Errors.UNKNOWN_TOPIC_OR_PARTITION, Errors.UNKNOWN_TOPIC_OR_PARTITION.message()));
|
||||||
}
|
}
|
||||||
|
@ -849,8 +851,9 @@ public class ShareCoordinatorShard implements CoordinatorShard<CoordinatorRecord
|
||||||
return Optional.of(ReadShareGroupStateSummaryResponse.toErrorResponseData(topicId, partitionId, Errors.UNKNOWN_TOPIC_OR_PARTITION, Errors.UNKNOWN_TOPIC_OR_PARTITION.message()));
|
return Optional.of(ReadShareGroupStateSummaryResponse.toErrorResponseData(topicId, partitionId, Errors.UNKNOWN_TOPIC_OR_PARTITION, Errors.UNKNOWN_TOPIC_OR_PARTITION.message()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadataImage.topics().getTopic(topicId) == null ||
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadataOp = metadataImage.topicMetadata(topicId);
|
||||||
metadataImage.topics().getPartition(topicId, partitionId) == null) {
|
if (topicMetadataOp.isEmpty() ||
|
||||||
|
topicMetadataOp.get().partitionCount() <= partitionId) {
|
||||||
log.error("Topic/TopicPartition not found in metadata image.");
|
log.error("Topic/TopicPartition not found in metadata image.");
|
||||||
return Optional.of(ReadShareGroupStateSummaryResponse.toErrorResponseData(topicId, partitionId, Errors.UNKNOWN_TOPIC_OR_PARTITION, Errors.UNKNOWN_TOPIC_OR_PARTITION.message()));
|
return Optional.of(ReadShareGroupStateSummaryResponse.toErrorResponseData(topicId, partitionId, Errors.UNKNOWN_TOPIC_OR_PARTITION, Errors.UNKNOWN_TOPIC_OR_PARTITION.message()));
|
||||||
}
|
}
|
||||||
|
@ -880,8 +883,9 @@ public class ShareCoordinatorShard implements CoordinatorShard<CoordinatorRecord
|
||||||
return Optional.of(getDeleteErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
return Optional.of(getDeleteErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadataImage.topics().getTopic(topicId) == null ||
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadataOp = metadataImage.topicMetadata(topicId);
|
||||||
metadataImage.topics().getPartition(topicId, partitionId) == null) {
|
if (topicMetadataOp.isEmpty() ||
|
||||||
|
topicMetadataOp.get().partitionCount() <= partitionId) {
|
||||||
log.error("Topic/TopicPartition not found in metadata image.");
|
log.error("Topic/TopicPartition not found in metadata image.");
|
||||||
return Optional.of(getDeleteErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
return Optional.of(getDeleteErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
||||||
}
|
}
|
||||||
|
@ -917,8 +921,9 @@ public class ShareCoordinatorShard implements CoordinatorShard<CoordinatorRecord
|
||||||
return Optional.of(getInitializeErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
return Optional.of(getInitializeErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadataImage.topics().getTopic(topicId) == null ||
|
Optional<CoordinatorMetadataImage.TopicMetadata> topicMetadataOp = metadataImage.topicMetadata(topicId);
|
||||||
metadataImage.topics().getPartition(topicId, partitionId) == null) {
|
if (topicMetadataOp.isEmpty() ||
|
||||||
|
topicMetadataOp.get().partitionCount() <= partitionId) {
|
||||||
log.error("Topic/TopicPartition not found in metadata image.");
|
log.error("Topic/TopicPartition not found in metadata image.");
|
||||||
return Optional.of(getInitializeErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
return Optional.of(getInitializeErrorCoordinatorResult(Errors.UNKNOWN_TOPIC_OR_PARTITION, null, topicId, partitionId));
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,13 @@ import org.apache.kafka.common.utils.BufferSupplier;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.Time;
|
import org.apache.kafka.common.utils.Time;
|
||||||
import org.apache.kafka.common.utils.Utils;
|
import org.apache.kafka.common.utils.Utils;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataDelta;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRuntime;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRuntime;
|
||||||
import org.apache.kafka.coordinator.common.runtime.PartitionWriter;
|
import org.apache.kafka.coordinator.common.runtime.PartitionWriter;
|
||||||
import org.apache.kafka.coordinator.share.metrics.ShareCoordinatorMetrics;
|
import org.apache.kafka.coordinator.share.metrics.ShareCoordinatorMetrics;
|
||||||
import org.apache.kafka.image.MetadataDelta;
|
import org.apache.kafka.image.FeaturesImage;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
|
||||||
import org.apache.kafka.server.common.ShareVersion;
|
import org.apache.kafka.server.common.ShareVersion;
|
||||||
import org.apache.kafka.server.share.SharePartitionKey;
|
import org.apache.kafka.server.share.SharePartitionKey;
|
||||||
import org.apache.kafka.server.util.FutureUtils;
|
import org.apache.kafka.server.util.FutureUtils;
|
||||||
|
@ -1485,7 +1486,7 @@ class ShareCoordinatorServiceTest {
|
||||||
));
|
));
|
||||||
|
|
||||||
service.startup(() -> 1);
|
service.startup(() -> 1);
|
||||||
service.onNewMetadataImage(mock(MetadataImage.class), mock(MetadataDelta.class));
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mock(FeaturesImage.class), mock(CoordinatorMetadataDelta.class));
|
||||||
verify(runtime, times(0))
|
verify(runtime, times(0))
|
||||||
.scheduleWriteOperation(
|
.scheduleWriteOperation(
|
||||||
eq("write-state-record-prune"),
|
eq("write-state-record-prune"),
|
||||||
|
@ -1580,7 +1581,7 @@ class ShareCoordinatorServiceTest {
|
||||||
));
|
));
|
||||||
|
|
||||||
service.startup(() -> 2);
|
service.startup(() -> 2);
|
||||||
service.onNewMetadataImage(mock(MetadataImage.class), mock(MetadataDelta.class));
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mock(FeaturesImage.class), mock(CoordinatorMetadataDelta.class));
|
||||||
verify(runtime, times(0))
|
verify(runtime, times(0))
|
||||||
.scheduleWriteOperation(
|
.scheduleWriteOperation(
|
||||||
eq("write-state-record-prune"),
|
eq("write-state-record-prune"),
|
||||||
|
@ -1642,7 +1643,7 @@ class ShareCoordinatorServiceTest {
|
||||||
));
|
));
|
||||||
|
|
||||||
service.startup(() -> 1);
|
service.startup(() -> 1);
|
||||||
service.onNewMetadataImage(mock(MetadataImage.class), mock(MetadataDelta.class));
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mock(FeaturesImage.class), mock(CoordinatorMetadataDelta.class));
|
||||||
verify(runtime, times(0))
|
verify(runtime, times(0))
|
||||||
.scheduleWriteOperation(
|
.scheduleWriteOperation(
|
||||||
eq("write-state-record-prune"),
|
eq("write-state-record-prune"),
|
||||||
|
@ -1695,7 +1696,7 @@ class ShareCoordinatorServiceTest {
|
||||||
));
|
));
|
||||||
|
|
||||||
service.startup(() -> 1);
|
service.startup(() -> 1);
|
||||||
service.onNewMetadataImage(mock(MetadataImage.class), mock(MetadataDelta.class));
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mock(FeaturesImage.class), mock(CoordinatorMetadataDelta.class));
|
||||||
verify(runtime, times(0))
|
verify(runtime, times(0))
|
||||||
.scheduleWriteOperation(
|
.scheduleWriteOperation(
|
||||||
eq("write-state-record-prune"),
|
eq("write-state-record-prune"),
|
||||||
|
@ -1746,7 +1747,7 @@ class ShareCoordinatorServiceTest {
|
||||||
));
|
));
|
||||||
|
|
||||||
service.startup(() -> 1);
|
service.startup(() -> 1);
|
||||||
service.onNewMetadataImage(mock(MetadataImage.class), mock(MetadataDelta.class));
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mock(FeaturesImage.class), mock(CoordinatorMetadataDelta.class));
|
||||||
|
|
||||||
verify(runtime, times(0))
|
verify(runtime, times(0))
|
||||||
.scheduleWriteOperation(
|
.scheduleWriteOperation(
|
||||||
|
@ -1810,7 +1811,7 @@ class ShareCoordinatorServiceTest {
|
||||||
));
|
));
|
||||||
|
|
||||||
service.startup(() -> 1);
|
service.startup(() -> 1);
|
||||||
service.onNewMetadataImage(mock(MetadataImage.class), mock(MetadataDelta.class));
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mock(FeaturesImage.class), mock(CoordinatorMetadataDelta.class));
|
||||||
verify(runtime, times(0))
|
verify(runtime, times(0))
|
||||||
.scheduleWriteOperation(
|
.scheduleWriteOperation(
|
||||||
eq("write-state-record-prune"),
|
eq("write-state-record-prune"),
|
||||||
|
@ -1886,7 +1887,7 @@ class ShareCoordinatorServiceTest {
|
||||||
));
|
));
|
||||||
|
|
||||||
service.startup(() -> 1);
|
service.startup(() -> 1);
|
||||||
service.onNewMetadataImage(mock(MetadataImage.class), mock(MetadataDelta.class));
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mock(FeaturesImage.class), mock(CoordinatorMetadataDelta.class));
|
||||||
verify(runtime, times(0))
|
verify(runtime, times(0))
|
||||||
.scheduleWriteOperation(
|
.scheduleWriteOperation(
|
||||||
eq("write-state-record-prune"),
|
eq("write-state-record-prune"),
|
||||||
|
@ -1946,7 +1947,7 @@ class ShareCoordinatorServiceTest {
|
||||||
)).thenReturn(List.of(CompletableFuture.completedFuture(null)));
|
)).thenReturn(List.of(CompletableFuture.completedFuture(null)));
|
||||||
|
|
||||||
service.startup(() -> 1);
|
service.startup(() -> 1);
|
||||||
service.onNewMetadataImage(mock(MetadataImage.class), mock(MetadataDelta.class));
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mock(FeaturesImage.class), mock(CoordinatorMetadataDelta.class));
|
||||||
verify(runtime, times(0))
|
verify(runtime, times(0))
|
||||||
.scheduleWriteOperation(
|
.scheduleWriteOperation(
|
||||||
eq("snapshot-cold-partitions"),
|
eq("snapshot-cold-partitions"),
|
||||||
|
@ -2004,7 +2005,7 @@ class ShareCoordinatorServiceTest {
|
||||||
));
|
));
|
||||||
|
|
||||||
service.startup(() -> 2);
|
service.startup(() -> 2);
|
||||||
service.onNewMetadataImage(mock(MetadataImage.class), mock(MetadataDelta.class));
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mock(FeaturesImage.class), mock(CoordinatorMetadataDelta.class));
|
||||||
verify(runtime, times(0))
|
verify(runtime, times(0))
|
||||||
.scheduleWriteAllOperation(
|
.scheduleWriteAllOperation(
|
||||||
eq("snapshot-cold-partitions"),
|
eq("snapshot-cold-partitions"),
|
||||||
|
@ -2069,11 +2070,11 @@ class ShareCoordinatorServiceTest {
|
||||||
|
|
||||||
service.startup(() -> 1);
|
service.startup(() -> 1);
|
||||||
|
|
||||||
MetadataImage mockedImage = mock(MetadataImage.class, RETURNS_DEEP_STUBS);
|
FeaturesImage mockedFeaturesImage = mock(FeaturesImage.class, RETURNS_DEEP_STUBS);
|
||||||
|
|
||||||
// Feature disabled on start.
|
// Feature disabled on start.
|
||||||
when(mockedImage.features().finalizedVersions().getOrDefault(eq(ShareVersion.FEATURE_NAME), anyShort())).thenReturn((short) 0);
|
when(mockedFeaturesImage.finalizedVersions().getOrDefault(eq(ShareVersion.FEATURE_NAME), anyShort())).thenReturn((short) 0);
|
||||||
service.onNewMetadataImage(mockedImage, mock(MetadataDelta.class)); // Jobs will not execute as feature is OFF in image.
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mockedFeaturesImage, mock(CoordinatorMetadataDelta.class)); // Jobs will not execute as feature is OFF in image.
|
||||||
|
|
||||||
verify(timer, times(0)).add(any()); // Timer task not added.
|
verify(timer, times(0)).add(any()); // Timer task not added.
|
||||||
verify(runtime, times(0)).scheduleWriteOperation(
|
verify(runtime, times(0)).scheduleWriteOperation(
|
||||||
|
@ -2090,9 +2091,9 @@ class ShareCoordinatorServiceTest {
|
||||||
assertFalse(service.shouldRunPeriodicJob());
|
assertFalse(service.shouldRunPeriodicJob());
|
||||||
|
|
||||||
// Enable feature.
|
// Enable feature.
|
||||||
Mockito.reset(mockedImage);
|
Mockito.reset(mockedFeaturesImage);
|
||||||
when(mockedImage.features().finalizedVersions().getOrDefault(eq(ShareVersion.FEATURE_NAME), anyShort())).thenReturn((short) 1);
|
when(mockedFeaturesImage.finalizedVersions().getOrDefault(eq(ShareVersion.FEATURE_NAME), anyShort())).thenReturn((short) 1);
|
||||||
service.onNewMetadataImage(mockedImage, mock(MetadataDelta.class)); // Jobs will execute as feature is ON in image.
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mockedFeaturesImage, mock(CoordinatorMetadataDelta.class)); // Jobs will execute as feature is ON in image.
|
||||||
|
|
||||||
verify(timer, times(2)).add(any()); // Timer task added twice (prune, snapshot).
|
verify(timer, times(2)).add(any()); // Timer task added twice (prune, snapshot).
|
||||||
timer.advanceClock(30001L);
|
timer.advanceClock(30001L);
|
||||||
|
@ -2110,9 +2111,9 @@ class ShareCoordinatorServiceTest {
|
||||||
assertTrue(service.shouldRunPeriodicJob());
|
assertTrue(service.shouldRunPeriodicJob());
|
||||||
|
|
||||||
// Disable feature
|
// Disable feature
|
||||||
Mockito.reset(mockedImage);
|
Mockito.reset(mockedFeaturesImage);
|
||||||
when(mockedImage.features().finalizedVersions().getOrDefault(eq(ShareVersion.FEATURE_NAME), anyShort())).thenReturn((short) 0);
|
when(mockedFeaturesImage.finalizedVersions().getOrDefault(eq(ShareVersion.FEATURE_NAME), anyShort())).thenReturn((short) 0);
|
||||||
service.onNewMetadataImage(mockedImage, mock(MetadataDelta.class)); // Jobs will not execute as feature is on in image.
|
service.onNewMetadataImage(mock(CoordinatorMetadataImage.class), mockedFeaturesImage, mock(CoordinatorMetadataDelta.class)); // Jobs will not execute as feature is on in image.
|
||||||
timer.advanceClock(30001L);
|
timer.advanceClock(30001L);
|
||||||
|
|
||||||
verify(timer, times(4)).add(any()); // Tasks added but will return immediately.
|
verify(timer, times(4)).add(any()); // Tasks added but will return immediately.
|
||||||
|
|
|
@ -38,19 +38,21 @@ import org.apache.kafka.common.requests.WriteShareGroupStateResponse;
|
||||||
import org.apache.kafka.common.utils.LogContext;
|
import org.apache.kafka.common.utils.LogContext;
|
||||||
import org.apache.kafka.common.utils.MockTime;
|
import org.apache.kafka.common.utils.MockTime;
|
||||||
import org.apache.kafka.common.utils.Time;
|
import org.apache.kafka.common.utils.Time;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetrics;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetrics;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetricsShard;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorMetricsShard;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorRecord;
|
||||||
import org.apache.kafka.coordinator.common.runtime.CoordinatorResult;
|
import org.apache.kafka.coordinator.common.runtime.CoordinatorResult;
|
||||||
|
import org.apache.kafka.coordinator.common.runtime.KRaftCoordinatorMetadataImage;
|
||||||
import org.apache.kafka.coordinator.share.generated.ShareSnapshotKey;
|
import org.apache.kafka.coordinator.share.generated.ShareSnapshotKey;
|
||||||
import org.apache.kafka.coordinator.share.generated.ShareSnapshotValue;
|
import org.apache.kafka.coordinator.share.generated.ShareSnapshotValue;
|
||||||
import org.apache.kafka.coordinator.share.generated.ShareUpdateKey;
|
import org.apache.kafka.coordinator.share.generated.ShareUpdateKey;
|
||||||
import org.apache.kafka.coordinator.share.generated.ShareUpdateValue;
|
import org.apache.kafka.coordinator.share.generated.ShareUpdateValue;
|
||||||
import org.apache.kafka.coordinator.share.metrics.ShareCoordinatorMetrics;
|
import org.apache.kafka.coordinator.share.metrics.ShareCoordinatorMetrics;
|
||||||
|
import org.apache.kafka.image.ClusterImage;
|
||||||
import org.apache.kafka.image.MetadataImage;
|
import org.apache.kafka.image.MetadataImage;
|
||||||
import org.apache.kafka.image.TopicImage;
|
import org.apache.kafka.image.TopicImage;
|
||||||
import org.apache.kafka.image.TopicsImage;
|
import org.apache.kafka.image.TopicsImage;
|
||||||
import org.apache.kafka.metadata.PartitionRegistration;
|
|
||||||
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
import org.apache.kafka.server.common.ApiMessageAndVersion;
|
||||||
import org.apache.kafka.server.share.SharePartitionKey;
|
import org.apache.kafka.server.share.SharePartitionKey;
|
||||||
import org.apache.kafka.server.share.persister.PartitionFactory;
|
import org.apache.kafka.server.share.persister.PartitionFactory;
|
||||||
|
@ -73,7 +75,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
|
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
@ -97,13 +98,13 @@ class ShareCoordinatorShardTest {
|
||||||
private final CoordinatorMetrics coordinatorMetrics = mock(CoordinatorMetrics.class);
|
private final CoordinatorMetrics coordinatorMetrics = mock(CoordinatorMetrics.class);
|
||||||
private final CoordinatorMetricsShard metricsShard = mock(CoordinatorMetricsShard.class);
|
private final CoordinatorMetricsShard metricsShard = mock(CoordinatorMetricsShard.class);
|
||||||
private final SnapshotRegistry snapshotRegistry = new SnapshotRegistry(logContext);
|
private final SnapshotRegistry snapshotRegistry = new SnapshotRegistry(logContext);
|
||||||
private MetadataImage metadataImage = null;
|
private CoordinatorMetadataImage metadataImage = null;
|
||||||
private Map<String, String> configOverrides = new HashMap<>();
|
private Map<String, String> configOverrides = new HashMap<>();
|
||||||
ShareCoordinatorOffsetsManager offsetsManager = mock(ShareCoordinatorOffsetsManager.class);
|
ShareCoordinatorOffsetsManager offsetsManager = mock(ShareCoordinatorOffsetsManager.class);
|
||||||
private Time time;
|
private Time time;
|
||||||
|
|
||||||
ShareCoordinatorShard build() {
|
ShareCoordinatorShard build() {
|
||||||
if (metadataImage == null) metadataImage = mock(MetadataImage.class, RETURNS_DEEP_STUBS);
|
if (metadataImage == null) metadataImage = mock(CoordinatorMetadataImage.class, RETURNS_DEEP_STUBS);
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
config = ShareCoordinatorTestConfig.createConfig(ShareCoordinatorTestConfig.testConfigMap(configOverrides));
|
config = ShareCoordinatorTestConfig.createConfig(ShareCoordinatorTestConfig.testConfigMap(configOverrides));
|
||||||
}
|
}
|
||||||
|
@ -117,8 +118,10 @@ class ShareCoordinatorShardTest {
|
||||||
offsetsManager,
|
offsetsManager,
|
||||||
time == null ? TIME : time
|
time == null ? TIME : time
|
||||||
);
|
);
|
||||||
when(metadataImage.topics().getTopic((Uuid) any())).thenReturn(mock(TopicImage.class));
|
|
||||||
when(metadataImage.topics().getPartition(any(), anyInt())).thenReturn(mock(PartitionRegistration.class));
|
var topicMetadata = mock(CoordinatorMetadataImage.TopicMetadata.class);
|
||||||
|
when(topicMetadata.partitionCount()).thenReturn(PARTITION + 1);
|
||||||
|
when(metadataImage.topicMetadata((Uuid) any())).thenReturn(Optional.of(topicMetadata));
|
||||||
shard.onNewMetadataImage(metadataImage, null);
|
shard.onNewMetadataImage(metadataImage, null);
|
||||||
return shard;
|
return shard;
|
||||||
}
|
}
|
||||||
|
@ -1081,7 +1084,7 @@ class ShareCoordinatorShardTest {
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteTopicIdNonExistentInMetadataImage() {
|
public void testDeleteTopicIdNonExistentInMetadataImage() {
|
||||||
MetadataImage image = mock(MetadataImage.class);
|
MetadataImage image = mock(MetadataImage.class);
|
||||||
shard.onNewMetadataImage(image, null);
|
shard.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
|
|
||||||
DeleteShareGroupStateRequestData request = new DeleteShareGroupStateRequestData()
|
DeleteShareGroupStateRequestData request = new DeleteShareGroupStateRequestData()
|
||||||
.setGroupId(GROUP_ID)
|
.setGroupId(GROUP_ID)
|
||||||
|
@ -1112,7 +1115,8 @@ class ShareCoordinatorShardTest {
|
||||||
@Test
|
@Test
|
||||||
public void testDeletePartitionIdNonExistentInMetadataImage() {
|
public void testDeletePartitionIdNonExistentInMetadataImage() {
|
||||||
MetadataImage image = mock(MetadataImage.class);
|
MetadataImage image = mock(MetadataImage.class);
|
||||||
shard.onNewMetadataImage(image, null);
|
when(image.cluster()).thenReturn(mock(ClusterImage.class));
|
||||||
|
shard.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
|
|
||||||
DeleteShareGroupStateRequestData request = new DeleteShareGroupStateRequestData()
|
DeleteShareGroupStateRequestData request = new DeleteShareGroupStateRequestData()
|
||||||
.setGroupId(GROUP_ID)
|
.setGroupId(GROUP_ID)
|
||||||
|
@ -1123,12 +1127,10 @@ class ShareCoordinatorShardTest {
|
||||||
|
|
||||||
// topic id found in cache
|
// topic id found in cache
|
||||||
TopicsImage topicsImage = mock(TopicsImage.class);
|
TopicsImage topicsImage = mock(TopicsImage.class);
|
||||||
when(topicsImage.getTopic(eq(TOPIC_ID))).thenReturn(
|
TopicImage topicImage = mock(TopicImage.class);
|
||||||
mock(TopicImage.class)
|
when(topicImage.partitions()).thenReturn(Map.of());
|
||||||
);
|
when(topicsImage.getTopic(eq(TOPIC_ID))).thenReturn(topicImage);
|
||||||
when(image.topics()).thenReturn(
|
when(image.topics()).thenReturn(topicsImage);
|
||||||
topicsImage
|
|
||||||
);
|
|
||||||
|
|
||||||
// partition id not found
|
// partition id not found
|
||||||
when(topicsImage.getPartition(eq(TOPIC_ID), eq(0))).thenReturn(
|
when(topicsImage.getPartition(eq(TOPIC_ID), eq(0))).thenReturn(
|
||||||
|
@ -1143,7 +1145,7 @@ class ShareCoordinatorShardTest {
|
||||||
assertEquals(expectedData, result.response());
|
assertEquals(expectedData, result.response());
|
||||||
assertEquals(expectedRecords, result.records());
|
assertEquals(expectedRecords, result.records());
|
||||||
verify(topicsImage, times(1)).getTopic(eq(TOPIC_ID));
|
verify(topicsImage, times(1)).getTopic(eq(TOPIC_ID));
|
||||||
verify(topicsImage, times(1)).getPartition(eq(TOPIC_ID), eq(0));
|
verify(topicImage, times(1)).partitions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1255,7 +1257,7 @@ class ShareCoordinatorShardTest {
|
||||||
@Test
|
@Test
|
||||||
public void testInitializeTopicIdNonExistentInMetadataImage() {
|
public void testInitializeTopicIdNonExistentInMetadataImage() {
|
||||||
MetadataImage image = mock(MetadataImage.class);
|
MetadataImage image = mock(MetadataImage.class);
|
||||||
shard.onNewMetadataImage(image, null);
|
shard.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
|
|
||||||
InitializeShareGroupStateRequestData request = new InitializeShareGroupStateRequestData()
|
InitializeShareGroupStateRequestData request = new InitializeShareGroupStateRequestData()
|
||||||
.setGroupId(GROUP_ID)
|
.setGroupId(GROUP_ID)
|
||||||
|
@ -1284,7 +1286,8 @@ class ShareCoordinatorShardTest {
|
||||||
@Test
|
@Test
|
||||||
public void testInitializePartitionIdNonExistentInMetadataImage() {
|
public void testInitializePartitionIdNonExistentInMetadataImage() {
|
||||||
MetadataImage image = mock(MetadataImage.class);
|
MetadataImage image = mock(MetadataImage.class);
|
||||||
shard.onNewMetadataImage(image, null);
|
when(image.cluster()).thenReturn(mock(ClusterImage.class));
|
||||||
|
shard.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
|
|
||||||
InitializeShareGroupStateRequestData request = new InitializeShareGroupStateRequestData()
|
InitializeShareGroupStateRequestData request = new InitializeShareGroupStateRequestData()
|
||||||
.setGroupId(GROUP_ID)
|
.setGroupId(GROUP_ID)
|
||||||
|
@ -1296,8 +1299,10 @@ class ShareCoordinatorShardTest {
|
||||||
));
|
));
|
||||||
|
|
||||||
// topic id found in cache
|
// topic id found in cache
|
||||||
|
TopicImage topicImage = mock(TopicImage.class);
|
||||||
|
when(topicImage.partitions()).thenReturn(Map.of());
|
||||||
TopicsImage topicsImage = mock(TopicsImage.class);
|
TopicsImage topicsImage = mock(TopicsImage.class);
|
||||||
when(topicsImage.getTopic(eq(TOPIC_ID))).thenReturn(mock(TopicImage.class));
|
when(topicsImage.getTopic(eq(TOPIC_ID))).thenReturn(topicImage);
|
||||||
when(image.topics()).thenReturn(topicsImage);
|
when(image.topics()).thenReturn(topicsImage);
|
||||||
|
|
||||||
// partition id not found
|
// partition id not found
|
||||||
|
@ -1311,13 +1316,13 @@ class ShareCoordinatorShardTest {
|
||||||
assertEquals(expectedData, result.response());
|
assertEquals(expectedData, result.response());
|
||||||
assertEquals(expectedRecords, result.records());
|
assertEquals(expectedRecords, result.records());
|
||||||
verify(topicsImage, times(1)).getTopic(eq(TOPIC_ID));
|
verify(topicsImage, times(1)).getTopic(eq(TOPIC_ID));
|
||||||
verify(topicsImage, times(1)).getPartition(eq(TOPIC_ID), eq(0));
|
verify(topicImage, times(1)).partitions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSnapshotColdPartitionsNoEligiblePartitions() {
|
public void testSnapshotColdPartitionsNoEligiblePartitions() {
|
||||||
MetadataImage image = mock(MetadataImage.class);
|
MetadataImage image = mock(MetadataImage.class);
|
||||||
shard.onNewMetadataImage(image, null);
|
shard.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int producerId = 0;
|
int producerId = 0;
|
||||||
short producerEpoch = 0;
|
short producerEpoch = 0;
|
||||||
|
@ -1383,7 +1388,7 @@ class ShareCoordinatorShardTest {
|
||||||
@Test
|
@Test
|
||||||
public void testSnapshotColdPartitionsSnapshotUpdateNotConsidered() {
|
public void testSnapshotColdPartitionsSnapshotUpdateNotConsidered() {
|
||||||
MetadataImage image = mock(MetadataImage.class);
|
MetadataImage image = mock(MetadataImage.class);
|
||||||
shard.onNewMetadataImage(image, null);
|
shard.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int producerId = 0;
|
int producerId = 0;
|
||||||
short producerEpoch = 0;
|
short producerEpoch = 0;
|
||||||
|
@ -1480,7 +1485,7 @@ class ShareCoordinatorShardTest {
|
||||||
@Test
|
@Test
|
||||||
public void testSnapshotColdPartitionsDoesNotPerpetuallySnapshot() {
|
public void testSnapshotColdPartitionsDoesNotPerpetuallySnapshot() {
|
||||||
MetadataImage image = mock(MetadataImage.class);
|
MetadataImage image = mock(MetadataImage.class);
|
||||||
shard.onNewMetadataImage(image, null);
|
shard.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int producerId = 0;
|
int producerId = 0;
|
||||||
short producerEpoch = 0;
|
short producerEpoch = 0;
|
||||||
|
@ -1554,7 +1559,7 @@ class ShareCoordinatorShardTest {
|
||||||
@Test
|
@Test
|
||||||
public void testSnapshotColdPartitionsPartialEligiblePartitions() {
|
public void testSnapshotColdPartitionsPartialEligiblePartitions() {
|
||||||
MetadataImage image = mock(MetadataImage.class);
|
MetadataImage image = mock(MetadataImage.class);
|
||||||
shard.onNewMetadataImage(image, null);
|
shard.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int producerId = 0;
|
int producerId = 0;
|
||||||
short producerEpoch = 0;
|
short producerEpoch = 0;
|
||||||
|
@ -1668,7 +1673,7 @@ class ShareCoordinatorShardTest {
|
||||||
@Test
|
@Test
|
||||||
public void testOnTopicsDeletedTopicIds() {
|
public void testOnTopicsDeletedTopicIds() {
|
||||||
MetadataImage image = mock(MetadataImage.class);
|
MetadataImage image = mock(MetadataImage.class);
|
||||||
shard.onNewMetadataImage(image, null);
|
shard.onNewMetadataImage(new KRaftCoordinatorMetadataImage(image), null);
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int producerId = 0;
|
int producerId = 0;
|
||||||
|
|
Loading…
Reference in New Issue