-
Notifications
You must be signed in to change notification settings - Fork 14k
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
KAFKA-18052: Decouple the dependency of feature stable version to the metadata version #17886
base: trunk
Are you sure you want to change the base?
KAFKA-18052: Decouple the dependency of feature stable version to the metadata version #17886
Conversation
server-common/src/main/java/org/apache/kafka/server/common/TestFeatureVersion.java
Outdated
Show resolved
Hide resolved
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.
@dongnuo123 : Thanks for the PR. Left a comment.
server-common/src/main/java/org/apache/kafka/server/common/Features.java
Outdated
Show resolved
Hide resolved
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.
@dongnuo123 : Thanks for the updated PR. A few minor comments.
server-common/src/main/java/org/apache/kafka/server/common/Features.java
Outdated
Show resolved
Hide resolved
server-common/src/main/java/org/apache/kafka/server/common/Features.java
Outdated
Show resolved
Hide resolved
server-common/src/test/java/org/apache/kafka/server/common/FeaturesTest.java
Show resolved
Hide resolved
server-common/src/main/java/org/apache/kafka/server/common/TestFeatureVersion.java
Show resolved
Hide resolved
@@ -313,7 +313,7 @@ Map<String, Short> calculateEffectiveFeatureLevels() { | |||
Optional.ofNullable(newFeatureLevels.get(KRaftVersion.FEATURE_NAME)))); | |||
} else if (!newFeatureLevels.containsKey(supportedFeature.featureName())) { | |||
newFeatureLevels.put(supportedFeature.featureName(), | |||
supportedFeature.defaultValue(releaseVersion)); | |||
supportedFeature.defaultLevel(releaseVersion)); | |||
} | |||
}); | |||
// Verify that the specified features support the given levels. This requires the full |
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.
FAILED ❌ FormatterTest > "testFeatureFlag(short).version=0"
FAILED ❌ FormatterTest > "testFeatureFlag(short).version=1"
FAILED ❌ FormatterTest > testInvalidFeatureFlag()
Got 3 failed tests. Will fix it today
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.
@dongnuo123 : Thanks for the updated PR. A few more comments.
* - The feature X has default version = XV_10 (dependency = {}), latest production = XV_5 (dependency = {}) | ||
* (Violating rule 2. The latest production value XV_5 is smaller than the default value) | ||
* - The feature X has default version = XV_10 (dependency = {Y: YV_3}), latest production = XV_11 (dependency = {Y: YV_4}) | ||
* The feature Y has default version = YV_3 (dependency = {}), latest production = YV_3 (dependency = {}) |
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.
The default version part seems unrelated to this example.
* The feature Y has default version = YV_3 (dependency = {}), latest production = YV_3 (dependency = {}) | ||
* (Violating rule 3. For latest production XV_11, Y's latest production YV_3 is smaller than the dependency value YV_4) | ||
* - The feature X has default version = XV_10 (dependency = {Y: YV_4}), latest production = XV_11 (dependency = {Y: YV_4}) | ||
* The feature Y has default version = YV_3 (dependency = {}), latest production = YV_4 (dependency = {}) |
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.
The latest production part seems unrelated to this example.
* - The feature X has default version = XV_10 (dependency = {Y: YV_3}), latest production = XV_11 (dependency = {Y: YV_4}) | ||
* The feature Y has default version = YV_3 (dependency = {}), latest production = YV_4 (dependency = {}) | ||
* - The feature X has default version = latest production = XV_10 (dependency = {MetadataVersion: IBP_4_0_IV0}) | ||
* (Some features can depend on MetadataVersion, which is not checked in this method) |
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.
Hmm, how do we enforce the dependency on MV? For example, if feature level X_1 depends on MV_10 and is production ready, but MV_10 is not production ready, how do we detect that in tests?
KRAFT_VERSION("kraft.version", KRaftVersion.values()), | ||
TRANSACTION_VERSION("transaction.version", TransactionVersion.values()), | ||
GROUP_VERSION("group.version", GroupVersion.values()); | ||
TEST_VERSION("test.feature.version", TestFeatureVersion.values(), TestFeatureVersion.LATEST_PRODUCTION), |
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.
This is an existing issue. It seems that Features
should be Feature
since it represents a single feature?
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.
This file contains many different features so I'm not sure I follow.
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.
Well, Features.FEATURES
contains many features, but the enum Features
represents a single feature. For example, Features.name()
provides the name of a single feature.
// value calculated with {@link #defaultValue(MetadataVersion)}. | ||
public final FeatureVersion latestProduction; | ||
|
||
private static final Logger log = LoggerFactory.getLogger(Features.class); |
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.
This seems unused?
*/ | ||
public enum UnitTestFeatureVersion implements FeatureVersion { | ||
UT_FV0_0(0, MetadataVersion.MINIMUM_KRAFT_VERSION, Collections.emptyMap()), | ||
UT_FV0_1(1, MetadataVersion.IBP_3_7_IV0, Collections.emptyMap()), |
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.
Could we add a comment on the purpose of each feature?
/** | ||
* The enum is only used for testing invalid features in FeaturesTest.java. | ||
*/ | ||
public enum UnitTestFeatureVersion implements FeatureVersion { |
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.
Should we consolidate UnitTestFeatureVersion with TestFeatureVersion?
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.apache.kafka.server.common; |
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.
Should this be in the test directory?
UNIT_TEST_VERSION_2(UnitTestFeatureVersion.FEATURE_NAME + ".2", new FeatureVersion[]{UT_FV2_0, UT_FV2_1}, UT_FV2_0), | ||
UNIT_TEST_VERSION_3(UnitTestFeatureVersion.FEATURE_NAME + ".3", new FeatureVersion[]{UT_FV3_0, UT_FV3_1}, UT_FV3_1), | ||
UNIT_TEST_VERSION_4(UnitTestFeatureVersion.FEATURE_NAME + ".4", new FeatureVersion[]{UT_FV4_0, UT_FV4_1}, UT_FV4_1), | ||
UNIT_TEST_VERSION_5(UnitTestFeatureVersion.FEATURE_NAME + ".5", new FeatureVersion[]{UT_FV5_0, UT_FV5_1}, UT_FV5_1); |
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.
It's kind of weird to include unit test code in production code.
"UNIT_TEST_VERSION_2", | ||
"UNIT_TEST_VERSION_3", | ||
"UNIT_TEST_VERSION_4", | ||
"UNIT_TEST_VERSION_5"}, mode = EnumSource.Mode.EXCLUDE) |
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.
Hmm, is it correct for EXCLUDE
to be empty?
Currently the validation of feature upgrade relies on the supported version range generated during registration. For a given feature, its max supported feature version in production is set to be the default version value (the latest feature version with bootstrap metadata value smaller or equal to the latest production metadata value).
This patch introduces a
LATEST_PRODUCTION
value independent from the metadata version to each feature so that the highest supported feature version can be customized by the feature owner.The change only applies to dynamic feature upgrade. During formatting, we still use the default value associated the metadata version.
Committer Checklist (excluded from commit message)