diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java index cffb9e09854..c0283aa450c 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java @@ -81,6 +81,9 @@ public abstract class BaseRegionObserver implements RegionObserver { @Override public void postOpen(ObserverContext e) { } + @Override + public void postLogReplay(ObserverContext e) { } + @Override public void preClose(ObserverContext c, boolean abortRequested) throws IOException { } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java index fba1225e35b..bae258b51bc 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java @@ -86,6 +86,12 @@ public interface RegionObserver extends Coprocessor { */ void postOpen(final ObserverContext c); + /** + * Called after the log replay on the region is over. + * @param c the environment provided by the region server + */ + void postLogReplay(final ObserverContext c); + /** * Called before a memstore is flushed to disk and prior to creating the scanner to read from * the memstore. To override or modify how a memstore is flushed, diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java index d7705551863..e7b5a2c2aa2 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java @@ -859,7 +859,12 @@ public class HRegion implements HeapSize { // , Writable{ * @param newState */ public void setRecovering(boolean newState) { + boolean wasRecovering = this.isRecovering; this.isRecovering = newState; + if (wasRecovering && !isRecovering) { + // Call only when log replay is over. + coprocessorHost.postLogReplay(); + } } /** diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java index a05e0a89eb7..46ff7bed7a0 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java @@ -316,6 +316,26 @@ public class RegionCoprocessorHost } } + /** + * Invoked after log replay on region + */ + public void postLogReplay() { + ObserverContext ctx = null; + for (RegionEnvironment env: coprocessors) { + if (env.getInstance() instanceof RegionObserver) { + ctx = ObserverContext.createAndPrepare(env, ctx); + try { + ((RegionObserver) env.getInstance()).postLogReplay(ctx); + } catch (Throwable e) { + handleCoprocessorThrowableNoRethrow(env, e); + } + if (ctx.shouldComplete()) { + break; + } + } + } + } + /** * Invoked before a region is closed * @param abortRequested true if the server is aborting