package coprocessor;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import com.google.common.collect.ImmutableList;
import com.google.protobuf.RpcCallback;
import com.google.protobuf.RpcController;
import com.google.protobuf.Service;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.client.Append;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Increment;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.coprocessor.CoprocessorException;
import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.coprocessor.RegionObserver;
import org.apache.hadoop.hbase.filter.ByteArrayComparable;
import org.apache.hadoop.hbase.filter.CompareFilter;
import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper;
import org.apache.hadoop.hbase.io.Reference;
import org.apache.hadoop.hbase.io.hfile.CacheConfig;
import org.apache.hadoop.hbase.protobuf.ResponseConverter;
import org.apache.hadoop.hbase.regionserver.DeleteTracker;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.regionserver.InternalScanner;
import org.apache.hadoop.hbase.regionserver.KeyValueScanner;
import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress;
import org.apache.hadoop.hbase.regionserver.Region;
import org.apache.hadoop.hbase.regionserver.RegionScanner;
import org.apache.hadoop.hbase.regionserver.ScanType;
import org.apache.hadoop.hbase.regionserver.Store;
import org.apache.hadoop.hbase.regionserver.StoreFile;
import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest;
import org.apache.hadoop.hbase.regionserver.wal.HLogKey;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.hbase.wal.WALKey;
import coprocessor.generated.ObserverStatisticsProtos;
// cc ObserverStatisticsEndpoint Observer collecting invocation statistics.
// vv ObserverStatisticsEndpoint
@SuppressWarnings("deprecation") // because of API usage
public class ObserverStatisticsEndpoint
extends ObserverStatisticsProtos.ObserverStatisticsService
implements Coprocessor, CoprocessorService, RegionObserver {
private RegionCoprocessorEnvironment env;
private Map<String, Integer> stats = new LinkedHashMap<>();
// Lifecycle methods
@Override
public void start(CoprocessorEnvironment env) throws IOException {
if (env instanceof RegionCoprocessorEnvironment) {
this.env = (RegionCoprocessorEnvironment) env;
} else {
throw new CoprocessorException("Must be loaded on a table region!");
}
}
/*...*/
// ^^ ObserverStatisticsEndpoint
@Override
public void stop(CoprocessorEnvironment env) throws IOException {
// nothing to do when coprocessor is shutting down
}
@Override
public Service getService() {
return this;
}
// vv ObserverStatisticsEndpoint
// Endpoint methods
@Override
public void getStatistics(RpcController controller,
ObserverStatisticsProtos.StatisticsRequest request,
RpcCallback<ObserverStatisticsProtos.StatisticsResponse> done) {
ObserverStatisticsProtos.StatisticsResponse response = null;
try {
ObserverStatisticsProtos.StatisticsResponse.Builder builder =
ObserverStatisticsProtos.StatisticsResponse.newBuilder();
ObserverStatisticsProtos.NameInt32Pair.Builder pair =
ObserverStatisticsProtos.NameInt32Pair.newBuilder();
for (Map.Entry<String, Integer> entry : stats.entrySet()) {
pair.setName(entry.getKey());
pair.setValue(entry.getValue().intValue());
builder.addAttribute(pair.build());
}
response = builder.build();
// optionally clear out stats
if (request.hasClear() && request.getClear()) {
synchronized (stats) {
stats.clear();
}
}
} catch (Exception e) {
ResponseConverter.setControllerException(controller,
new IOException(e));
}
done.run(response);
}
/**
* Internal helper to keep track of call counts.
*
* @param call The name of the call.
*/
private void addCallCount(String call) {
synchronized (stats) {
Integer count = stats.get(call);
if (count == null) count = new Integer(1);
else count = new Integer(count + 1);
stats.put(call, count);
}
}
// All Observer callbacks follow here
@Override
public void preOpen(
ObserverContext<RegionCoprocessorEnvironment> observerContext)
throws IOException {
addCallCount("preOpen");
}
@Override
public void postOpen(
ObserverContext<RegionCoprocessorEnvironment> observerContext) {
addCallCount("postOpen");
}
/*...*/
// ^^ ObserverStatisticsEndpoint
@Override
public void postLogReplay(
ObserverContext<RegionCoprocessorEnvironment> observerContext) {
addCallCount("postLogReplay");
}
@Override
public InternalScanner preFlushScannerOpen(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
KeyValueScanner keyValueScanner, InternalScanner internalScanner)
throws IOException {
addCallCount("preFlushScannerOpen");
return internalScanner;
}
@Override
public void preFlush(
ObserverContext<RegionCoprocessorEnvironment> observerContext)
throws IOException {
addCallCount("preFlush1");
}
@Override
public InternalScanner preFlush(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
InternalScanner internalScanner) throws IOException {
addCallCount("preFlush2");
return internalScanner;
}
@Override
public void postFlush(
ObserverContext<RegionCoprocessorEnvironment> observerContext)
throws IOException {
addCallCount("postFlush1");
}
@Override
public void postFlush(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
StoreFile storeFile) throws IOException {
addCallCount("postFlush2");
}
@Override
public void preCompactSelection(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
List<StoreFile> list, CompactionRequest compactionRequest)
throws IOException {
addCallCount("preCompactSelection1");
}
@Override
public void preCompactSelection(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
List<StoreFile> list) throws IOException {
addCallCount("preCompactSelection2");
}
@Override
public void postCompactSelection(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
ImmutableList<StoreFile> immutableList,
CompactionRequest compactionRequest) {
addCallCount("postCompactSelection1");
}
@Override
public void postCompactSelection(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
ImmutableList<StoreFile> immutableList) {
addCallCount("postCompactSelection2");
}
@Override
public InternalScanner preCompact(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
InternalScanner internalScanner, ScanType scanType,
CompactionRequest compactionRequest) throws IOException {
addCallCount("preCompact1");
return internalScanner;
}
@Override
public InternalScanner preCompact(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
InternalScanner internalScanner, ScanType scanType) throws IOException {
addCallCount("preCompact2");
return internalScanner;
}
@Override
public InternalScanner preCompactScannerOpen(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
List<? extends KeyValueScanner> list, ScanType scanType, long l,
InternalScanner internalScanner, CompactionRequest compactionRequest)
throws IOException {
addCallCount("preCompactScannerOpen1");
return internalScanner;
}
@Override
public InternalScanner preCompactScannerOpen(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
List<? extends KeyValueScanner> list, ScanType scanType, long l,
InternalScanner internalScanner) throws IOException {
addCallCount("preCompactScannerOpen2");
return internalScanner;
}
@Override
public void postCompact(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
StoreFile storeFile, CompactionRequest compactionRequest)
throws IOException {
addCallCount("postCompact1");
}
@Override
public void postCompact(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
StoreFile storeFile) throws IOException {
addCallCount("postCompact2");
}
@Override
public void preSplit(
ObserverContext<RegionCoprocessorEnvironment> observerContext)
throws IOException {
addCallCount("preSplit1");
}
@Override
public void preSplit(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes)
throws IOException {
addCallCount("preSplit2");
}
@Override
public void postSplit(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
Region region, Region region1) throws IOException {
addCallCount("postSplit");
}
@Override
public void preSplitBeforePONR(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes,
List<Mutation> list) throws IOException {
addCallCount("preSplitBeforePONR");
}
@Override
public void preSplitAfterPONR(
ObserverContext<RegionCoprocessorEnvironment> observerContext)
throws IOException {
addCallCount("preSplitAfterPONR");
}
@Override
public void preRollBackSplit(
ObserverContext<RegionCoprocessorEnvironment> observerContext)
throws IOException {
addCallCount("preRollBackSplit");
}
@Override
public void postRollBackSplit(
ObserverContext<RegionCoprocessorEnvironment> observerContext)
throws IOException {
addCallCount("postRollBackSplit");
}
@Override
public void postCompleteSplit(
ObserverContext<RegionCoprocessorEnvironment> observerContext)
throws IOException {
addCallCount("postCompleteSplit");
}
@Override
public void preClose(
ObserverContext<RegionCoprocessorEnvironment> observerContext, boolean b)
throws IOException {
addCallCount("preClose");
}
@Override
public void postClose(
ObserverContext<RegionCoprocessorEnvironment> observerContext, boolean b) {
addCallCount("postClose");
}
@Override
public void preGetClosestRowBefore(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes,
byte[] bytes1, Result result) throws IOException {
addCallCount("preGetClosestRowBefore");
}
@Override
public void postGetClosestRowBefore(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes,
byte[] bytes1, Result result) throws IOException {
addCallCount("postGetClosestRowBefore");
}
@Override
public void preGetOp(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Get get,
List<Cell> list) throws IOException {
addCallCount("preGetOp");
}
@Override
public void postGetOp(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Get get,
List<Cell> list) throws IOException {
addCallCount("postGetOp");
}
@Override
public boolean preExists(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Get get,
boolean b) throws IOException {
addCallCount("preExists");
return b;
}
@Override
public boolean postExists(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Get get,
boolean b) throws IOException {
addCallCount("postExists");
return b;
}
@Override
public void prePut(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Put put,
WALEdit walEdit, Durability durability) throws IOException {
addCallCount("prePut");
}
@Override
public void postPut(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Put put,
WALEdit walEdit, Durability durability) throws IOException {
addCallCount("postPut");
}
@Override
public void preDelete(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
Delete delete, WALEdit walEdit, Durability durability) throws IOException {
addCallCount("preDelete");
}
@Override
public void prePrepareTimeStampForDeleteVersion(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
Mutation mutation, Cell cell, byte[] bytes, Get get) throws IOException {
addCallCount("prePrepareTimeStampForDeleteVersion");
}
@Override
public void postDelete(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
Delete delete, WALEdit walEdit, Durability durability) throws IOException {
addCallCount("postDelete");
}
@Override
public void preBatchMutate(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
MiniBatchOperationInProgress<Mutation> miniBatchOperationInProgress)
throws IOException {
addCallCount("preBatchMutate");
}
@Override
public void postBatchMutate(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
MiniBatchOperationInProgress<Mutation> miniBatchOperationInProgress)
throws IOException {
addCallCount("postBatchMutate");
}
@Override
public void postStartRegionOperation(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
HRegion.Operation operation) throws IOException {
addCallCount("postStartRegionOperation");
addCallCount("- postStartRegionOperation-" + operation);
}
@Override
public void postCloseRegionOperation(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
HRegion.Operation operation) throws IOException {
addCallCount("postCloseRegionOperation");
addCallCount("- postCloseRegionOperation-" + operation);
}
@Override
public void postBatchMutateIndispensably(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
MiniBatchOperationInProgress<Mutation> miniBatchOperationInProgress,
boolean b) throws IOException {
addCallCount("postBatchMutateIndispensably");
}
@Override
public boolean preCheckAndPut(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes,
byte[] bytes1, byte[] bytes2, CompareFilter.CompareOp compareOp,
ByteArrayComparable byteArrayComparable, Put put, boolean b)
throws IOException {
addCallCount("preCheckAndPut");
return b;
}
@Override
public boolean preCheckAndPutAfterRowLock(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes,
byte[] bytes1, byte[] bytes2, CompareFilter.CompareOp compareOp,
ByteArrayComparable byteArrayComparable, Put put, boolean b)
throws IOException {
addCallCount("preCheckAndPutAfterRowLock");
return b;
}
@Override
public boolean postCheckAndPut(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes,
byte[] bytes1, byte[] bytes2, CompareFilter.CompareOp compareOp,
ByteArrayComparable byteArrayComparable, Put put, boolean b)
throws IOException {
addCallCount("postCheckAndPut");
return b;
}
@Override
public boolean preCheckAndDelete(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes,
byte[] bytes1, byte[] bytes2, CompareFilter.CompareOp compareOp,
ByteArrayComparable byteArrayComparable, Delete delete, boolean b)
throws IOException {
addCallCount("preCheckAndDelete");
return b;
}
@Override
public boolean preCheckAndDeleteAfterRowLock(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes,
byte[] bytes1, byte[] bytes2, CompareFilter.CompareOp compareOp,
ByteArrayComparable byteArrayComparable, Delete delete, boolean b)
throws IOException {
addCallCount("preCheckAndDeleteAfterRowLock");
return b;
}
@Override
public boolean postCheckAndDelete(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes,
byte[] bytes1, byte[] bytes2, CompareFilter.CompareOp compareOp,
ByteArrayComparable byteArrayComparable, Delete delete, boolean b)
throws IOException {
addCallCount("postCheckAndDelete");
return b;
}
@Override
public long preIncrementColumnValue(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes,
byte[] bytes1, byte[] bytes2, long l, boolean b) throws IOException {
addCallCount("preIncrementColumnValue");
return l;
}
@Override
public long postIncrementColumnValue(
ObserverContext<RegionCoprocessorEnvironment> observerContext, byte[] bytes,
byte[] bytes1, byte[] bytes2, long l, boolean b, long l1)
throws IOException {
addCallCount("postIncrementColumnValue");
return l;
}
@Override
public Result preAppend(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
Append append) throws IOException {
addCallCount("preAppend");
return null;
}
@Override
public Result preAppendAfterRowLock(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
Append append) throws IOException {
addCallCount("preAppendAfterRowLock");
return null;
}
@Override
public Result postAppend(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
Append append, Result result) throws IOException {
addCallCount("postAppend");
return result;
}
@Override
public Result preIncrement(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
Increment increment) throws IOException {
addCallCount("preIncrement");
return null;
}
@Override
public Result preIncrementAfterRowLock(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
Increment increment) throws IOException {
addCallCount("preIncrementAfterRowLock");
return null;
}
@Override
public Result postIncrement(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
Increment increment, Result result) throws IOException {
addCallCount("postIncrement");
return result;
}
@Override
public RegionScanner preScannerOpen(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Scan scan,
RegionScanner regionScanner) throws IOException {
addCallCount("preScannerOpen");
return regionScanner;
}
@Override
public KeyValueScanner preStoreScannerOpen(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Store store,
Scan scan, NavigableSet<byte[]> navigableSet,
KeyValueScanner keyValueScanner) throws IOException {
addCallCount("preStoreScannerOpen");
return keyValueScanner;
}
@Override
public RegionScanner postScannerOpen(
ObserverContext<RegionCoprocessorEnvironment> observerContext, Scan scan,
RegionScanner regionScanner) throws IOException {
addCallCount("postScannerOpen");
return regionScanner;
}
@Override
public boolean preScannerNext(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
InternalScanner internalScanner, List<Result> list, int i, boolean b)
throws IOException {
addCallCount("preScannerNext");
return b;
}
@Override
public boolean postScannerNext(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
InternalScanner internalScanner, List<Result> list, int i, boolean b)
throws IOException {
addCallCount("postScannerNext");
return b;
}
@Override
public boolean postScannerFilterRow(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
InternalScanner internalScanner, byte[] bytes, int i, short i1, boolean b)
throws IOException {
addCallCount("postScannerFilterRow");
return b;
}
@Override
public void preScannerClose(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
InternalScanner internalScanner) throws IOException {
addCallCount("preScannerClose");
}
@Override
public void postScannerClose(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
InternalScanner internalScanner) throws IOException {
addCallCount("postScannerClose");
}
@Override
public void preWALRestore(
ObserverContext<? extends RegionCoprocessorEnvironment> observerContext,
HRegionInfo hRegionInfo, WALKey walKey, WALEdit walEdit)
throws IOException {
addCallCount("preWALRestore1");
}
@Override
public void preWALRestore(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
HRegionInfo hRegionInfo, HLogKey hLogKey, WALEdit walEdit)
throws IOException {
addCallCount("preWALRestore2");
}
@Override
public void postWALRestore(
ObserverContext<? extends RegionCoprocessorEnvironment> observerContext,
HRegionInfo hRegionInfo, WALKey walKey, WALEdit walEdit)
throws IOException {
addCallCount("postWALRestore1");
}
@Override
public void postWALRestore(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
HRegionInfo hRegionInfo, HLogKey hLogKey, WALEdit walEdit)
throws IOException {
addCallCount("postWALRestore2");
}
@Override
public void preBulkLoadHFile(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
List<Pair<byte[], String>> list) throws IOException {
addCallCount("preBulkLoadHFile");
}
@Override
public boolean postBulkLoadHFile(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
List<Pair<byte[], String>> list, boolean b) throws IOException {
addCallCount("postBulkLoadHFile");
return b;
}
@Override
public StoreFile.Reader preStoreFileReaderOpen(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
FileSystem fileSystem, Path path,
FSDataInputStreamWrapper fsDataInputStreamWrapper, long l,
CacheConfig cacheConfig, Reference reference, StoreFile.Reader reader)
throws IOException {
addCallCount("preStoreFileReaderOpen");
addCallCount("- preStoreFileReaderOpen-" + path.getName());
return reader;
}
@Override
public StoreFile.Reader postStoreFileReaderOpen(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
FileSystem fileSystem, Path path,
FSDataInputStreamWrapper fsDataInputStreamWrapper, long l,
CacheConfig cacheConfig, Reference reference, StoreFile.Reader reader)
throws IOException {
addCallCount("postStoreFileReaderOpen");
addCallCount("- postStoreFileReaderOpen-" + path.getName());
return reader;
}
@Override
public Cell postMutationBeforeWAL(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
MutationType mutationType, Mutation mutation, Cell cell, Cell cell1)
throws IOException {
addCallCount("postMutationBeforeWAL");
addCallCount("- postMutationBeforeWAL-" + mutationType);
return cell1;
}
@Override
public DeleteTracker postInstantiateDeleteTracker(
ObserverContext<RegionCoprocessorEnvironment> observerContext,
DeleteTracker deleteTracker) throws IOException {
addCallCount("postInstantiateDeleteTracker");
return deleteTracker;
}
// vv ObserverStatisticsEndpoint
}
// ^^ ObserverStatisticsEndpoint