Skip to content

MINOR: Several fixes and improvements for FeatureControlManager#12207

Merged
cmccabe merged 8 commits intoapache:trunkfrom
cmccabe:feature-control-manager-fixes
Jun 1, 2022
Merged

MINOR: Several fixes and improvements for FeatureControlManager#12207
cmccabe merged 8 commits intoapache:trunkfrom
cmccabe:feature-control-manager-fixes

Conversation

@cmccabe
Copy link
Copy Markdown
Contributor

@cmccabe cmccabe commented May 24, 2022

This PR fixes a bug where FeatureControlManager#replay(FeatureLevelRecord) was throwing an
exception if not all controllers in the quorum supported the feature being applied. While we do
want to validate this, it needs to be validated earlier, before the record is committed to the log.
Once the record has been committed to the log it should always be applied if the current controller
supports it.

Fix another bug where removing a feature was not supported once it had been configured. Note that
because we reserve feature level 0 for "feature not enabled", we don't need to use
Optional; we can just return a range of 0-0 when the feature is not supported.

In error messages, give more detail about what the problem is when a controller in the quorum cannot
handle a new version. For example, "Local controller 0 does not support this feature" rather than just
"quorum does not support this feature".

Allow the metadata version to be downgraded when UpgradeType.UNSAFE_DOWNGRADE has been set.
Previously we were unconditionally denying this even when this was set.

Add a builder for FeatureControlManager, so that we can easily add new parameters to the
constructor in the future. This will also be useful for creating FeatureControlManagers that are
initialized to a specific MetadataVersion.

This PR fixes a bug where FeatureControlManager#replay(FeatureLevelRecord) was throwing an
exception if not all controllers in the quorum supported the feature being applied. While we do
want to validate this, it needs to be validated earlier, before the record is committed to the log.
Once the record has been committed to the log it should always be applied if the current controller
supports it.

Fix another bug where removing a feature was not supported once it had been configured. Note that
because we reserve feature level 0 for "feature not enabled", we don't need to use
Optional<VersionRange>; we can just return a range of 0-0 when the feature is not supported.

Allow the metadata version to be downgraded when UpgradeType.UNSAFE_DOWNGRADE has been set.
Previously we were unconditionally denying this even when this was set.

Add a builder for FeatureControlManager, so that we can easily add new parameters to the
constructor in the future. This will also be useful for creating FeatureControlManagers that are
initialized to a specific MetadataVersion.
@cmccabe cmccabe force-pushed the feature-control-manager-fixes branch from 5d9960f to ed44532 Compare May 25, 2022 17:23
Copy link
Copy Markdown
Member

@mumrah mumrah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @cmccabe! Overall looks good, a few comments inline

}

public void replay(FeatureLevelRecord record) {
if (!canSupportVersion(record.name(), record.featureLevel())) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This made me wonder about bootstrapping and if we could load in an unknown version. However, looking at BootstrapMetadata#load, we will parse the feature level as a MetadataVersion before returning so we would throw an exception as we read the bootstrap records into memory. This could happen if someone generates a bootstrap snapshot at version N and then tries to load it into a cluster at N-1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah.

It's fine to do a sanity check based on local supported versions. Pulling in the quorum is where it is incorrect (which might be an argument for pulling localSupportedFeatures out of QuorumFeatures, but one step at a time.)

}
}

ControllerResult<Map<String, ApiError>> initializeMetadataVersion(short initVersion) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, this was leftover from a previous iteration on the bootstrapping logic where the controller was just getting the initial metadata version.

return invalidMetadataVersion(newVersionLevel, "The quorum does not support metadata.version.");
}

if (newVersionLevel <= 0) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we allow a metadata.version of zero? Seems like it might complicate things to support a non-present metadata.version at runtime. Would that mean we need to revert back to reading the IBP from config?

Copy link
Copy Markdown
Contributor Author

@cmccabe cmccabe May 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about this too.

I would like to get rid of MetadataVersion.UNINITIALIZED as a concept. There are a few places where the MV isn't stored and it should be (pre-3.3 snapshots, for example) but we can just treat those as MetadataVersion.3_0_0IV1

That would allow us to just say that MV for a kraft cluster was always > 0

But this PR was already getting too big so I held off on that.

* @param level The feature level.
* @return The reason why the feature level is not supported, or Optional.empty if it is supported.
*/
public Optional<String> reasonNotSupported(String featureName, short level) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name sort of seems like we're expecting it not to be supported. Maybe call it something like checkIfQuorumSupported? I think it would be good to include "quorum" in here to avoid confusion with the "local" compatibility check

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the problem with "check" or "validate" is that it sort of implies that we throw an exception if the validation fails, whereas this returns a reason string.

I liked avoiding exceptions here since it avoids messing with questions like what is the exception type and how do you pull out the string (which is what you really want)

FeatureControlManager manager = new FeatureControlManager.Builder().
build();
manager.updateFeatures(Collections.singletonMap("foo",
Map<String, FeatureUpdate.UpgradeType> upgradeTypes,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this added by accident?

@mumrah
Copy link
Copy Markdown
Member

mumrah commented May 31, 2022

@cmccabe changes look good. Looks like there is a compile error in FeatureControlManagerTest

@cmccabe
Copy link
Copy Markdown
Contributor Author

cmccabe commented Jun 1, 2022

One thing I did just now was get rid of RemoveFeatureLevelRecord since it’s redundant. We can just set level = 0 to remove a feature level

I also fixed it so that we support this case fully. In particular 0 is handled just like any other level — if there are brokers that don’t support level 0, you can’t turn it off. I don't think we'll have any such features any time soon, but this is conceptually simple and will help in the future

Copy link
Copy Markdown
Member

@mumrah mumrah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing RemoveFeatureLevelRecord seems fine, I guess we haven't really had any code to produce that record yet so no possibility of deserialization issues.

One minor thing inline, besides that LGTM 👍

}

if (newVersion <= 0) {
if (newVersion < 0) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message below should be updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants