Skip to content

Commit 0ef757e

Browse files
authored
HBASE-29526 Dynamic configuration not working for coprocessor (#7506)
Signed-off-by: Tak Lon (Stephen) Wu <taklwu@apache.org>
1 parent 38f0df2 commit 0ef757e

6 files changed

Lines changed: 92 additions & 25 deletions

File tree

hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,19 @@ public Set<String> getCoprocessors() {
115115
return returnValue;
116116
}
117117

118+
/**
119+
* Get the full class names of all loaded coprocessors. This method returns the complete class
120+
* names including package information, which is useful for precise coprocessor identification and
121+
* comparison.
122+
*/
123+
public Set<String> getCoprocessorClassNames() {
124+
Set<String> returnValue = new TreeSet<>();
125+
for (E e : coprocEnvironments) {
126+
returnValue.add(e.getInstance().getClass().getName());
127+
}
128+
return returnValue;
129+
}
130+
118131
/**
119132
* Load system coprocessors once only. Read the class names from configuration. Called by
120133
* constructor.

hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,7 +1054,7 @@ private void finishActiveMasterInitialization() throws IOException, InterruptedE
10541054
if (!maintenanceMode) {
10551055
startupTaskGroup.addTask("Initializing master coprocessors");
10561056
setQuotasObserver(conf);
1057-
initializeCoprocessorHost(conf);
1057+
this.cpHost = new MasterCoprocessorHost(this, conf);
10581058
}
10591059

10601060
// Checking if meta needs initializing.
@@ -4380,11 +4380,11 @@ public void onConfigurationChange(Configuration newConf) {
43804380
setQuotasObserver(newConf);
43814381
// update region server coprocessor if the configuration has changed.
43824382
if (
4383-
CoprocessorConfigurationUtil.checkConfigurationChange(getConfiguration(), newConf,
4383+
CoprocessorConfigurationUtil.checkConfigurationChange(this.cpHost, newConf,
43844384
CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY) && !maintenanceMode
43854385
) {
43864386
LOG.info("Update the master coprocessor(s) because the configuration has changed");
4387-
initializeCoprocessorHost(newConf);
4387+
this.cpHost = new MasterCoprocessorHost(this, newConf);
43884388
}
43894389
}
43904390

@@ -4396,11 +4396,6 @@ private void setQuotasObserver(Configuration conf) {
43964396
}
43974397
}
43984398

4399-
private void initializeCoprocessorHost(Configuration conf) {
4400-
// initialize master side coprocessors before we start handling requests
4401-
this.cpHost = new MasterCoprocessorHost(this, conf);
4402-
}
4403-
44044399
@Override
44054400
public long flushTable(TableName tableName, List<byte[]> columnFamilies, long nonceGroup,
44064401
long nonce) throws IOException {

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8541,7 +8541,7 @@ public void onConfigurationChange(Configuration conf) {
85418541
this.storeHotnessProtector.update(conf);
85428542
// update coprocessorHost if the configuration has changed.
85438543
if (
8544-
CoprocessorConfigurationUtil.checkConfigurationChange(getReadOnlyConfiguration(), conf,
8544+
CoprocessorConfigurationUtil.checkConfigurationChange(this.coprocessorHost, conf,
85458545
CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
85468546
CoprocessorHost.USER_REGION_COPROCESSOR_CONF_KEY)
85478547
) {

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4010,7 +4010,7 @@ public void onConfigurationChange(Configuration newConf) {
40104010

40114011
// update region server coprocessor if the configuration has changed.
40124012
if (
4013-
CoprocessorConfigurationUtil.checkConfigurationChange(getConfiguration(), newConf,
4013+
CoprocessorConfigurationUtil.checkConfigurationChange(this.rsHost, newConf,
40144014
CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY)
40154015
) {
40164016
LOG.info("Update region server coprocessors because the configuration has changed");

hbase-server/src/main/java/org/apache/hadoop/hbase/util/CoprocessorConfigurationUtil.java

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@
1717
*/
1818
package org.apache.hadoop.hbase.util;
1919

20-
import org.apache.commons.lang3.StringUtils;
20+
import java.util.HashSet;
21+
import java.util.Set;
2122
import org.apache.hadoop.conf.Configuration;
23+
import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
2224
import org.apache.yetus.audience.InterfaceAudience;
2325

2426
import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
27+
import org.apache.hbase.thirdparty.com.google.common.base.Strings;
2528

2629
/**
2730
* Helper class for coprocessor host when configuration changes.
@@ -32,19 +35,71 @@ public final class CoprocessorConfigurationUtil {
3235
private CoprocessorConfigurationUtil() {
3336
}
3437

35-
public static boolean checkConfigurationChange(Configuration oldConfig, Configuration newConfig,
36-
String... configurationKey) {
38+
/**
39+
* Check configuration change by comparing current loaded coprocessors with configuration values.
40+
* This method is useful when the configuration object has been updated but we need to determine
41+
* if coprocessor configuration has actually changed compared to what's currently loaded.
42+
* <p>
43+
* <b>Note:</b> This method only detects changes in the set of coprocessor class names. It does
44+
* <b>not</b> detect changes to priority or path for coprocessors that are already loaded with the
45+
* same class name. If you need to update the priority or path of an existing coprocessor, you
46+
* must restart the region/regionserver/master.
47+
* @param coprocessorHost the coprocessor host to check current loaded coprocessors (can be null)
48+
* @param conf the configuration to check
49+
* @param configurationKey the configuration keys to check
50+
* @return true if configuration has changed, false otherwise
51+
*/
52+
public static boolean checkConfigurationChange(CoprocessorHost<?, ?> coprocessorHost,
53+
Configuration conf, String... configurationKey) {
3754
Preconditions.checkArgument(configurationKey != null, "Configuration Key(s) must be provided");
38-
boolean isConfigurationChange = false;
55+
Preconditions.checkArgument(conf != null, "Configuration must be provided");
56+
57+
if (
58+
!conf.getBoolean(CoprocessorHost.COPROCESSORS_ENABLED_CONF_KEY,
59+
CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED)
60+
) {
61+
return false;
62+
}
63+
64+
if (coprocessorHost == null) {
65+
// If no coprocessor host exists, check if any coprocessors are now configured
66+
return hasCoprocessorsConfigured(conf, configurationKey);
67+
}
68+
69+
// Get currently loaded coprocessor class names
70+
Set<String> currentlyLoaded = coprocessorHost.getCoprocessorClassNames();
71+
72+
// Get coprocessor class names from configuration
73+
// Only class names are compared; priority and path changes are not detected
74+
Set<String> configuredClasses = new HashSet<>();
75+
for (String key : configurationKey) {
76+
String[] classes = conf.getStrings(key);
77+
if (classes != null) {
78+
for (String className : classes) {
79+
// Handle the className|priority|path format
80+
String[] classNameToken = className.split("\\|");
81+
String actualClassName = classNameToken[0].trim();
82+
if (!Strings.isNullOrEmpty(actualClassName)) {
83+
configuredClasses.add(actualClassName);
84+
}
85+
}
86+
}
87+
}
88+
89+
// Compare the two sets
90+
return !currentlyLoaded.equals(configuredClasses);
91+
}
92+
93+
/**
94+
* Helper method to check if there are any coprocessors configured.
95+
*/
96+
private static boolean hasCoprocessorsConfigured(Configuration conf, String... configurationKey) {
3997
for (String key : configurationKey) {
40-
String oldValue = oldConfig.get(key);
41-
String newValue = newConfig.get(key);
42-
// check if the coprocessor key has any difference
43-
if (!StringUtils.equalsIgnoreCase(oldValue, newValue)) {
44-
isConfigurationChange = true;
45-
break;
98+
String[] coprocessors = conf.getStrings(key);
99+
if (coprocessors != null && coprocessors.length > 0) {
100+
return true;
46101
}
47102
}
48-
return isConfigurationChange;
103+
return false;
49104
}
50105
}

hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerOnlineConfigChange.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,18 +230,22 @@ public void testStoreConfigurationOnlineChange() {
230230
@Test
231231
public void testCoprocessorConfigurationOnlineChange() {
232232
assertNull(rs1.getRegionServerCoprocessorHost().findCoprocessor(JMXListener.class.getName()));
233-
conf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, JMXListener.class.getName());
234-
rs1.getConfigurationManager().notifyAllObservers(conf);
233+
// Update configuration directly to simulate dynamic configuration reload
234+
Configuration rsConf = rs1.getConfiguration();
235+
rsConf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, JMXListener.class.getName());
236+
rs1.getConfigurationManager().notifyAllObservers(rsConf);
235237
assertNotNull(
236238
rs1.getRegionServerCoprocessorHost().findCoprocessor(JMXListener.class.getName()));
237239
}
238240

239241
@Test
240242
public void testCoprocessorConfigurationOnlineChangeOnMaster() {
241243
assertNull(hMaster.getMasterCoprocessorHost().findCoprocessor(JMXListener.class.getName()));
242-
conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, JMXListener.class.getName());
244+
// Update configuration directly to simulate dynamic configuration reload
245+
Configuration masterConf = hMaster.getConfiguration();
246+
masterConf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, JMXListener.class.getName());
243247
assertFalse(hMaster.isInMaintenanceMode());
244-
hMaster.getConfigurationManager().notifyAllObservers(conf);
248+
hMaster.getConfigurationManager().notifyAllObservers(masterConf);
245249
assertNotNull(hMaster.getMasterCoprocessorHost().findCoprocessor(JMXListener.class.getName()));
246250
}
247251

0 commit comments

Comments
 (0)