HBASE-23710 - Priority configuration for system coprocessors (#1077)

Signed-off-by: Viraj Jasani <vjasani@apache.org>
This commit is contained in:
Geoffrey Jacoby 2020-01-23 16:23:28 -08:00 committed by Viraj Jasani
parent 7c61c3992a
commit 2d6bb81dff
3 changed files with 48 additions and 8 deletions

View File

@ -143,8 +143,16 @@ public abstract class CoprocessorHost<C extends Coprocessor, E extends Coprocess
if (defaultCPClasses == null || defaultCPClasses.length == 0)
return;
int priority = Coprocessor.PRIORITY_SYSTEM;
int currentSystemPriority = Coprocessor.PRIORITY_SYSTEM;
for (String className : defaultCPClasses) {
String[] classNameAndPriority = className.split("\\|");
boolean hasPriorityOverride = false;
className = classNameAndPriority[0];
int overridePriority = Coprocessor.PRIORITY_SYSTEM;
if (classNameAndPriority.length > 1){
overridePriority = Integer.parseInt(classNameAndPriority[1]);
hasPriorityOverride = true;
}
className = className.trim();
if (findCoprocessor(className) != null) {
// If already loaded will just continue
@ -155,13 +163,16 @@ public abstract class CoprocessorHost<C extends Coprocessor, E extends Coprocess
Thread.currentThread().setContextClassLoader(cl);
try {
implClass = cl.loadClass(className);
int coprocPriority = hasPriorityOverride ? overridePriority : currentSystemPriority;
// Add coprocessors as we go to guard against case where a coprocessor is specified twice
// in the configuration
E env = checkAndLoadInstance(implClass, priority, conf);
E env = checkAndLoadInstance(implClass, coprocPriority, conf);
if (env != null) {
this.coprocEnvironments.add(env);
LOG.info("System coprocessor {} loaded, priority={}.", className, priority);
++priority;
LOG.info("System coprocessor {} loaded, priority={}.", className, coprocPriority);
if (!hasPriorityOverride) {
++currentSystemPriority;
}
}
} catch (Throwable t) {
// We always abort if system coprocessors cannot be loaded

View File

@ -67,29 +67,42 @@ public class TestCoprocessorHost {
CoprocessorHost<RegionCoprocessor, CoprocessorEnvironment<RegionCoprocessor>> host;
host = new CoprocessorHostForTest<>(conf);
int overridePriority = Integer.MAX_VALUE - 1;
final String coprocessor_v3 =
SimpleRegionObserverV3.class.getName() + "|" + overridePriority;
// Try and load a coprocessor three times
conf.setStrings(key, coprocessor, coprocessor, coprocessor,
SimpleRegionObserverV2.class.getName());
SimpleRegionObserverV2.class.getName(), coprocessor_v3);
host.loadSystemCoprocessors(conf, key);
// Two coprocessors(SimpleRegionObserver and SimpleRegionObserverV2) loaded
Assert.assertEquals(2, host.coprocEnvironments.size());
// Three coprocessors(SimpleRegionObserver, SimpleRegionObserverV2,
// SimpleRegionObserverV3) loaded
Assert.assertEquals(3, host.coprocEnvironments.size());
// Check the priority value
CoprocessorEnvironment<?> simpleEnv = host.findCoprocessorEnvironment(
SimpleRegionObserver.class.getName());
CoprocessorEnvironment<?> simpleEnv_v2 = host.findCoprocessorEnvironment(
SimpleRegionObserverV2.class.getName());
CoprocessorEnvironment<?> simpleEnv_v3 = host.findCoprocessorEnvironment(
SimpleRegionObserverV3.class.getName());
assertNotNull(simpleEnv);
assertNotNull(simpleEnv_v2);
assertNotNull(simpleEnv_v3);
assertEquals(Coprocessor.PRIORITY_SYSTEM, simpleEnv.getPriority());
assertEquals(Coprocessor.PRIORITY_SYSTEM + 1, simpleEnv_v2.getPriority());
assertEquals(overridePriority, simpleEnv_v3.getPriority());
}
public static class SimpleRegionObserverV2 extends SimpleRegionObserver { }
public static class SimpleRegionObserverV3 extends SimpleRegionObserver {
}
private static class CoprocessorHostForTest<E extends Coprocessor> extends
CoprocessorHost<E, CoprocessorEnvironment<E>> {
final Configuration cpHostConf;

View File

@ -242,12 +242,28 @@ following entry in RegionServer's 'hbase-site.xml' file (generally located under
If multiple classes are specified for loading, the class names must be comma-separated.
The framework attempts to load all the configured classes using the default class loader.
Therefore, the jar file must reside on the server-side HBase classpath.
+
Coprocessors which are loaded in this way will be active on all regions of all tables.
These are also called system Coprocessor.
The first listed Coprocessors will be assigned the priority `Coprocessor.Priority.SYSTEM`.
Each subsequent coprocessor in the list will have its priority value incremented by one (which
reduces its priority, because priorities have the natural sort order of Integers).
+
These priority values can be manually overriden in hbase-site.xml. This can be useful if you
want to guarantee that a coprocessor will execute after another. For example, in the following
configuration `SumEndPoint` would be guaranteed to go last, except in the case of a tie with
another coprocessor:
+
[source,xml]
----
<property>
<name>hbase.coprocessor.region.classes</name>
<value>org.myname.hbase.coprocessor.endpoint.SumEndPoint|2147483647</value>
</property>
----
+
When calling out to registered observers, the framework executes their callbacks methods in the
sorted order of their priority. +
@ -758,7 +774,7 @@ Restricting arbitrary user coprocessors can be a big concern in multitenant envi
- `hbase.coprocessor.enabled`: Enables or disables all coprocessors. This will limit the functionality of HBase, as disabling all coprocessors will disable some security providers. An example coproccessor so affected is `org.apache.hadoop.hbase.security.access.AccessController`.
* `hbase.coprocessor.user.enabled`: Enables or disables loading coprocessors on tables (i.e. user coprocessors).
* One can statically load coprocessors via the following tunables in `hbase-site.xml`:
* One can statically load coprocessors, and optionally tune their priorities, via the following tunables in `hbase-site.xml`:
** `hbase.coprocessor.regionserver.classes`: A comma-separated list of coprocessors that are loaded by region servers
** `hbase.coprocessor.region.classes`: A comma-separated list of RegionObserver and Endpoint coprocessors
** `hbase.coprocessor.user.region.classes`: A comma-separated list of coprocessors that are loaded by all regions