kevin-wu24 commented on code in PR #21122:
URL: https://github.com/apache/kafka/pull/21122#discussion_r2608362807
##########
core/src/main/scala/kafka/server/ControllerServer.scala:
##########
@@ -158,9 +158,10 @@ class ControllerServer(
val apiVersionManager = new SimpleApiVersionManager(
ListenerType.CONTROLLER,
config.unstableApiVersionsEnabled,
- () => featuresPublisher.features().setFinalizedLevel(
- KRaftVersion.FEATURE_NAME,
- raftManager.client.kraftVersion().featureLevel())
+ () => featuresPublisher.features().map(f =>
Review Comment:
There is a subtlety here with `kraft.version`. Previously,
`featuresPublisher.features` was always "present", so we can always set the
"finalized" kraft version known by the local `KafkaRaftClient`. However, now
the `featurePublisher.features()` might be an empty optional, in which case the
function in the `.map` call won't be applied until after
`featuresPublisher.features().isPresent()`.
This means if a node has kraft.version=1, but has not committed the
bootstrap metadata version record, it 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 `ApiVersionsResponse` to show the local
node's kraft.version level, even if it may be uncommitted. Is that correct
@jsancio?
##########
server/src/main/java/org/apache/kafka/server/SimpleApiVersionManager.java:
##########
@@ -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);
Review Comment:
We should avoid ever returning null, because this is not safe. Instead, we
can change the `ApiVersionManager` interface's `features()` method to return an
`Optional<FinalizedFeatures>`. The implementors can return the wrapped
optional, and check things based on its presence.
For example, `ControllerApis#handleDescribeCluster` can now return a more
useful error message if the optional is not present. We can also add a test for
that in `ControllerApisTest`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]