HBASE-25277 postScannerFilterRow impacts Scan performance a lot in HBase 2.x (#2751)
1. Added a check for Object class in RegionCoprocessorHost to avoid wrong initialization of hasCustomPostScannerFilterRow 2. Removed dummy implementation of postScannerFilterRow from AccessController, VisibilityController & ConstraintProcessor (which are not required currently) Signed-off-by Ramkrishna S Vasudevan <ramkrishna@apache.org> Signed-off-by Anoop Sam John <anoopsamjohn@apache.org> Signed-off-by: Duo Zhang <zhangduo@apache.org>
This commit is contained in:
parent
e855b627e0
commit
6ff02dedf8
|
@ -22,20 +22,19 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.apache.yetus.audience.InterfaceAudience;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.apache.hadoop.hbase.Cell;
|
|
||||||
import org.apache.hadoop.hbase.CoprocessorEnvironment;
|
import org.apache.hadoop.hbase.CoprocessorEnvironment;
|
||||||
import org.apache.hadoop.hbase.client.Put;
|
|
||||||
import org.apache.hadoop.hbase.client.Durability;
|
import org.apache.hadoop.hbase.client.Durability;
|
||||||
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
import org.apache.hadoop.hbase.client.TableDescriptor;
|
import org.apache.hadoop.hbase.client.TableDescriptor;
|
||||||
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
|
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
|
||||||
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor;
|
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor;
|
||||||
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
|
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
|
||||||
import org.apache.hadoop.hbase.coprocessor.RegionObserver;
|
import org.apache.hadoop.hbase.coprocessor.RegionObserver;
|
||||||
import org.apache.hadoop.hbase.regionserver.InternalScanner;
|
|
||||||
import org.apache.hadoop.hbase.wal.WALEdit;
|
import org.apache.hadoop.hbase.wal.WALEdit;
|
||||||
|
import org.apache.yetus.audience.InterfaceAudience;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Processes multiple {@link Constraint Constraints} on a given table.
|
* Processes multiple {@link Constraint Constraints} on a given table.
|
||||||
|
@ -98,11 +97,4 @@ public class ConstraintProcessor implements RegionCoprocessor, RegionObserver {
|
||||||
}
|
}
|
||||||
// if we made it here, then the Put is valid
|
// if we made it here, then the Put is valid
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean postScannerFilterRow(final ObserverContext<RegionCoprocessorEnvironment> e,
|
|
||||||
final InternalScanner s, final Cell curRowCell, final boolean hasMore) throws IOException {
|
|
||||||
// 'default' in RegionObserver might do unnecessary copy for Off heap backed Cells.
|
|
||||||
return hasMore;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,13 @@ public class RegionCoprocessorHost
|
||||||
// optimization: no need to call postScannerFilterRow, if no coprocessor implements it
|
// optimization: no need to call postScannerFilterRow, if no coprocessor implements it
|
||||||
private final boolean hasCustomPostScannerFilterRow;
|
private final boolean hasCustomPostScannerFilterRow;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Whether any configured CPs override postScannerFilterRow hook
|
||||||
|
*/
|
||||||
|
public boolean hasCustomPostScannerFilterRow() {
|
||||||
|
return hasCustomPostScannerFilterRow;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Encapsulation of the environment of each coprocessor
|
* Encapsulation of the environment of each coprocessor
|
||||||
|
@ -278,11 +285,10 @@ public class RegionCoprocessorHost
|
||||||
out: for (RegionCoprocessorEnvironment env: coprocEnvironments) {
|
out: for (RegionCoprocessorEnvironment env: coprocEnvironments) {
|
||||||
if (env.getInstance() instanceof RegionObserver) {
|
if (env.getInstance() instanceof RegionObserver) {
|
||||||
Class<?> clazz = env.getInstance().getClass();
|
Class<?> clazz = env.getInstance().getClass();
|
||||||
for(;;) {
|
for (;;) {
|
||||||
if (clazz == null) {
|
if (clazz == Object.class) {
|
||||||
// we must have directly implemented RegionObserver
|
// we dont need to look postScannerFilterRow into Object class
|
||||||
hasCustomPostScannerFilterRow = true;
|
break; // break the inner loop
|
||||||
break out;
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
clazz.getDeclaredMethod("postScannerFilterRow", ObserverContext.class,
|
clazz.getDeclaredMethod("postScannerFilterRow", ObserverContext.class,
|
||||||
|
|
|
@ -1852,13 +1852,6 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
|
||||||
scannerOwners.remove(s);
|
scannerOwners.remove(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean postScannerFilterRow(final ObserverContext<RegionCoprocessorEnvironment> e,
|
|
||||||
final InternalScanner s, final Cell curRowCell, final boolean hasMore) throws IOException {
|
|
||||||
// 'default' in RegionObserver might do unnecessary copy for Off heap backed Cells.
|
|
||||||
return hasMore;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify, when servicing an RPC, that the caller is the scanner owner.
|
* Verify, when servicing an RPC, that the caller is the scanner owner.
|
||||||
* If so, we assume that access control is correctly enforced based on
|
* If so, we assume that access control is correctly enforced based on
|
||||||
|
|
|
@ -677,13 +677,6 @@ public class VisibilityController implements MasterCoprocessor, RegionCoprocesso
|
||||||
return PrivateCellUtil.createCell(newCell, tags);
|
return PrivateCellUtil.createCell(newCell, tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean postScannerFilterRow(final ObserverContext<RegionCoprocessorEnvironment> e,
|
|
||||||
final InternalScanner s, final Cell curRowCell, final boolean hasMore) throws IOException {
|
|
||||||
// 'default' in RegionObserver might do unnecessary copy for Off heap backed Cells.
|
|
||||||
return hasMore;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************** VisibilityEndpoint service related methods ******************************/
|
/****************************** VisibilityEndpoint service related methods ******************************/
|
||||||
@Override
|
@Override
|
||||||
public synchronized void addLabels(RpcController controller, VisibilityLabelsRequest request,
|
public synchronized void addLabels(RpcController controller, VisibilityLabelsRequest request,
|
||||||
|
|
|
@ -22,11 +22,14 @@ import static org.apache.hadoop.hbase.coprocessor.CoprocessorHost.REGION_COPROCE
|
||||||
import static org.apache.hadoop.hbase.coprocessor.CoprocessorHost.SKIP_LOAD_DUPLICATE_TABLE_COPROCESSOR;
|
import static org.apache.hadoop.hbase.coprocessor.CoprocessorHost.SKIP_LOAD_DUPLICATE_TABLE_COPROCESSOR;
|
||||||
import static org.apache.hadoop.hbase.coprocessor.CoprocessorHost.USER_COPROCESSORS_ENABLED_CONF_KEY;
|
import static org.apache.hadoop.hbase.coprocessor.CoprocessorHost.USER_COPROCESSORS_ENABLED_CONF_KEY;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.hbase.CellComparator;
|
import org.apache.hadoop.hbase.CellComparator;
|
||||||
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
|
@ -58,7 +61,6 @@ import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.experimental.categories.Category;
|
import org.junit.experimental.categories.Category;
|
||||||
import org.junit.rules.TestName;
|
import org.junit.rules.TestName;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
@Category({SmallTests.class})
|
@Category({SmallTests.class})
|
||||||
public class TestRegionCoprocessorHost {
|
public class TestRegionCoprocessorHost {
|
||||||
|
@ -79,19 +81,36 @@ public class TestRegionCoprocessorHost {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws IOException {
|
public void setup() throws IOException {
|
||||||
|
init(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(Boolean flag) throws IOException {
|
||||||
conf = HBaseConfiguration.create();
|
conf = HBaseConfiguration.create();
|
||||||
conf.setBoolean(COPROCESSORS_ENABLED_CONF_KEY, true);
|
conf.setBoolean(COPROCESSORS_ENABLED_CONF_KEY, true);
|
||||||
conf.setBoolean(USER_COPROCESSORS_ENABLED_CONF_KEY, true);
|
conf.setBoolean(USER_COPROCESSORS_ENABLED_CONF_KEY, true);
|
||||||
TableName tableName = TableName.valueOf(name.getMethodName());
|
TableName tableName = TableName.valueOf(name.getMethodName());
|
||||||
regionInfo = RegionInfoBuilder.newBuilder(tableName).build();
|
regionInfo = RegionInfoBuilder.newBuilder(tableName).build();
|
||||||
// config a same coprocessor with system coprocessor
|
TableDescriptor tableDesc = null;
|
||||||
TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(tableName)
|
if (flag == null) {
|
||||||
.setCoprocessor(SimpleRegionObserver.class.getName()).build();
|
// configure a coprocessor which override postScannerFilterRow
|
||||||
|
tableDesc = TableDescriptorBuilder.newBuilder(tableName)
|
||||||
|
.setCoprocessor(SimpleRegionObserver.class.getName()).build();
|
||||||
|
} else if (flag) {
|
||||||
|
// configure a coprocessor which don't override postScannerFilterRow
|
||||||
|
tableDesc = TableDescriptorBuilder.newBuilder(tableName)
|
||||||
|
.setCoprocessor(TempRegionObserver.class.getName()).build();
|
||||||
|
} else {
|
||||||
|
// configure two coprocessors, one don't override postScannerFilterRow but another one does
|
||||||
|
conf.set(REGION_COPROCESSOR_CONF_KEY, TempRegionObserver.class.getName());
|
||||||
|
tableDesc = TableDescriptorBuilder.newBuilder(tableName)
|
||||||
|
.setCoprocessor(SimpleRegionObserver.class.getName()).build();
|
||||||
|
}
|
||||||
region = mock(HRegion.class);
|
region = mock(HRegion.class);
|
||||||
when(region.getRegionInfo()).thenReturn(regionInfo);
|
when(region.getRegionInfo()).thenReturn(regionInfo);
|
||||||
when(region.getTableDescriptor()).thenReturn(tableDesc);
|
when(region.getTableDescriptor()).thenReturn(tableDesc);
|
||||||
rsServices = mock(RegionServerServices.class);
|
rsServices = mock(RegionServerServices.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoadDuplicateCoprocessor() throws Exception {
|
public void testLoadDuplicateCoprocessor() throws Exception {
|
||||||
conf.setBoolean(SKIP_LOAD_DUPLICATE_TABLE_COPROCESSOR, true);
|
conf.setBoolean(SKIP_LOAD_DUPLICATE_TABLE_COPROCESSOR, true);
|
||||||
|
@ -158,6 +177,27 @@ public class TestRegionCoprocessorHost {
|
||||||
verifyScanInfo(newScanInfo);
|
verifyScanInfo(newScanInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPostScannerFilterRow() throws IOException {
|
||||||
|
// By default SimpleRegionObserver is set as region coprocessor which implements
|
||||||
|
// postScannerFilterRow
|
||||||
|
RegionCoprocessorHost host = new RegionCoprocessorHost(region, rsServices, conf);
|
||||||
|
assertTrue("Region coprocessor implement postScannerFilterRow",
|
||||||
|
host.hasCustomPostScannerFilterRow());
|
||||||
|
|
||||||
|
// Set a region CP which doesn't implement postScannerFilterRow
|
||||||
|
init(true);
|
||||||
|
host = new RegionCoprocessorHost(region, rsServices, conf);
|
||||||
|
assertFalse("Region coprocessor implement postScannerFilterRow",
|
||||||
|
host.hasCustomPostScannerFilterRow());
|
||||||
|
|
||||||
|
// Set multiple region CPs, in which one implements postScannerFilterRow
|
||||||
|
init(false);
|
||||||
|
host = new RegionCoprocessorHost(region, rsServices, conf);
|
||||||
|
assertTrue("Region coprocessor doesn't implement postScannerFilterRow",
|
||||||
|
host.hasCustomPostScannerFilterRow());
|
||||||
|
}
|
||||||
|
|
||||||
private void verifyScanInfo(ScanInfo newScanInfo) {
|
private void verifyScanInfo(ScanInfo newScanInfo) {
|
||||||
assertEquals(KeepDeletedCells.TRUE, newScanInfo.getKeepDeletedCells());
|
assertEquals(KeepDeletedCells.TRUE, newScanInfo.getKeepDeletedCells());
|
||||||
assertEquals(MAX_VERSIONS, newScanInfo.getMaxVersions());
|
assertEquals(MAX_VERSIONS, newScanInfo.getMaxVersions());
|
||||||
|
@ -175,4 +215,13 @@ public class TestRegionCoprocessorHost {
|
||||||
CellComparator.getInstance(), true);
|
CellComparator.getInstance(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple region coprocessor which doesn't override postScannerFilterRow
|
||||||
|
*/
|
||||||
|
public static class TempRegionObserver implements RegionCoprocessor, RegionObserver {
|
||||||
|
@Override
|
||||||
|
public Optional<RegionObserver> getRegionObserver() {
|
||||||
|
return Optional.of(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue