HBASE-3583 Coprocessors: scannerNext and scannerClose hooks are called when HRegionInterface#get is invoked
git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1084854 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c63fe3174a
commit
a17043496b
|
@ -46,6 +46,9 @@ Release 0.91.0 - Unreleased
|
||||||
HBASE-3532 HRegion#equals is broken (Ted Yu via Stack)
|
HBASE-3532 HRegion#equals is broken (Ted Yu via Stack)
|
||||||
HBASE-3697 Admin actions that use MetaReader to iterate regions need to
|
HBASE-3697 Admin actions that use MetaReader to iterate regions need to
|
||||||
skip offline ones
|
skip offline ones
|
||||||
|
HBASE-3583 Coprocessors: scannerNext and scannerClose hooks are called
|
||||||
|
when HRegionInterface#get is invoked (Mingjie Lai via
|
||||||
|
Andrew Purtell)
|
||||||
|
|
||||||
IMPROVEMENTS
|
IMPROVEMENTS
|
||||||
HBASE-3290 Max Compaction Size (Nicolas Spiegelberg via Stack)
|
HBASE-3290 Max Compaction Size (Nicolas Spiegelberg via Stack)
|
||||||
|
|
|
@ -206,14 +206,14 @@ public abstract class BaseRegionObserverCoprocessor implements RegionObserver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preScannerNext(final RegionCoprocessorEnvironment e,
|
public boolean preScannerNext(final RegionCoprocessorEnvironment e,
|
||||||
final InternalScanner s, final List<KeyValue> results,
|
final InternalScanner s, final List<Result> results,
|
||||||
final int limit, final boolean hasMore) throws IOException {
|
final int limit, final boolean hasMore) throws IOException {
|
||||||
return hasMore;
|
return hasMore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean postScannerNext(final RegionCoprocessorEnvironment e,
|
public boolean postScannerNext(final RegionCoprocessorEnvironment e,
|
||||||
final InternalScanner s, final List<KeyValue> results, final int limit,
|
final InternalScanner s, final List<Result> results, final int limit,
|
||||||
final boolean hasMore) throws IOException {
|
final boolean hasMore) throws IOException {
|
||||||
return hasMore;
|
return hasMore;
|
||||||
}
|
}
|
||||||
|
|
|
@ -492,7 +492,7 @@ public interface RegionObserver extends Coprocessor {
|
||||||
* @throws IOException if an error occurred on the coprocessor
|
* @throws IOException if an error occurred on the coprocessor
|
||||||
*/
|
*/
|
||||||
public boolean preScannerNext(final RegionCoprocessorEnvironment e,
|
public boolean preScannerNext(final RegionCoprocessorEnvironment e,
|
||||||
final InternalScanner s, final List<KeyValue> result,
|
final InternalScanner s, final List<Result> result,
|
||||||
final int limit, final boolean hasNext)
|
final int limit, final boolean hasNext)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
|
@ -510,7 +510,7 @@ public interface RegionObserver extends Coprocessor {
|
||||||
* @throws IOException if an error occurred on the coprocessor
|
* @throws IOException if an error occurred on the coprocessor
|
||||||
*/
|
*/
|
||||||
public boolean postScannerNext(final RegionCoprocessorEnvironment e,
|
public boolean postScannerNext(final RegionCoprocessorEnvironment e,
|
||||||
final InternalScanner s, final List<KeyValue> result, final int limit,
|
final InternalScanner s, final List<Result> result, final int limit,
|
||||||
final boolean hasNext)
|
final boolean hasNext)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
|
|
|
@ -2461,14 +2461,6 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
|
|
||||||
public synchronized boolean next(List<KeyValue> outResults, int limit)
|
public synchronized boolean next(List<KeyValue> outResults, int limit)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (coprocessorHost != null) {
|
|
||||||
Boolean result = coprocessorHost.preScannerNext((InternalScanner)this,
|
|
||||||
outResults, limit);
|
|
||||||
if (result != null) {
|
|
||||||
return result.booleanValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.filterClosed) {
|
if (this.filterClosed) {
|
||||||
throw new UnknownScannerException("Scanner was closed (timed out?) " +
|
throw new UnknownScannerException("Scanner was closed (timed out?) " +
|
||||||
"after we renewed it. Could be caused by a very slow scanner " +
|
"after we renewed it. Could be caused by a very slow scanner " +
|
||||||
|
@ -2484,11 +2476,6 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
|
|
||||||
boolean returnResult = nextInternal(limit);
|
boolean returnResult = nextInternal(limit);
|
||||||
|
|
||||||
if (coprocessorHost != null) {
|
|
||||||
returnResult = coprocessorHost.postScannerNext((InternalScanner)this,
|
|
||||||
results, limit, returnResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
outResults.addAll(results);
|
outResults.addAll(results);
|
||||||
resetFilters();
|
resetFilters();
|
||||||
if (isFilterDone()) {
|
if (isFilterDone()) {
|
||||||
|
@ -2596,20 +2583,12 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
currentRow, 0, currentRow.length) <= isScan);
|
currentRow, 0, currentRow.length) <= isScan);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void close() throws IOException {
|
public synchronized void close() {
|
||||||
if (coprocessorHost != null) {
|
|
||||||
if (coprocessorHost.preScannerClose((InternalScanner)this)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (storeHeap != null) {
|
if (storeHeap != null) {
|
||||||
storeHeap.close();
|
storeHeap.close();
|
||||||
storeHeap = null;
|
storeHeap = null;
|
||||||
}
|
}
|
||||||
this.filterClosed = true;
|
this.filterClosed = true;
|
||||||
if (coprocessorHost != null) {
|
|
||||||
coprocessorHost.postScannerClose((InternalScanner)this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1929,6 +1929,32 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler,
|
||||||
List<Result> results = new ArrayList<Result>(nbRows);
|
List<Result> results = new ArrayList<Result>(nbRows);
|
||||||
long currentScanResultSize = 0;
|
long currentScanResultSize = 0;
|
||||||
List<KeyValue> values = new ArrayList<KeyValue>();
|
List<KeyValue> values = new ArrayList<KeyValue>();
|
||||||
|
|
||||||
|
// Call coprocessor. Get region info from scanner.
|
||||||
|
HRegion region = null;
|
||||||
|
if (s instanceof HRegion.RegionScanner) {
|
||||||
|
HRegion.RegionScanner rs = (HRegion.RegionScanner) s;
|
||||||
|
region = getRegion(rs.getRegionName().getRegionName());
|
||||||
|
} else {
|
||||||
|
throw new IOException("InternalScanner implementation is expected " +
|
||||||
|
"to be HRegion.RegionScanner.");
|
||||||
|
}
|
||||||
|
if (region != null && region.getCoprocessorHost() != null) {
|
||||||
|
Boolean bypass = region.getCoprocessorHost().preScannerNext(s,
|
||||||
|
results, nbRows);
|
||||||
|
if (!results.isEmpty()) {
|
||||||
|
for (Result r : results) {
|
||||||
|
for (KeyValue kv : r.raw()) {
|
||||||
|
currentScanResultSize += kv.heapSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bypass != null) {
|
||||||
|
return ((HRegion.RegionScanner) s).isFilterDone() && results.isEmpty() ? null
|
||||||
|
: results.toArray(new Result[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < nbRows
|
for (int i = 0; i < nbRows
|
||||||
&& currentScanResultSize < maxScannerResultSize; i++) {
|
&& currentScanResultSize < maxScannerResultSize; i++) {
|
||||||
requestCount.incrementAndGet();
|
requestCount.incrementAndGet();
|
||||||
|
@ -1945,6 +1971,12 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler,
|
||||||
}
|
}
|
||||||
values.clear();
|
values.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// coprocessor postNext hook
|
||||||
|
if (region != null && region.getCoprocessorHost() != null) {
|
||||||
|
region.getCoprocessorHost().postScannerNext(s, results, nbRows, true);
|
||||||
|
}
|
||||||
|
|
||||||
// Below is an ugly hack where we cast the InternalScanner to be a
|
// Below is an ugly hack where we cast the InternalScanner to be a
|
||||||
// HRegion.RegionScanner. The alternative is to change InternalScanner
|
// HRegion.RegionScanner. The alternative is to change InternalScanner
|
||||||
// interface but its used everywhere whereas we just need a bit of info
|
// interface but its used everywhere whereas we just need a bit of info
|
||||||
|
@ -1967,10 +1999,33 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler,
|
||||||
checkOpen();
|
checkOpen();
|
||||||
requestCount.incrementAndGet();
|
requestCount.incrementAndGet();
|
||||||
String scannerName = String.valueOf(scannerId);
|
String scannerName = String.valueOf(scannerId);
|
||||||
InternalScanner s = scanners.remove(scannerName);
|
InternalScanner s = scanners.get(scannerName);
|
||||||
|
|
||||||
|
HRegion region = null;
|
||||||
|
if (s != null) {
|
||||||
|
// call coprocessor.
|
||||||
|
if (s instanceof HRegion.RegionScanner) {
|
||||||
|
HRegion.RegionScanner rs = (HRegion.RegionScanner) s;
|
||||||
|
region = getRegion(rs.getRegionName().getRegionName());
|
||||||
|
} else {
|
||||||
|
throw new IOException("InternalScanner implementation is expected " +
|
||||||
|
"to be HRegion.RegionScanner.");
|
||||||
|
}
|
||||||
|
if (region != null && region.getCoprocessorHost() != null) {
|
||||||
|
if (region.getCoprocessorHost().preScannerClose(s)) {
|
||||||
|
return; // bypass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = scanners.remove(scannerName);
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
s.close();
|
s.close();
|
||||||
this.leases.cancelLease(scannerName);
|
this.leases.cancelLease(scannerName);
|
||||||
|
|
||||||
|
if (region != null && region.getCoprocessorHost() != null) {
|
||||||
|
region.getCoprocessorHost().postScannerClose(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
throw convertThrowableToIOE(cleanup(t));
|
throw convertThrowableToIOE(cleanup(t));
|
||||||
|
|
|
@ -911,7 +911,7 @@ public class RegionCoprocessorHost
|
||||||
* @exception IOException Exception
|
* @exception IOException Exception
|
||||||
*/
|
*/
|
||||||
public Boolean preScannerNext(final InternalScanner s,
|
public Boolean preScannerNext(final InternalScanner s,
|
||||||
final List<KeyValue> results, int limit) throws IOException {
|
final List<Result> results, int limit) throws IOException {
|
||||||
try {
|
try {
|
||||||
boolean bypass = false;
|
boolean bypass = false;
|
||||||
boolean hasNext = false;
|
boolean hasNext = false;
|
||||||
|
@ -941,7 +941,7 @@ public class RegionCoprocessorHost
|
||||||
* @exception IOException Exception
|
* @exception IOException Exception
|
||||||
*/
|
*/
|
||||||
public boolean postScannerNext(final InternalScanner s,
|
public boolean postScannerNext(final InternalScanner s,
|
||||||
final List<KeyValue> results, final int limit, boolean hasMore)
|
final List<Result> results, final int limit, boolean hasMore)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
try {
|
try {
|
||||||
coprocessorLock.readLock().lock();
|
coprocessorLock.readLock().lock();
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.apache.hadoop.hbase.client.Get;
|
||||||
import org.apache.hadoop.hbase.client.Increment;
|
import org.apache.hadoop.hbase.client.Increment;
|
||||||
import org.apache.hadoop.hbase.client.Result;
|
import org.apache.hadoop.hbase.client.Result;
|
||||||
import org.apache.hadoop.hbase.regionserver.HRegion;
|
import org.apache.hadoop.hbase.regionserver.HRegion;
|
||||||
|
import org.apache.hadoop.hbase.regionserver.InternalScanner;
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,6 +69,10 @@ public class SimpleRegionObserver extends BaseRegionObserverCoprocessor {
|
||||||
boolean hadPostIncrement = false;
|
boolean hadPostIncrement = false;
|
||||||
boolean hadPreWALRestored = false;
|
boolean hadPreWALRestored = false;
|
||||||
boolean hadPostWALRestored = false;
|
boolean hadPostWALRestored = false;
|
||||||
|
boolean hadPreScannerNext = false;
|
||||||
|
boolean hadPostScannerNext = false;
|
||||||
|
boolean hadPreScannerClose = false;
|
||||||
|
boolean hadPostScannerClose = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preOpen(RegionCoprocessorEnvironment e) {
|
public void preOpen(RegionCoprocessorEnvironment e) {
|
||||||
|
@ -135,6 +140,35 @@ public class SimpleRegionObserver extends BaseRegionObserverCoprocessor {
|
||||||
hadPostCompact = true;
|
hadPostCompact = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preScannerNext(final RegionCoprocessorEnvironment e,
|
||||||
|
final InternalScanner s, final List<Result> results,
|
||||||
|
final int limit, final boolean hasMore) throws IOException {
|
||||||
|
hadPreScannerNext = true;
|
||||||
|
return hasMore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean postScannerNext(final RegionCoprocessorEnvironment e,
|
||||||
|
final InternalScanner s, final List<Result> results, final int limit,
|
||||||
|
final boolean hasMore) throws IOException {
|
||||||
|
hadPostScannerNext = true;
|
||||||
|
return hasMore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preScannerClose(final RegionCoprocessorEnvironment e,
|
||||||
|
final InternalScanner s) throws IOException {
|
||||||
|
hadPreScannerClose = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postScannerClose(final RegionCoprocessorEnvironment e,
|
||||||
|
final InternalScanner s) throws IOException {
|
||||||
|
hadPostScannerClose = true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean wasCompacted() {
|
public boolean wasCompacted() {
|
||||||
return hadPreCompact && hadPostCompact;
|
return hadPreCompact && hadPostCompact;
|
||||||
}
|
}
|
||||||
|
@ -146,10 +180,7 @@ public class SimpleRegionObserver extends BaseRegionObserverCoprocessor {
|
||||||
assertNotNull(e.getRegion());
|
assertNotNull(e.getRegion());
|
||||||
assertNotNull(get);
|
assertNotNull(get);
|
||||||
assertNotNull(results);
|
assertNotNull(results);
|
||||||
if (Arrays.equals(e.getRegion().getTableDesc().getName(),
|
hadPreGet = true;
|
||||||
TestRegionObserverInterface.TEST_TABLE)) {
|
|
||||||
hadPreGet = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -178,8 +209,8 @@ public class SimpleRegionObserver extends BaseRegionObserverCoprocessor {
|
||||||
assertTrue(foundA);
|
assertTrue(foundA);
|
||||||
assertTrue(foundB);
|
assertTrue(foundB);
|
||||||
assertTrue(foundC);
|
assertTrue(foundC);
|
||||||
hadPostGet = true;
|
|
||||||
}
|
}
|
||||||
|
hadPostGet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -205,8 +236,8 @@ public class SimpleRegionObserver extends BaseRegionObserverCoprocessor {
|
||||||
assertNotNull(kvs.get(0));
|
assertNotNull(kvs.get(0));
|
||||||
assertTrue(Bytes.equals(kvs.get(0).getQualifier(),
|
assertTrue(Bytes.equals(kvs.get(0).getQualifier(),
|
||||||
TestRegionObserverInterface.C));
|
TestRegionObserverInterface.C));
|
||||||
hadPrePut = true;
|
|
||||||
}
|
}
|
||||||
|
hadPrePut = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -232,8 +263,8 @@ public class SimpleRegionObserver extends BaseRegionObserverCoprocessor {
|
||||||
assertNotNull(kvs.get(0));
|
assertNotNull(kvs.get(0));
|
||||||
assertTrue(Bytes.equals(kvs.get(0).getQualifier(),
|
assertTrue(Bytes.equals(kvs.get(0).getQualifier(),
|
||||||
TestRegionObserverInterface.C));
|
TestRegionObserverInterface.C));
|
||||||
hadPostPut = true;
|
|
||||||
}
|
}
|
||||||
|
hadPostPut = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -242,8 +273,7 @@ public class SimpleRegionObserver extends BaseRegionObserverCoprocessor {
|
||||||
assertNotNull(e);
|
assertNotNull(e);
|
||||||
assertNotNull(e.getRegion());
|
assertNotNull(e.getRegion());
|
||||||
assertNotNull(familyMap);
|
assertNotNull(familyMap);
|
||||||
if (beforeDelete && e.getRegion().getTableDesc().getName().equals(
|
if (beforeDelete) {
|
||||||
TestRegionObserverInterface.TEST_TABLE)) {
|
|
||||||
hadPreDeleted = true;
|
hadPreDeleted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,11 +284,8 @@ public class SimpleRegionObserver extends BaseRegionObserverCoprocessor {
|
||||||
assertNotNull(e);
|
assertNotNull(e);
|
||||||
assertNotNull(e.getRegion());
|
assertNotNull(e.getRegion());
|
||||||
assertNotNull(familyMap);
|
assertNotNull(familyMap);
|
||||||
if (Arrays.equals(e.getRegion().getTableDesc().getName(),
|
beforeDelete = false;
|
||||||
TestRegionObserverInterface.TEST_TABLE)) {
|
hadPostDeleted = true;
|
||||||
beforeDelete = false;
|
|
||||||
hadPostDeleted = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -269,8 +296,7 @@ public class SimpleRegionObserver extends BaseRegionObserverCoprocessor {
|
||||||
assertNotNull(e.getRegion());
|
assertNotNull(e.getRegion());
|
||||||
assertNotNull(row);
|
assertNotNull(row);
|
||||||
assertNotNull(result);
|
assertNotNull(result);
|
||||||
if (beforeDelete && e.getRegion().getTableDesc().getName().equals(
|
if (beforeDelete) {
|
||||||
TestRegionObserverInterface.TEST_TABLE)) {
|
|
||||||
hadPreGetClosestRowBefore = true;
|
hadPreGetClosestRowBefore = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,63 +309,59 @@ public class SimpleRegionObserver extends BaseRegionObserverCoprocessor {
|
||||||
assertNotNull(e.getRegion());
|
assertNotNull(e.getRegion());
|
||||||
assertNotNull(row);
|
assertNotNull(row);
|
||||||
assertNotNull(result);
|
assertNotNull(result);
|
||||||
if (Arrays.equals(e.getRegion().getTableDesc().getName(),
|
hadPostGetClosestRowBefore = true;
|
||||||
TestRegionObserverInterface.TEST_TABLE)) {
|
|
||||||
hadPostGetClosestRowBefore = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preIncrement(final RegionCoprocessorEnvironment e,
|
public void preIncrement(final RegionCoprocessorEnvironment e,
|
||||||
final Increment increment, final Result result) throws IOException {
|
final Increment increment, final Result result) throws IOException {
|
||||||
if (Arrays.equals(e.getRegion().getTableDesc().getName(),
|
hadPreIncrement = true;
|
||||||
TestRegionObserverInterface.TEST_TABLE_2)) {
|
|
||||||
hadPreIncrement = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postIncrement(final RegionCoprocessorEnvironment e,
|
public void postIncrement(final RegionCoprocessorEnvironment e,
|
||||||
final Increment increment, final Result result) throws IOException {
|
final Increment increment, final Result result) throws IOException {
|
||||||
if (Arrays.equals(e.getRegion().getTableDesc().getName(),
|
hadPostIncrement = true;
|
||||||
TestRegionObserverInterface.TEST_TABLE_2)) {
|
|
||||||
hadPostIncrement = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hadPreGet() {
|
public boolean hadPreGet() {
|
||||||
return hadPreGet;
|
return hadPreGet;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hadPostGet() {
|
public boolean hadPostGet() {
|
||||||
return hadPostGet;
|
return hadPostGet;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hadPrePut() {
|
public boolean hadPrePut() {
|
||||||
return hadPrePut;
|
return hadPrePut;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hadPostPut() {
|
public boolean hadPostPut() {
|
||||||
return hadPostPut;
|
return hadPostPut;
|
||||||
}
|
}
|
||||||
|
public boolean hadDelete() {
|
||||||
boolean hadDelete() {
|
|
||||||
return !beforeDelete;
|
return !beforeDelete;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hadPreIncrement() {
|
public boolean hadPreIncrement() {
|
||||||
return hadPreIncrement;
|
return hadPreIncrement;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hadPostIncrement() {
|
public boolean hadPostIncrement() {
|
||||||
return hadPostIncrement;
|
return hadPostIncrement;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hadPreWALRestored() {
|
public boolean hadPreWALRestored() {
|
||||||
return hadPreWALRestored;
|
return hadPreWALRestored;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hadPostWALRestored() {
|
public boolean hadPostWALRestored() {
|
||||||
return hadPostWALRestored;
|
return hadPostWALRestored;
|
||||||
}
|
}
|
||||||
|
public boolean wasScannerNextCalled() {
|
||||||
|
return hadPreScannerNext && hadPostScannerNext;
|
||||||
|
}
|
||||||
|
public boolean wasScannerCloseCalled() {
|
||||||
|
return hadPreScannerClose && hadPostScannerClose;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
package org.apache.hadoop.hbase.coprocessor;
|
package org.apache.hadoop.hbase.coprocessor;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
@ -32,11 +33,7 @@ import org.apache.hadoop.hbase.HColumnDescriptor;
|
||||||
import org.apache.hadoop.hbase.HRegionInfo;
|
import org.apache.hadoop.hbase.HRegionInfo;
|
||||||
import org.apache.hadoop.hbase.HTableDescriptor;
|
import org.apache.hadoop.hbase.HTableDescriptor;
|
||||||
import org.apache.hadoop.hbase.MiniHBaseCluster;
|
import org.apache.hadoop.hbase.MiniHBaseCluster;
|
||||||
import org.apache.hadoop.hbase.client.Delete;
|
import org.apache.hadoop.hbase.client.*;
|
||||||
import org.apache.hadoop.hbase.client.Get;
|
|
||||||
import org.apache.hadoop.hbase.client.HTable;
|
|
||||||
import org.apache.hadoop.hbase.client.Increment;
|
|
||||||
import org.apache.hadoop.hbase.client.Put;
|
|
||||||
import org.apache.hadoop.hbase.coprocessor.Coprocessor.Priority;
|
import org.apache.hadoop.hbase.coprocessor.Coprocessor.Priority;
|
||||||
import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
|
import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
|
||||||
import org.apache.hadoop.hbase.regionserver.HRegion;
|
import org.apache.hadoop.hbase.regionserver.HRegion;
|
||||||
|
@ -47,6 +44,8 @@ import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.el.MethodNotFoundException;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class TestRegionObserverInterface {
|
public class TestRegionObserverInterface {
|
||||||
|
@ -54,16 +53,10 @@ public class TestRegionObserverInterface {
|
||||||
static final String DIR = "test/build/data/TestRegionObserver/";
|
static final String DIR = "test/build/data/TestRegionObserver/";
|
||||||
|
|
||||||
public static final byte[] TEST_TABLE = Bytes.toBytes("TestTable");
|
public static final byte[] TEST_TABLE = Bytes.toBytes("TestTable");
|
||||||
public static final byte[] TEST_TABLE_2 = Bytes.toBytes("TestTable2");
|
|
||||||
public static final byte[] TEST_FAMILY = Bytes.toBytes("TestFamily");
|
|
||||||
public static final byte[] TEST_QUALIFIER = Bytes.toBytes("TestQualifier");
|
|
||||||
|
|
||||||
public final static byte[] A = Bytes.toBytes("a");
|
public final static byte[] A = Bytes.toBytes("a");
|
||||||
public final static byte[] B = Bytes.toBytes("b");
|
public final static byte[] B = Bytes.toBytes("b");
|
||||||
public final static byte[] C = Bytes.toBytes("c");
|
public final static byte[] C = Bytes.toBytes("c");
|
||||||
public final static byte[] ROW = Bytes.toBytes("testrow");
|
public final static byte[] ROW = Bytes.toBytes("testrow");
|
||||||
public final static byte[] ROW1 = Bytes.toBytes("testrow1");
|
|
||||||
public final static byte[] ROW2 = Bytes.toBytes("testrow2");
|
|
||||||
|
|
||||||
private static final int ROWSIZE = 20;
|
private static final int ROWSIZE = 20;
|
||||||
private static byte [][] ROWS = makeN(ROW, ROWSIZE);
|
private static byte [][] ROWS = makeN(ROW, ROWSIZE);
|
||||||
|
@ -80,17 +73,6 @@ public class TestRegionObserverInterface {
|
||||||
|
|
||||||
util.startMiniCluster(2);
|
util.startMiniCluster(2);
|
||||||
cluster = util.getMiniHBaseCluster();
|
cluster = util.getMiniHBaseCluster();
|
||||||
|
|
||||||
HTable table = util.createTable(TEST_TABLE_2, TEST_FAMILY);
|
|
||||||
|
|
||||||
for(int i = 0; i < ROWSIZE; i++) {
|
|
||||||
Put put = new Put(ROWS[i]);
|
|
||||||
put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(i));
|
|
||||||
table.put(put);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sleep here is an ugly hack to allow region transitions to finish
|
|
||||||
Thread.sleep(5000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
@ -98,87 +80,157 @@ public class TestRegionObserverInterface {
|
||||||
util.shutdownMiniCluster();
|
util.shutdownMiniCluster();
|
||||||
}
|
}
|
||||||
|
|
||||||
HRegion initHRegion (byte [] tableName, String callingMethod,
|
|
||||||
Configuration conf, Class<?> implClass, byte [] ... families)
|
|
||||||
throws IOException{
|
|
||||||
HTableDescriptor htd = new HTableDescriptor(tableName);
|
|
||||||
for(byte [] family : families) {
|
|
||||||
htd.addFamily(new HColumnDescriptor(family));
|
|
||||||
}
|
|
||||||
HRegionInfo info = new HRegionInfo(htd, null, null, false);
|
|
||||||
Path path = new Path(DIR + callingMethod);
|
|
||||||
// this following piece is a hack. currently a coprocessorHost
|
|
||||||
// is secretly loaded at OpenRegionHandler. we don't really
|
|
||||||
// start a region server here, so just manually create cphost
|
|
||||||
// and set it to region.
|
|
||||||
HRegion r = HRegion.createHRegion(info, path, conf);
|
|
||||||
RegionCoprocessorHost host = new RegionCoprocessorHost(r, null, conf);
|
|
||||||
r.setCoprocessorHost(host);
|
|
||||||
host.load(implClass, Priority.USER);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegionObserver() throws IOException {
|
public void testRegionObserver() throws IOException {
|
||||||
byte[] TABLE = Bytes.toBytes(getClass().getName());
|
byte[] tableName = TEST_TABLE;
|
||||||
byte[][] FAMILIES = new byte[][] { A, B, C } ;
|
// recreate table every time in order to reset the status of the
|
||||||
|
// coproccessor.
|
||||||
|
HTable table = util.createTable(tableName, new byte[][] {A, B, C});
|
||||||
|
verifyMethodResult(SimpleRegionObserver.class,
|
||||||
|
new String[] {"hadPreGet", "hadPostGet", "hadPrePut", "hadPostPut",
|
||||||
|
"hadDelete"},
|
||||||
|
TEST_TABLE,
|
||||||
|
new Boolean[] {false, false, false, false, false});
|
||||||
|
|
||||||
Put put = new Put(ROW);
|
Put put = new Put(ROW);
|
||||||
put.add(A, A, A);
|
put.add(A, A, A);
|
||||||
put.add(B, B, B);
|
put.add(B, B, B);
|
||||||
put.add(C, C, C);
|
put.add(C, C, C);
|
||||||
|
table.put(put);
|
||||||
|
|
||||||
|
verifyMethodResult(SimpleRegionObserver.class,
|
||||||
|
new String[] {"hadPreGet", "hadPostGet", "hadPrePut", "hadPostPut",
|
||||||
|
"hadDelete"},
|
||||||
|
TEST_TABLE,
|
||||||
|
new Boolean[] {false, false, true, true, false}
|
||||||
|
);
|
||||||
|
|
||||||
Get get = new Get(ROW);
|
Get get = new Get(ROW);
|
||||||
get.addColumn(A, A);
|
get.addColumn(A, A);
|
||||||
get.addColumn(B, B);
|
get.addColumn(B, B);
|
||||||
get.addColumn(C, C);
|
get.addColumn(C, C);
|
||||||
|
table.get(get);
|
||||||
|
|
||||||
|
verifyMethodResult(SimpleRegionObserver.class,
|
||||||
|
new String[] {"hadPreGet", "hadPostGet", "hadPrePut", "hadPostPut",
|
||||||
|
"hadDelete"},
|
||||||
|
TEST_TABLE,
|
||||||
|
new Boolean[] {true, true, true, true, false}
|
||||||
|
);
|
||||||
|
|
||||||
Delete delete = new Delete(ROW);
|
Delete delete = new Delete(ROW);
|
||||||
delete.deleteColumn(A, A);
|
delete.deleteColumn(A, A);
|
||||||
delete.deleteColumn(B, B);
|
delete.deleteColumn(B, B);
|
||||||
delete.deleteColumn(C, C);
|
delete.deleteColumn(C, C);
|
||||||
|
table.delete(delete);
|
||||||
|
|
||||||
for (JVMClusterUtil.RegionServerThread t : cluster.getRegionServerThreads()) {
|
verifyMethodResult(SimpleRegionObserver.class,
|
||||||
for (HRegionInfo r : t.getRegionServer().getOnlineRegions()) {
|
new String[] {"hadPreGet", "hadPostGet", "hadPrePut", "hadPostPut",
|
||||||
if (!Arrays.equals(r.getTableDesc().getName(), TEST_TABLE)) {
|
"hadDelete"},
|
||||||
continue;
|
TEST_TABLE,
|
||||||
}
|
new Boolean[] {true, true, true, true, true}
|
||||||
RegionCoprocessorHost cph = t.getRegionServer().getOnlineRegion(r.getRegionName()).
|
);
|
||||||
getCoprocessorHost();
|
util.deleteTable(tableName);
|
||||||
Coprocessor c = cph.findCoprocessor(SimpleRegionObserver.class.getName());
|
|
||||||
assertNotNull(c);
|
|
||||||
assertTrue(((SimpleRegionObserver)c).hadPreGet());
|
|
||||||
assertTrue(((SimpleRegionObserver)c).hadPostGet());
|
|
||||||
assertTrue(((SimpleRegionObserver)c).hadPrePut());
|
|
||||||
assertTrue(((SimpleRegionObserver)c).hadPostPut());
|
|
||||||
assertTrue(((SimpleRegionObserver)c).hadDelete());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add tests for other methods which need to be tested
|
|
||||||
// at region servers.
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIncrementHook() throws IOException {
|
public void testIncrementHook() throws IOException {
|
||||||
HTable table = new HTable(util.getConfiguration(), TEST_TABLE_2);
|
byte[] tableName = TEST_TABLE;
|
||||||
|
|
||||||
|
HTable table = util.createTable(tableName, new byte[][] {A, B, C});
|
||||||
Increment inc = new Increment(Bytes.toBytes(0));
|
Increment inc = new Increment(Bytes.toBytes(0));
|
||||||
inc.addColumn(TEST_FAMILY, TEST_QUALIFIER, 1);
|
inc.addColumn(A, A, 1);
|
||||||
|
|
||||||
|
verifyMethodResult(SimpleRegionObserver.class,
|
||||||
|
new String[] {"hadPreIncrement", "hadPostIncrement"},
|
||||||
|
tableName,
|
||||||
|
new Boolean[] {false, false}
|
||||||
|
);
|
||||||
|
|
||||||
table.increment(inc);
|
table.increment(inc);
|
||||||
|
|
||||||
for (JVMClusterUtil.RegionServerThread t : cluster.getRegionServerThreads()) {
|
verifyMethodResult(SimpleRegionObserver.class,
|
||||||
for (HRegionInfo r : t.getRegionServer().getOnlineRegions()) {
|
new String[] {"hadPreIncrement", "hadPostIncrement"},
|
||||||
if (!Arrays.equals(r.getTableDesc().getName(), TEST_TABLE_2)) {
|
tableName,
|
||||||
continue;
|
new Boolean[] {true, true}
|
||||||
}
|
);
|
||||||
RegionCoprocessorHost cph = t.getRegionServer().getOnlineRegion(r.getRegionName()).
|
util.deleteTable(tableName);
|
||||||
getCoprocessorHost();
|
}
|
||||||
Coprocessor c = cph.findCoprocessor(SimpleRegionObserver.class.getName());
|
|
||||||
assertTrue(((SimpleRegionObserver)c).hadPreIncrement());
|
@Test
|
||||||
assertTrue(((SimpleRegionObserver)c).hadPostIncrement());
|
// HBase-3583
|
||||||
|
public void testHBase3583() throws IOException {
|
||||||
|
byte[] tableName = Bytes.toBytes("testHBase3583");
|
||||||
|
util.createTable(tableName, new byte[][] {A, B, C});
|
||||||
|
|
||||||
|
verifyMethodResult(SimpleRegionObserver.class,
|
||||||
|
new String[] {"hadPreGet", "hadPostGet", "wasScannerNextCalled",
|
||||||
|
"wasScannerCloseCalled"},
|
||||||
|
tableName,
|
||||||
|
new Boolean[] {false, false, false, false}
|
||||||
|
);
|
||||||
|
|
||||||
|
HTable table = new HTable(util.getConfiguration(), tableName);
|
||||||
|
Put put = new Put(ROW);
|
||||||
|
put.add(A, A, A);
|
||||||
|
table.put(put);
|
||||||
|
|
||||||
|
Get get = new Get(ROW);
|
||||||
|
get.addColumn(A, A);
|
||||||
|
table.get(get);
|
||||||
|
|
||||||
|
// verify that scannerNext and scannerClose upcalls won't be invoked
|
||||||
|
// when we perform get().
|
||||||
|
verifyMethodResult(SimpleRegionObserver.class,
|
||||||
|
new String[] {"hadPreGet", "hadPostGet", "wasScannerNextCalled",
|
||||||
|
"wasScannerCloseCalled"},
|
||||||
|
tableName,
|
||||||
|
new Boolean[] {true, true, false, false}
|
||||||
|
);
|
||||||
|
|
||||||
|
Scan s = new Scan();
|
||||||
|
ResultScanner scanner = table.getScanner(s);
|
||||||
|
try {
|
||||||
|
for (Result rr = scanner.next(); rr != null; rr = scanner.next()) {
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
scanner.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// now scanner hooks should be invoked.
|
||||||
|
verifyMethodResult(SimpleRegionObserver.class,
|
||||||
|
new String[] {"wasScannerNextCalled", "wasScannerCloseCalled"},
|
||||||
|
tableName,
|
||||||
|
new Boolean[] {true, true}
|
||||||
|
);
|
||||||
|
util.deleteTable(tableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check each region whether the coprocessor upcalls are called or not.
|
||||||
|
private void verifyMethodResult(Class c, String methodName[], byte[] tableName,
|
||||||
|
Object value[]) throws IOException {
|
||||||
|
try {
|
||||||
|
for (JVMClusterUtil.RegionServerThread t : cluster.getRegionServerThreads()) {
|
||||||
|
for (HRegionInfo r : t.getRegionServer().getOnlineRegions()) {
|
||||||
|
if (!Arrays.equals(r.getTableDesc().getName(), tableName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RegionCoprocessorHost cph = t.getRegionServer().getOnlineRegion(r.getRegionName()).
|
||||||
|
getCoprocessorHost();
|
||||||
|
|
||||||
|
Coprocessor cp = cph.findCoprocessor(c.getName());
|
||||||
|
assertNotNull(cp);
|
||||||
|
for (int i = 0; i < methodName.length; ++i) {
|
||||||
|
Method m = c.getMethod(methodName[i]);
|
||||||
|
Object o = m.invoke(cp);
|
||||||
|
assertTrue("Result of " + c.getName() + "." + methodName[i]
|
||||||
|
+ " is expected to be " + value[i].toString()
|
||||||
|
+ ", while we get " + o.toString(), o.equals(value[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IOException(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue