Index: hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java (revision 1524952) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java (working copy) @@ -45,6 +45,7 @@ import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; import org.apache.hadoop.hbase.io.hfile.CacheConfig; import org.apache.hadoop.hbase.regionserver.HRegion; +import org.apache.hadoop.hbase.regionserver.HRegion.Operation; import org.apache.hadoop.hbase.regionserver.InternalScanner; import org.apache.hadoop.hbase.regionserver.KeyValueScanner; import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress; @@ -323,6 +324,11 @@ } @Override + public void postCompleteBatchMutate(final ObserverContext ctx) + throws IOException { + } + + @Override public boolean preCheckAndPut(final ObserverContext e, final byte [] row, final byte [] family, final byte [] qualifier, final CompareOp compareOp, final ByteArrayComparable comparator, @@ -476,4 +482,14 @@ DataBlockEncoding preferredEncodingInCache, Reference r, Reader reader) throws IOException { return reader; } + + @Override + public void postStartRegionOperation(final ObserverContext ctx, + Operation op) throws IOException { + } + + @Override + public void postCloseRegionOperation(final ObserverContext ctx) + throws IOException { + } } Index: hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java (revision 1524952) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java (working copy) @@ -43,6 +43,7 @@ import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; import org.apache.hadoop.hbase.io.hfile.CacheConfig; import org.apache.hadoop.hbase.regionserver.HRegion; +import org.apache.hadoop.hbase.regionserver.HRegion.Operation; import org.apache.hadoop.hbase.regionserver.InternalScanner; import org.apache.hadoop.hbase.regionserver.KeyValueScanner; import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress; @@ -613,6 +614,34 @@ final MiniBatchOperationInProgress miniBatchOp) throws IOException; /** + * Used after startRegionOperation in region operation + * @param ctx + * @param operation + * @throws IOException + */ + void postStartRegionOperation(final ObserverContext ctx, + Operation operation) throws IOException; + + /** + * Used after closeRegionOperation in region operation + * @param ctx + * @throws IOException + */ + void postCloseRegionOperation(final ObserverContext ctx) + throws IOException; + + /** + * Called after the completion of batch put/delete and will be called even if the batch + * operation fails + * + * @param ctx + * @throws IOException + */ + void postCompleteBatchMutate( + final ObserverContext ctx) + throws IOException; + + /** * Called before checkAndPut *

* Call CoprocessorEnvironment#bypass to skip default actions Index: hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (revision 1524952) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (working copy) @@ -213,7 +213,7 @@ * operations have to be defined here. It's only needed when a special check is need in * startRegionOperation */ - protected enum Operation { + public enum Operation { ANY, GET, PUT, DELETE, SCAN, APPEND, INCREMENT, SPLIT_REGION, MERGE_REGION, BATCH_MUTATE, REPLAY_BATCH_MUTATE, COMPACT_REGION } @@ -2276,6 +2276,11 @@ this.updatesLock.readLock().unlock(); } releaseRowLocks(acquiredRowLocks); + // call the coprocessor hook to do to any finalization steps + // after the put is done + if (coprocessorHost != null) { + coprocessorHost.postCompleteBatchMutate(); + } // See if the column families were consistent through the whole thing. // if they were then keep them. If they were not then pass a null. @@ -5219,23 +5224,17 @@ * modifies data. It has to be called just before a try. * #closeRegionOperation needs to be called in the try's finally block * Acquires a read lock and checks if the region is closing or closed. - * @throws NotServingRegionException when the region is closing or closed - * @throws RegionTooBusyException if failed to get the lock in time - * @throws InterruptedIOException if interrupted while waiting for a lock + * @throws IOException */ - public void startRegionOperation() - throws NotServingRegionException, RegionTooBusyException, InterruptedIOException { + public void startRegionOperation() throws IOException { startRegionOperation(Operation.ANY); } /** * @param op The operation is about to be taken on the region - * @throws NotServingRegionException - * @throws RegionTooBusyException - * @throws InterruptedIOException + * @throws IOException */ - protected void startRegionOperation(Operation op) throws NotServingRegionException, - RegionTooBusyException, InterruptedIOException { + protected void startRegionOperation(Operation op) throws IOException { switch (op) { case INCREMENT: case APPEND: @@ -5270,14 +5269,26 @@ lock.readLock().unlock(); throw new NotServingRegionException(getRegionNameAsString() + " is closed"); } + try { + if (coprocessorHost != null) { + coprocessorHost.postStartRegionOperation(op); + } + } catch (IOException e) { + lock.readLock().unlock(); + throw e; + } } /** * Closes the lock. This needs to be called in the finally block corresponding * to the try block of #startRegionOperation + * @throws IOException */ - public void closeRegionOperation() { + public void closeRegionOperation() throws IOException { lock.readLock().unlock(); + if (coprocessorHost != null) { + coprocessorHost.postCloseRegionOperation(); + } } /** Index: hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java (revision 1524952) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java (working copy) @@ -62,6 +62,7 @@ import org.apache.hadoop.hbase.io.Reference; import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; import org.apache.hadoop.hbase.io.hfile.CacheConfig; +import org.apache.hadoop.hbase.regionserver.HRegion.Operation; import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest; import org.apache.hadoop.hbase.regionserver.wal.HLogKey; import org.apache.hadoop.hbase.regionserver.wal.WALEdit; @@ -1077,6 +1078,23 @@ } } + public void postCompleteBatchMutate() throws IOException { + ObserverContext ctx = null; + for (RegionEnvironment env : coprocessors) { + if (env.getInstance() instanceof RegionObserver) { + ctx = ObserverContext.createAndPrepare(env, ctx); + try { + ((RegionObserver) env.getInstance()).postCompleteBatchMutate(ctx); + } catch (Throwable e) { + handleCoprocessorThrowable(env, e); + } + if (ctx.shouldComplete()) { + break; + } + } + } + } + /** * @param row row to check * @param family column family @@ -1641,6 +1659,40 @@ return hasLoaded; } + public void postStartRegionOperation(Operation op) throws IOException { + ObserverContext ctx = null; + for (RegionEnvironment env : coprocessors) { + if (env.getInstance() instanceof RegionObserver) { + ctx = ObserverContext.createAndPrepare(env, ctx); + try { + ((RegionObserver) env.getInstance()).postStartRegionOperation(ctx, op); + } catch (Throwable e) { + handleCoprocessorThrowable(env, e); + } + if (ctx.shouldComplete()) { + break; + } + } + } + } + + public void postCloseRegionOperation() throws IOException { + ObserverContext ctx = null; + for (RegionEnvironment env : coprocessors) { + if (env.getInstance() instanceof RegionObserver) { + ctx = ObserverContext.createAndPrepare(env, ctx); + try { + ((RegionObserver) env.getInstance()).postCloseRegionOperation(ctx); + } catch (Throwable e) { + handleCoprocessorThrowable(env, e); + } + if (ctx.shouldComplete()) { + break; + } + } + } + } + /** * @param fs fileystem to read from * @param p path to the file Index: hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/SimpleRegionObserver.java =================================================================== --- hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/SimpleRegionObserver.java (revision 1524952) +++ hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/SimpleRegionObserver.java (working copy) @@ -54,6 +54,7 @@ import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; import org.apache.hadoop.hbase.io.hfile.CacheConfig; import org.apache.hadoop.hbase.regionserver.HRegion; +import org.apache.hadoop.hbase.regionserver.HRegion.Operation; import org.apache.hadoop.hbase.regionserver.InternalScanner; import org.apache.hadoop.hbase.regionserver.KeyValueScanner; import org.apache.hadoop.hbase.regionserver.Leases; @@ -119,6 +120,9 @@ final AtomicInteger ctPreSplitAfterPONR = new AtomicInteger(0); final AtomicInteger ctPreStoreFileReaderOpen = new AtomicInteger(0); final AtomicInteger ctPostStoreFileReaderOpen = new AtomicInteger(0); + final AtomicInteger ctPostCompleteBatchMutate = new AtomicInteger(0); + final AtomicInteger ctPostStartRegionOperation = new AtomicInteger(0); + final AtomicInteger ctPostCloseRegionOperation = new AtomicInteger(0); final AtomicBoolean throwOnPostFlush = new AtomicBoolean(false); @@ -464,6 +468,26 @@ } @Override + public void postCompleteBatchMutate(ObserverContext ctx) + throws IOException { + ctPostCompleteBatchMutate.incrementAndGet(); + } + + @Override + public void postStartRegionOperation(final ObserverContext ctx, + Operation op) throws IOException { + ctPostStartRegionOperation.incrementAndGet(); + } + + @Override + public void postCloseRegionOperation(final ObserverContext ctx) + throws IOException { + if (ctPostStartRegionOperation.get() > 0) { + ctPostCloseRegionOperation.incrementAndGet(); + } + } + + @Override public void preGetClosestRowBefore(final ObserverContext c, final byte[] row, final byte[] family, final Result result) throws IOException { @@ -591,11 +615,31 @@ public boolean hadPostBatchMutate() { return ctPostBatchMutate.get() > 0; } + + public boolean hadPostCompleteBatchMutate() { + return ctPostCompleteBatchMutate.get() > 0; + } + public boolean hadPostStartRegionOperation() { + return ctPostStartRegionOperation.get() > 0; + } + + public boolean hadPostCloseRegionOperation() { + return ctPostCloseRegionOperation.get() > 0; + } + public boolean hadDelete() { return !(ctBeforeDelete.get() > 0); } + public int getCtPostStartRegionOperation() { + return ctPostStartRegionOperation.get(); + } + + public int getCtPostCloseRegionOperation() { + return ctPostCloseRegionOperation.get(); + } + public boolean hadPreIncrement() { return ctPreIncrement.get() > 0; } Index: hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestRegionObserverInterface.java =================================================================== --- hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestRegionObserverInterface.java (revision 1524952) +++ hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestRegionObserverInterface.java (working copy) @@ -115,9 +115,10 @@ HTable table = util.createTable(tableName, new byte[][] {A, B, C}); verifyMethodResult(SimpleRegionObserver.class, new String[] {"hadPreGet", "hadPostGet", "hadPrePut", "hadPostPut", - "hadDelete"}, + "hadDelete", "hadPostStartRegionOperation", + "hadPostCloseRegionOperation", "hadPostCompleteBatchMutate"}, TEST_TABLE, - new Boolean[] {false, false, false, false, false}); + new Boolean[] {false, false, false, false, false, false, false, false}); Put put = new Put(ROW); put.add(A, A, A); @@ -125,12 +126,12 @@ put.add(C, C, C); table.put(put); - verifyMethodResult(SimpleRegionObserver.class, - new String[] {"hadPreGet", "hadPostGet", "hadPrePut", "hadPostPut", - "hadPreBatchMutate", "hadPostBatchMutate", "hadDelete"}, - TEST_TABLE, - new Boolean[] {false, false, true, true, true, true, false} - ); + verifyMethodResult(SimpleRegionObserver.class, new String[] { "hadPreGet", + "hadPostGet", "hadPrePut", "hadPostPut", "hadPreBatchMutate", + "hadPostBatchMutate", "hadDelete", "hadPostStartRegionOperation", + "hadPostCloseRegionOperation","hadPostCompleteBatchMutate" }, + TEST_TABLE, + new Boolean[] { false, false, true, true, true, true, false, true, true, true }); verifyMethodResult(SimpleRegionObserver.class, new String[] {"getCtPreOpen", "getCtPostOpen", "getCtPreClose", "getCtPostClose"},