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 1516366) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java (working copy) @@ -44,6 +44,7 @@ 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.SplitTransaction.SplitInfo; import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest; import org.apache.hadoop.hbase.regionserver.wal.HLogKey; import org.apache.hadoop.hbase.regionserver.wal.WALEdit; @@ -115,6 +116,18 @@ } @Override + public SplitInfo preSplitBeforePONR( + ObserverContext ctx, byte[] splitKey) + throws IOException { + return null; + } + + @Override + public void preSplitAfterPONR( + ObserverContext ctx) throws IOException { + } + + @Override public void preRollBackSplit(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 1516366) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java (working copy) @@ -41,6 +41,7 @@ import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress; import org.apache.hadoop.hbase.regionserver.RegionScanner; import org.apache.hadoop.hbase.regionserver.ScanType; +import org.apache.hadoop.hbase.regionserver.SplitTransaction.SplitInfo; import org.apache.hadoop.hbase.regionserver.Store; import org.apache.hadoop.hbase.regionserver.StoreFile; import org.apache.hadoop.hbase.regionserver.StoreFileScanner; @@ -342,6 +343,24 @@ final HRegion r) throws IOException; /** + * This will be called before PONR step as part of split transaction + * @param ctx + * @param splitKey + * @return + * @throws IOException + */ + SplitInfo preSplitBeforePONR(final ObserverContext ctx, + byte[] splitKey) throws IOException; + + + /** + * This will be called after PONR step as part of split transaction + * @param ctx + * @throws IOException + */ + void preSplitAfterPONR(final ObserverContext ctx) throws IOException; + + /** * This will be called before the roll back of the split region is completed * @param ctx * @throws IOException 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 1516366) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java (working copy) @@ -57,6 +57,7 @@ import org.apache.hadoop.hbase.filter.ByteArrayComparable; import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.hadoop.hbase.regionserver.SplitTransaction.SplitInfo; import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest; import org.apache.hadoop.hbase.regionserver.wal.HLogKey; import org.apache.hadoop.hbase.regionserver.wal.WALEdit; @@ -663,6 +664,43 @@ } } + + public SplitInfo preSplitBeforePONR(byte[] splitKey) throws IOException { + SplitInfo info = null; + ObserverContext ctx = null; + for (RegionEnvironment env : coprocessors) { + if (env.getInstance() instanceof RegionObserver) { + ctx = ObserverContext.createAndPrepare(env, ctx); + try { + info = ((RegionObserver) env.getInstance()).preSplitBeforePONR(ctx, splitKey); + } catch (Throwable e) { + handleCoprocessorThrowable(env, e); + } + if (ctx.shouldComplete()) { + break; + } + } + } + return info; + } + + public void preSplitAfterPONR() throws IOException { + ObserverContext ctx = null; + for (RegionEnvironment env : coprocessors) { + if (env.getInstance() instanceof RegionObserver) { + ctx = ObserverContext.createAndPrepare(env, ctx); + try { + ((RegionObserver) env.getInstance()).preSplitAfterPONR(ctx); + } catch (Throwable e) { + handleCoprocessorThrowable(env, e); + } + if (ctx.shouldComplete()) { + break; + } + } + } + } + /** * Invoked just before the rollback of a failed split is started * @throws IOException Index: hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransaction.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransaction.java (revision 1516366) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransaction.java (working copy) @@ -229,6 +229,45 @@ server.getConfiguration().getLong("hbase.regionserver.fileSplitTimeout", this.fileSplitTimeout); + PairOfSameType daughterRegions = stepsBeforePONR(server, services, testing); + + SplitInfo info = null; + if (this.parent.getCoprocessorHost() != null) { + info = this.parent.getCoprocessorHost().preSplitBeforePONR(this.splitrow); + } + + // This is the point of no return. Adding subsequent edits to .META. as we + // do below when we do the daughter opens adding each to .META. can fail in + // various interesting ways the most interesting of which is a timeout + // BUT the edits all go through (See HBASE-3872). IF we reach the PONR + // then subsequent failures need to crash out this regionserver; the + // server shutdown processing should be able to fix-up the incomplete split. + // The offlined parent will have the daughters as extra columns. If + // we leave the daughter regions in place and do not remove them when we + // crash out, then they will have their references to the parent in place + // still and the server shutdown fixup of .META. will point to these + // regions. + // We should add PONR JournalEntry before offlineParentInMeta,so even if + // OfflineParentInMeta timeout,this will cause regionserver exit,and then + // master ServerShutdownHandler will fix daughter & avoid data loss. (See + // HBase-4562). + this.journal.add(JournalEntry.PONR); + + // Edit parent in meta. Offlines parent region and adds splita and splitb + // as an atomic update. See HBASE-7721. This update to META makes the region + // will determine whether the region is split or not in case of failures. + // If it is successful, master will roll-forward, if not, master will rollback + // and assign the parent region. + if (!testing) { + MetaEditor.splitRegion(server.getCatalogTracker(), + parent.getRegionInfo(), daughterRegions.getFirst().getRegionInfo(), + daughterRegions.getSecond().getRegionInfo(), server.getServerName()); + } + return daughterRegions; + } + + private PairOfSameType stepsBeforePONR(final Server server, + final RegionServerServices services, boolean testing) throws IOException { // Set ephemeral SPLITTING znode up in zk. Mocked servers sometimes don't // have zookeeper so don't do zk stuff if server or zookeeper is null if (server != null && server.getZooKeeper() != null) { @@ -305,34 +344,7 @@ // Ditto this.journal.add(JournalEntry.STARTED_REGION_B_CREATION); HRegion b = this.parent.createDaughterRegionFromSplits(this.hri_b); - - // This is the point of no return. Adding subsequent edits to .META. as we - // do below when we do the daughter opens adding each to .META. can fail in - // various interesting ways the most interesting of which is a timeout - // BUT the edits all go through (See HBASE-3872). IF we reach the PONR - // then subsequent failures need to crash out this regionserver; the - // server shutdown processing should be able to fix-up the incomplete split. - // The offlined parent will have the daughters as extra columns. If - // we leave the daughter regions in place and do not remove them when we - // crash out, then they will have their references to the parent in place - // still and the server shutdown fixup of .META. will point to these - // regions. - // We should add PONR JournalEntry before offlineParentInMeta,so even if - // OfflineParentInMeta timeout,this will cause regionserver exit,and then - // master ServerShutdownHandler will fix daughter & avoid data loss. (See - // HBase-4562). - this.journal.add(JournalEntry.PONR); - - // Edit parent in meta. Offlines parent region and adds splita and splitb - // as an atomic update. See HBASE-7721. This update to META makes the region - // will determine whether the region is split or not in case of failures. - // If it is successful, master will roll-forward, if not, master will rollback - // and assign the parent region. - if (!testing) { - MetaEditor.splitRegion(server.getCatalogTracker(), parent.getRegionInfo(), - a.getRegionInfo(), b.getRegionInfo(), server.getServerName()); - } - return new PairOfSameType(a, b); + return new PairOfSameType(a,b); } /** @@ -463,6 +475,15 @@ final RegionServerServices services) throws IOException { PairOfSameType regions = createDaughters(server, services); + if (this.parent.getCoprocessorHost() != null) { + this.parent.getCoprocessorHost().preSplitAfterPONR(); + } + return stepsAfterPONR(server, services, regions); + } + + private PairOfSameType stepsAfterPONR(final Server server, + final RegionServerServices services, PairOfSameType regions) + throws IOException { openDaughters(server, services, regions.getFirst(), regions.getSecond()); transitionZKNode(server, services, regions.getFirst(), regions.getSecond()); return regions; @@ -803,6 +824,31 @@ } /** + * + * Information of dependent region split processed in coprocessor hook + * {@link RegionCoprocessorHost#preSplitBeforePONR(byte[])} + * + */ + public static class SplitInfo { + private PairOfSameType daughterRegions; + private SplitTransaction st; + + public SplitInfo(final PairOfSameType pairOfSameType, + final SplitTransaction st) { + this.daughterRegions = pairOfSameType; + this.st = st; + } + + public PairOfSameType getDaughters() { + return this.daughterRegions; + } + + public SplitTransaction getSplitTransaction() { + return this.st; + } + } + + /** * * @param zkw zk reference * @param parent region to be transitioned to splitting 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 1516366) +++ hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/SimpleRegionObserver.java (working copy) @@ -53,6 +53,7 @@ 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.SplitTransaction.SplitInfo; import org.apache.hadoop.hbase.regionserver.wal.WALEdit; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; @@ -102,6 +103,8 @@ final AtomicInteger ctPostBulkLoadHFile = new AtomicInteger(0); final AtomicInteger ctPreBatchMutate = new AtomicInteger(0); final AtomicInteger ctPostBatchMutate = new AtomicInteger(0); + final AtomicInteger ctPreSplitBeforePONR = new AtomicInteger(0); + final AtomicInteger ctPreSplitAfterPONR = new AtomicInteger(0); @Override public void start(CoprocessorEnvironment e) throws IOException { @@ -171,6 +174,20 @@ } @Override + public SplitInfo preSplitBeforePONR( + ObserverContext ctx, byte[] splitKey) + throws IOException { + ctPreSplitBeforePONR.incrementAndGet(); + return null; + } + + @Override + public void preSplitAfterPONR( + ObserverContext ctx) throws IOException { + ctPreSplitAfterPONR.incrementAndGet(); + } + + @Override public void postSplit(ObserverContext c, HRegion l, HRegion r) { ctPostSplit.incrementAndGet(); } @@ -601,7 +618,15 @@ public int getCtPreSplit() { return ctPreSplit.get(); } + + public int getCtPreSplitBeforePONR() { + return ctPreSplitBeforePONR.get(); + } + public int getCtPreSplitAfterPONR() { + return ctPreSplitBeforePONR.get(); + } + public int getCtPostSplit() { return ctPostSplit.get(); }