-
Notifications
You must be signed in to change notification settings - Fork 14.8k
KAFKA-19964: API Versions Response returns minimum metadata version for finalized level when no quorum exists #21122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from 1 commit
6d53ead
3126d1c
80de492
08fcd72
f072ffb
92e34e4
1175997
ca35b06
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,8 @@ | |
| import org.apache.kafka.common.requests.ApiVersionsResponse; | ||
| import org.apache.kafka.server.common.FinalizedFeatures; | ||
|
|
||
| import java.util.Map; | ||
| import java.util.Optional; | ||
| import java.util.function.Supplier; | ||
|
|
||
| /** | ||
|
|
@@ -35,19 +37,19 @@ public class SimpleApiVersionManager implements ApiVersionManager { | |
| private final ApiMessageType.ListenerType listenerType; | ||
| private final Features<SupportedVersionRange> brokerFeatures; | ||
| private final boolean enableUnstableLastVersion; | ||
| private final Supplier<FinalizedFeatures> featuresProvider; | ||
| private final Supplier<Optional<FinalizedFeatures>> featuresProvider; | ||
| private final ApiVersionsResponseData.ApiVersionCollection apiVersions; | ||
|
|
||
| /** | ||
| * SimpleApiVersionManager constructor | ||
| * @param listenerType the listener type | ||
| * @param enableUnstableLastVersion whether to enable unstable last version, see | ||
| * {@link org.apache.kafka.server.config.ServerConfigs#UNSTABLE_API_VERSIONS_ENABLE_CONFIG} | ||
| * @param featuresProvider a provider to the finalized features supported | ||
| * @param featuresProvider a provider to the finalized features supported (may return Optional.empty() if not yet initialized) | ||
| */ | ||
| public SimpleApiVersionManager(ApiMessageType.ListenerType listenerType, | ||
| boolean enableUnstableLastVersion, | ||
| Supplier<FinalizedFeatures> featuresProvider) { | ||
| Supplier<Optional<FinalizedFeatures>> featuresProvider) { | ||
| this.listenerType = listenerType; | ||
| this.brokerFeatures = BrokerFeatures.defaultSupportedFeatures(enableUnstableLastVersion); | ||
| this.enableUnstableLastVersion = enableUnstableLastVersion; | ||
|
|
@@ -67,19 +69,19 @@ public ApiMessageType.ListenerType listenerType() { | |
|
|
||
| @Override | ||
| public ApiVersionsResponse apiVersionResponse(int throttleTimeMs, boolean alterFeatureLevel0) { | ||
| FinalizedFeatures currentFeatures = features(); | ||
| Optional<FinalizedFeatures> currentFeatures = featuresProvider.get(); | ||
| return new ApiVersionsResponse.Builder() | ||
| .setThrottleTimeMs(throttleTimeMs) | ||
| .setApiVersions(apiVersions) | ||
| .setSupportedFeatures(brokerFeatures) | ||
| .setFinalizedFeatures(currentFeatures.finalizedFeatures()) | ||
| .setFinalizedFeaturesEpoch(currentFeatures.finalizedFeaturesEpoch()) | ||
| .setFinalizedFeatures(currentFeatures.map(FinalizedFeatures::finalizedFeatures).orElse(Map.of())) | ||
|
||
| .setFinalizedFeaturesEpoch(currentFeatures.map(FinalizedFeatures::finalizedFeaturesEpoch).orElse(-1L)) | ||
| .setAlterFeatureLevel0(alterFeatureLevel0) | ||
| .build(); | ||
| } | ||
|
|
||
| @Override | ||
| public FinalizedFeatures features() { | ||
| return featuresProvider.get(); | ||
| return featuresProvider.get().orElse(null); | ||
|
||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a subtlety here with
kraft.version. Previously,featuresPublisher.featureswas always "present", so we can always set the "finalized" kraft version known by the localKafkaRaftClient. However, now thefeaturePublisher.features()might be an empty optional, in which case the function in the.mapcall won't be applied until afterfeaturesPublisher.features().isPresent().This means if a controller node has kraft.version=1, but has not committed the bootstrap metadata version record (i.e.
featuresPublisher.features().isEmpty()), the controller will not show that it is kraft.version=1 in the ApiVersionsResponse it sends, even though it previously would have.I think the intention is, for better or for worse, that the "finalizedFeatures" section of the
ApiVersionsResponseto show the local node's kraft.version level, even if it may be uncommitted. Is that correct @jsancio?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If so, one way to fix this is to add a
NOT_FINALIZEDenum value toMetadataVersion. This option makes the most sense to me, but it is weird thatFinalizedFeatureshas aNOT_FINALIZEDvalue for metadata version...Or we can make
FinalizedFeatures#metadataVersionfield an optional, and keep it so thatFinalizedFeaturesdoes not have to be an optional (although this seems confusing when the object is called "FinalizedFeatures").There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also it is weird we have
FinalizedFeaturesandFinalizedControllerFeaturesrecords.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this behavior is not intentional: KAFKA-18865