HBASE-13044 Configuration option for disabling coprocessor loading

This commit is contained in:
Andrew Purtell 2015-02-15 11:02:40 -08:00
parent 332515ed34
commit 9b2e4ed064
6 changed files with 232 additions and 2 deletions

View File

@ -993,6 +993,22 @@ possible configurations would overwhelm and obscure the important.
as part of the table details, region names, etc. When this is set to false, as part of the table details, region names, etc. When this is set to false,
the keys are hidden.</description> the keys are hidden.</description>
</property> </property>
<property>
<name>hbase.coprocessor.enabled</name>
<value>true</value>
<description>Enables or disables coprocessor loading. If 'false'
(disabled), any other coprocessor related configuration will be ignored.
</description>
</property>
<property>
<name>hbase.coprocessor.user.enabled</name>
<value>true</value>
<description>Enables or disables user (aka. table) coprocessor loading.
If 'false' (disabled), any table coprocessor attributes in table
descriptors will be ignored. If "hbase.coprocessor.enabled" is 'false'
this setting has no effect.
</description>
</property>
<property> <property>
<name>hbase.coprocessor.region.classes</name> <name>hbase.coprocessor.region.classes</name>
<value></value> <value></value>

View File

@ -73,6 +73,11 @@ public abstract class CoprocessorHost<E extends CoprocessorEnvironment> {
"hbase.coprocessor.wal.classes"; "hbase.coprocessor.wal.classes";
public static final String ABORT_ON_ERROR_KEY = "hbase.coprocessor.abortonerror"; public static final String ABORT_ON_ERROR_KEY = "hbase.coprocessor.abortonerror";
public static final boolean DEFAULT_ABORT_ON_ERROR = true; public static final boolean DEFAULT_ABORT_ON_ERROR = true;
public static final String COPROCESSORS_ENABLED_CONF_KEY = "hbase.coprocessor.enabled";
public static final boolean DEFAULT_COPROCESSORS_ENABLED = true;
public static final String USER_COPROCESSORS_ENABLED_CONF_KEY =
"hbase.coprocessor.user.enabled";
public static final boolean DEFAULT_USER_COPROCESSORS_ENABLED = true;
private static final Log LOG = LogFactory.getLog(CoprocessorHost.class); private static final Log LOG = LogFactory.getLog(CoprocessorHost.class);
protected Abortable abortable; protected Abortable abortable;
@ -123,6 +128,12 @@ public abstract class CoprocessorHost<E extends CoprocessorEnvironment> {
* Called by constructor. * Called by constructor.
*/ */
protected void loadSystemCoprocessors(Configuration conf, String confKey) { protected void loadSystemCoprocessors(Configuration conf, String confKey) {
boolean coprocessorsEnabled = conf.getBoolean(COPROCESSORS_ENABLED_CONF_KEY,
DEFAULT_COPROCESSORS_ENABLED);
if (!coprocessorsEnabled) {
return;
}
Class<?> implClass = null; Class<?> implClass = null;
// load default coprocessors from configure file // load default coprocessors from configure file

View File

@ -22,6 +22,8 @@ package org.apache.hadoop.hbase.master;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Coprocessor; import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HColumnDescriptor;
@ -48,6 +50,8 @@ import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
public class MasterCoprocessorHost public class MasterCoprocessorHost
extends CoprocessorHost<MasterCoprocessorHost.MasterEnvironment> { extends CoprocessorHost<MasterCoprocessorHost.MasterEnvironment> {
private static final Log LOG = LogFactory.getLog(MasterCoprocessorHost.class);
/** /**
* Coprocessor environment extension providing access to master related * Coprocessor environment extension providing access to master related
* services. * services.
@ -70,10 +74,16 @@ public class MasterCoprocessorHost
private MasterServices masterServices; private MasterServices masterServices;
MasterCoprocessorHost(final MasterServices services, final Configuration conf) { public MasterCoprocessorHost(final MasterServices services, final Configuration conf) {
super(services); super(services);
this.conf = conf; this.conf = conf;
this.masterServices = services; this.masterServices = services;
// Log the state of coprocessor loading here; should appear only once or
// twice in the daemon log, depending on HBase version, because there is
// only one MasterCoprocessorHost instance in the master process
boolean coprocessorsEnabled = conf.getBoolean(COPROCESSORS_ENABLED_CONF_KEY,
DEFAULT_COPROCESSORS_ENABLED);
LOG.info("System coprocessor loading is " + (coprocessorsEnabled ? "enabled" : "disabled"));
loadSystemCoprocessors(conf, MASTER_COPROCESSOR_CONF_KEY); loadSystemCoprocessors(conf, MASTER_COPROCESSOR_CONF_KEY);
} }

View File

@ -328,6 +328,14 @@ public class RegionCoprocessorHost
} }
void loadTableCoprocessors(final Configuration conf) { void loadTableCoprocessors(final Configuration conf) {
boolean coprocessorsEnabled = conf.getBoolean(COPROCESSORS_ENABLED_CONF_KEY,
DEFAULT_COPROCESSORS_ENABLED);
boolean tableCoprocessorsEnabled = conf.getBoolean(USER_COPROCESSORS_ENABLED_CONF_KEY,
DEFAULT_USER_COPROCESSORS_ENABLED);
if (!(coprocessorsEnabled && tableCoprocessorsEnabled)) {
return;
}
// scan the table attributes for coprocessor load specifications // scan the table attributes for coprocessor load specifications
// initialize the coprocessors // initialize the coprocessors
List<RegionEnvironment> configured = new ArrayList<RegionEnvironment>(); List<RegionEnvironment> configured = new ArrayList<RegionEnvironment>();

View File

@ -22,6 +22,8 @@ import java.io.IOException;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.classification.InterfaceStability; import org.apache.hadoop.hbase.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
@ -44,6 +46,8 @@ import org.apache.hadoop.hbase.replication.ReplicationEndpoint;
public class RegionServerCoprocessorHost extends public class RegionServerCoprocessorHost extends
CoprocessorHost<RegionServerCoprocessorHost.RegionServerEnvironment> { CoprocessorHost<RegionServerCoprocessorHost.RegionServerEnvironment> {
private static final Log LOG = LogFactory.getLog(RegionServerCoprocessorHost.class);
private RegionServerServices rsServices; private RegionServerServices rsServices;
public RegionServerCoprocessorHost(RegionServerServices rsServices, public RegionServerCoprocessorHost(RegionServerServices rsServices,
@ -51,7 +55,16 @@ public class RegionServerCoprocessorHost extends
super(rsServices); super(rsServices);
this.rsServices = rsServices; this.rsServices = rsServices;
this.conf = conf; this.conf = conf;
// load system default cp's from configuration. // Log the state of coprocessor loading here; should appear only once or
// twice in the daemon log, depending on HBase version, because there is
// only one RegionServerCoprocessorHost instance in the RS process
boolean coprocessorsEnabled = conf.getBoolean(COPROCESSORS_ENABLED_CONF_KEY,
DEFAULT_COPROCESSORS_ENABLED);
boolean tableCoprocessorsEnabled = conf.getBoolean(USER_COPROCESSORS_ENABLED_CONF_KEY,
DEFAULT_USER_COPROCESSORS_ENABLED);
LOG.info("System coprocessor loading is " + (coprocessorsEnabled ? "enabled" : "disabled"));
LOG.info("Table coprocessor loading is " +
((coprocessorsEnabled && tableCoprocessorsEnabled) ? "enabled" : "disabled"));
loadSystemCoprocessors(conf, REGIONSERVER_COPROCESSOR_CONF_KEY); loadSystemCoprocessors(conf, REGIONSERVER_COPROCESSOR_CONF_KEY);
} }

View File

@ -0,0 +1,172 @@
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.coprocessor;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
import org.apache.hadoop.hbase.regionserver.RegionServerServices;
import org.apache.hadoop.hbase.testclassification.CoprocessorTests;
import org.apache.hadoop.hbase.testclassification.SmallTests;
import org.junit.Test;
import org.junit.experimental.categories.Category;
/**
* Tests for global coprocessor loading configuration
*/
@Category({CoprocessorTests.class, SmallTests.class})
public class TestCoprocessorConfiguration {
private static final Configuration CONF = HBaseConfiguration.create();
static {
CONF.setStrings(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
SystemCoprocessor.class.getName());
CONF.setStrings(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY,
SystemCoprocessor.class.getName());
CONF.setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
SystemCoprocessor.class.getName());
}
private static final TableName TABLENAME = TableName.valueOf("TestCoprocessorConfiguration");
private static final HRegionInfo REGIONINFO = new HRegionInfo(TABLENAME);
private static final HTableDescriptor TABLEDESC = new HTableDescriptor(TABLENAME);
static {
try {
TABLEDESC.addCoprocessor(TableCoprocessor.class.getName());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// use atomic types in case coprocessor loading is ever multithreaded, also
// so we can mutate them even though they are declared final here
private static final AtomicBoolean systemCoprocessorLoaded = new AtomicBoolean();
private static final AtomicBoolean tableCoprocessorLoaded = new AtomicBoolean();
public static class SystemCoprocessor implements Coprocessor {
@Override
public void start(CoprocessorEnvironment env) throws IOException {
systemCoprocessorLoaded.set(true);
}
@Override
public void stop(CoprocessorEnvironment env) throws IOException { }
}
public static class TableCoprocessor implements Coprocessor {
@Override
public void start(CoprocessorEnvironment env) throws IOException {
tableCoprocessorLoaded.set(true);
}
@Override
public void stop(CoprocessorEnvironment env) throws IOException { }
}
@Test
public void testRegionCoprocessorHostDefaults() throws Exception {
Configuration conf = new Configuration(CONF);
HRegion region = mock(HRegion.class);
when(region.getRegionInfo()).thenReturn(REGIONINFO);
when(region.getTableDesc()).thenReturn(TABLEDESC);
RegionServerServices rsServices = mock(RegionServerServices.class);
systemCoprocessorLoaded.set(false);
tableCoprocessorLoaded.set(false);
new RegionCoprocessorHost(region, rsServices, conf);
assertEquals("System coprocessors loading default was not honored",
systemCoprocessorLoaded.get(),
CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED);
assertEquals("Table coprocessors loading default was not honored",
tableCoprocessorLoaded.get(),
CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED &&
CoprocessorHost.DEFAULT_USER_COPROCESSORS_ENABLED);
}
@Test
public void testRegionServerCoprocessorHostDefaults() throws Exception {
Configuration conf = new Configuration(CONF);
RegionServerServices rsServices = mock(RegionServerServices.class);
systemCoprocessorLoaded.set(false);
new RegionServerCoprocessorHost(rsServices, conf);
assertEquals("System coprocessors loading default was not honored",
systemCoprocessorLoaded.get(),
CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED);
}
@Test
public void testMasterCoprocessorHostDefaults() throws Exception {
Configuration conf = new Configuration(CONF);
MasterServices masterServices = mock(MasterServices.class);
systemCoprocessorLoaded.set(false);
new MasterCoprocessorHost(masterServices, conf);
assertEquals("System coprocessors loading default was not honored",
systemCoprocessorLoaded.get(),
CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED);
}
@Test
public void testRegionCoprocessorHostAllDisabled() throws Exception {
Configuration conf = new Configuration(CONF);
conf.setBoolean(CoprocessorHost.COPROCESSORS_ENABLED_CONF_KEY, false);
HRegion region = mock(HRegion.class);
when(region.getRegionInfo()).thenReturn(REGIONINFO);
when(region.getTableDesc()).thenReturn(TABLEDESC);
RegionServerServices rsServices = mock(RegionServerServices.class);
systemCoprocessorLoaded.set(false);
tableCoprocessorLoaded.set(false);
new RegionCoprocessorHost(region, rsServices, conf);
assertFalse("System coprocessors should not have been loaded",
systemCoprocessorLoaded.get());
assertFalse("Table coprocessors should not have been loaded",
tableCoprocessorLoaded.get());
}
@Test
public void testRegionCoprocessorHostTableLoadingDisabled() throws Exception {
Configuration conf = new Configuration(CONF);
conf.setBoolean(CoprocessorHost.COPROCESSORS_ENABLED_CONF_KEY, true); // if defaults change
conf.setBoolean(CoprocessorHost.USER_COPROCESSORS_ENABLED_CONF_KEY, false);
HRegion region = mock(HRegion.class);
when(region.getRegionInfo()).thenReturn(REGIONINFO);
when(region.getTableDesc()).thenReturn(TABLEDESC);
RegionServerServices rsServices = mock(RegionServerServices.class);
systemCoprocessorLoaded.set(false);
tableCoprocessorLoaded.set(false);
new RegionCoprocessorHost(region, rsServices, conf);
assertTrue("System coprocessors should have been loaded",
systemCoprocessorLoaded.get());
assertFalse("Table coprocessors should not have been loaded",
tableCoprocessorLoaded.get());
}
}