Skip to content

Conversation

@Jaehui-Lee
Copy link
Contributor

@Apache-HBase

This comment has been minimized.

@Apache-HBase

This comment has been minimized.

Copy link
Contributor

@taklwu taklwu left a comment

Choose a reason for hiding this comment

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

docker yetus failure is unrelated as reported in https://issues.apache.org/jira/browse/INFRA-27492, I will keep the PR open for another day and see if they can come back and look at the logs

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a bug where dynamic configuration changes for coprocessors were not being properly detected and applied. The root cause was that the configuration change detection was comparing two Configuration objects instead of comparing the currently loaded coprocessors with the new configuration values.

Key Changes:

  • Refactored CoprocessorConfigurationUtil.checkConfigurationChange() to compare current loaded coprocessors against new configuration instead of comparing two configuration objects
  • Added getCoprocessorClassNames() method to CoprocessorHost to retrieve currently loaded coprocessor class names
  • Updated all call sites to pass the CoprocessorHost instance instead of the old Configuration object

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
hbase-server/src/main/java/org/apache/hadoop/hbase/util/CoprocessorConfigurationUtil.java Rewrote checkConfigurationChange() to compare current state vs new config; added hasCoprocessorsConfigured() helper method
hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java Added getCoprocessorClassNames() method to expose currently loaded coprocessor class names
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java Updated to pass rsHost instance instead of old configuration to checkConfigurationChange()
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java Updated to pass coprocessorHost instance instead of old configuration to checkConfigurationChange()
hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java Updated to pass cpHost instance instead of old configuration; inlined initializeCoprocessorHost() method
hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java Updated to pass cpHost instance instead of old configuration to checkConfigurationChange()
hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerOnlineConfigChange.java Updated tests to modify the actual server configuration object to properly test dynamic configuration reload

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +96 to 104
private static boolean hasCoprocessorsConfigured(Configuration conf, String... configurationKey) {
for (String key : configurationKey) {
String oldValue = oldConfig.get(key);
String newValue = newConfig.get(key);
// check if the coprocessor key has any difference
if (!StringUtils.equalsIgnoreCase(oldValue, newValue)) {
isConfigurationChange = true;
break;
String[] coprocessors = conf.getStrings(key);
if (coprocessors != null && coprocessors.length > 0) {
return true;
}
}
return isConfigurationChange;
return false;
}
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The hasCoprocessorsConfigured method should validate that the coprocessor strings contain actual class names, not just check if the array is non-empty. If the configuration contains empty strings or only whitespace, this method will incorrectly return true even though no valid coprocessors are configured. This is inconsistent with the logic in checkConfigurationChange (lines 78-84) which properly filters empty class names. The method should parse the className|priority|path format and check if the actual class name is non-empty after trimming.

Copilot uses AI. Check for mistakes.
Comment on lines +57 to +71
if (
!conf.getBoolean(CoprocessorHost.COPROCESSORS_ENABLED_CONF_KEY,
CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED)
) {
return false;
}

if (coprocessorHost == null) {
// If no coprocessor host exists, check if any coprocessors are now configured
return hasCoprocessorsConfigured(conf, configurationKey);
}

// Get currently loaded coprocessor class names
Set<String> currentlyLoaded = coprocessorHost.getCoprocessorClassNames();

Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

When coprocessors are disabled in the new configuration (COPROCESSORS_ENABLED_CONF_KEY is false), this method returns false indicating no configuration change. However, if coprocessors were previously enabled and loaded, this prevents the coprocessor host from being recreated to unload those coprocessors. The method should return true if there's a mismatch between the current loaded state and the desired state, even when coprocessors are being disabled. Consider checking if currentlyLoaded is non-empty when coprocessors are disabled - that would indicate a change requiring coprocessor unloading.

Suggested change
if (
!conf.getBoolean(CoprocessorHost.COPROCESSORS_ENABLED_CONF_KEY,
CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED)
) {
return false;
}
if (coprocessorHost == null) {
// If no coprocessor host exists, check if any coprocessors are now configured
return hasCoprocessorsConfigured(conf, configurationKey);
}
// Get currently loaded coprocessor class names
Set<String> currentlyLoaded = coprocessorHost.getCoprocessorClassNames();
if (coprocessorHost == null) {
// If no coprocessor host exists, check if any coprocessors are now configured
if (!conf.getBoolean(CoprocessorHost.COPROCESSORS_ENABLED_CONF_KEY,
CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED)) {
// Coprocessors are disabled and none are loaded, so no change
return false;
}
return hasCoprocessorsConfigured(conf, configurationKey);
}
// Get currently loaded coprocessor class names
Set<String> currentlyLoaded = coprocessorHost.getCoprocessorClassNames();
if (!conf.getBoolean(CoprocessorHost.COPROCESSORS_ENABLED_CONF_KEY,
CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED)) {
// Coprocessors are now disabled, but if any are currently loaded, we need to unload them
return !currentlyLoaded.isEmpty();
}

Copilot uses AI. Check for mistakes.
*/
public static boolean checkConfigurationChange(CoprocessorHost<?, ?> coprocessorHost,
Configuration conf, String... configurationKey) {
Preconditions.checkArgument(configurationKey != null, "Configuration Key(s) must be provided");
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The precondition check verifies that configurationKey is not null, but doesn't check if the array is empty. If an empty array is passed, the method will always return false (no change) even if coprocessors are currently loaded and should be unloaded. Consider adding a check for array length or documenting that an empty array is allowed and means "no configuration keys to check".

Suggested change
Preconditions.checkArgument(configurationKey != null, "Configuration Key(s) must be provided");
Preconditions.checkArgument(configurationKey != null, "Configuration Key(s) must be provided");
Preconditions.checkArgument(configurationKey.length > 0, "At least one configuration key must be provided");

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +91
public static boolean checkConfigurationChange(CoprocessorHost<?, ?> coprocessorHost,
Configuration conf, String... configurationKey) {
Preconditions.checkArgument(configurationKey != null, "Configuration Key(s) must be provided");
boolean isConfigurationChange = false;
Preconditions.checkArgument(conf != null, "Configuration must be provided");

if (
!conf.getBoolean(CoprocessorHost.COPROCESSORS_ENABLED_CONF_KEY,
CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED)
) {
return false;
}

if (coprocessorHost == null) {
// If no coprocessor host exists, check if any coprocessors are now configured
return hasCoprocessorsConfigured(conf, configurationKey);
}

// Get currently loaded coprocessor class names
Set<String> currentlyLoaded = coprocessorHost.getCoprocessorClassNames();

// Get coprocessor class names from configuration
// Only class names are compared; priority and path changes are not detected
Set<String> configuredClasses = new HashSet<>();
for (String key : configurationKey) {
String[] classes = conf.getStrings(key);
if (classes != null) {
for (String className : classes) {
// Handle the className|priority|path format
String[] classNameToken = className.split("\\|");
String actualClassName = classNameToken[0].trim();
if (!Strings.isNullOrEmpty(actualClassName)) {
configuredClasses.add(actualClassName);
}
}
}
}

// Compare the two sets
return !currentlyLoaded.equals(configuredClasses);
}
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The new checkConfigurationChange method lacks unit test coverage. While integration tests exist in TestRegionServerOnlineConfigChange, they don't cover important edge cases such as: (1) disabling coprocessors when some are loaded, (2) the null coprocessorHost path that calls hasCoprocessorsConfigured, (3) parsing of className|priority|path format, (4) removing coprocessors from configuration, and (5) empty or whitespace-only class names. Consider adding unit tests for CoprocessorConfigurationUtil to ensure these scenarios are properly handled.

Copilot uses AI. Check for mistakes.
@Apache-HBase
Copy link

🎊 +1 overall

Vote Subsystem Runtime Logfile Comment
+0 🆗 reexec 0m 33s Docker mode activated.
_ Prechecks _
+1 💚 dupname 0m 0s No case conflicting files found.
+0 🆗 codespell 0m 0s codespell was not available.
+0 🆗 detsecrets 0m 0s detect-secrets was not available.
+1 💚 @author 0m 0s The patch does not contain any @author tags.
+1 💚 hbaseanti 0m 0s Patch does not have any anti-patterns.
_ branch-3 Compile Tests _
+1 💚 mvninstall 3m 42s branch-3 passed
+1 💚 compile 3m 31s branch-3 passed
+1 💚 checkstyle 1m 1s branch-3 passed
+1 💚 spotbugs 1m 41s branch-3 passed
+1 💚 spotless 0m 52s branch has no errors when running spotless:check.
_ Patch Compile Tests _
+1 💚 mvninstall 3m 7s the patch passed
+1 💚 compile 3m 31s the patch passed
+1 💚 javac 3m 31s the patch passed
+1 💚 blanks 0m 0s The patch has no blanks issues.
+1 💚 checkstyle 1m 0s the patch passed
+1 💚 spotbugs 1m 45s the patch passed
+1 💚 hadoopcheck 12m 8s Patch does not cause any errors with Hadoop 3.3.6 3.4.1.
+1 💚 spotless 0m 45s patch has no errors when running spotless:check.
_ Other Tests _
+1 💚 asflicense 0m 12s The patch does not generate ASF License warnings.
41m 31s
Subsystem Report/Notes
Docker ClientAPI=1.43 ServerAPI=1.43 base: https://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-7544/2/artifact/yetus-general-check/output/Dockerfile
GITHUB PR #7544
Optional Tests dupname asflicense javac spotbugs checkstyle codespell detsecrets compile hadoopcheck hbaseanti spotless
uname Linux 33d799b10596 5.4.0-1103-aws #111~18.04.1-Ubuntu SMP Tue May 23 20:04:10 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Build tool maven
Personality dev-support/hbase-personality.sh
git revision branch-3 / 63912c2
Default Java Eclipse Adoptium-17.0.11+9
Max. process+thread count 84 (vs. ulimit of 30000)
modules C: hbase-server U: hbase-server
Console output https://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-7544/2/console
versions git=2.34.1 maven=3.9.8 spotbugs=4.7.3
Powered by Apache Yetus 0.15.0 https://yetus.apache.org

This message was automatically generated.

@Apache-HBase
Copy link

🎊 +1 overall

Vote Subsystem Runtime Logfile Comment
+0 🆗 reexec 1m 14s Docker mode activated.
-0 ⚠️ yetus 0m 3s Unprocessed flag(s): --brief-report-file --spotbugs-strict-precheck --author-ignore-list --blanks-eol-ignore-file --blanks-tabs-ignore-file --quick-hadoopcheck
_ Prechecks _
_ branch-3 Compile Tests _
+1 💚 mvninstall 2m 54s branch-3 passed
+1 💚 compile 0m 43s branch-3 passed
+1 💚 javadoc 0m 22s branch-3 passed
+1 💚 shadedjars 4m 27s branch has no errors when building our shaded downstream artifacts.
_ Patch Compile Tests _
+1 💚 mvninstall 2m 12s the patch passed
+1 💚 compile 0m 43s the patch passed
+1 💚 javac 0m 43s the patch passed
+1 💚 javadoc 0m 21s the patch passed
+1 💚 shadedjars 4m 25s patch has no errors when building our shaded downstream artifacts.
_ Other Tests _
+1 💚 unit 195m 39s hbase-server in the patch passed.
216m 35s
Subsystem Report/Notes
Docker ClientAPI=1.48 ServerAPI=1.48 base: https://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-7544/2/artifact/yetus-jdk17-hadoop3-check/output/Dockerfile
GITHUB PR #7544
Optional Tests javac javadoc unit compile shadedjars
uname Linux 19c86117f3f7 6.8.0-1024-aws #26~22.04.1-Ubuntu SMP Wed Feb 19 06:54:57 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
Build tool maven
Personality dev-support/hbase-personality.sh
git revision branch-3 / 63912c2
Default Java Eclipse Adoptium-17.0.11+9
Test Results https://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-7544/2/testReport/
Max. process+thread count 6149 (vs. ulimit of 30000)
modules C: hbase-server U: hbase-server
Console output https://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-7544/2/console
versions git=2.34.1 maven=3.9.8
Powered by Apache Yetus 0.15.0 https://yetus.apache.org

This message was automatically generated.

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