2626import java .util .List ;
2727import java .util .Map ;
2828import java .util .function .BooleanSupplier ;
29+ import org .apache .hadoop .hbase .Cell ;
30+ import org .apache .hadoop .hbase .CellBuilderFactory ;
31+ import org .apache .hadoop .hbase .CellBuilderType ;
2932import org .apache .hadoop .hbase .HBaseClassTestRule ;
3033import org .apache .hadoop .hbase .HBaseTestingUtility ;
3134import org .apache .hadoop .hbase .HConstants ;
3235import org .apache .hadoop .hbase .MetaTableAccessor ;
3336import org .apache .hadoop .hbase .TableName ;
37+ import org .apache .hadoop .hbase .client .Put ;
3438import org .apache .hadoop .hbase .client .RegionInfo ;
3539import org .apache .hadoop .hbase .client .RegionInfoBuilder ;
3640import org .apache .hadoop .hbase .client .Result ;
4347import org .apache .hadoop .hbase .procedure2 .ProcedureExecutor ;
4448import org .apache .hadoop .hbase .testclassification .LargeTests ;
4549import org .apache .hadoop .hbase .testclassification .MasterTests ;
50+ import org .apache .hadoop .hbase .util .Bytes ;
4651import org .apache .hadoop .hbase .util .Pair ;
4752import org .apache .hadoop .hbase .util .Threads ;
4853import org .junit .AfterClass ;
@@ -141,7 +146,7 @@ public void testOneRegionTable() throws IOException {
141146 assertEquals (0 , ris .size ());
142147 }
143148
144- private static void makeOverlap (MasterServices services , RegionInfo a , RegionInfo b )
149+ private static RegionInfo makeOverlap (MasterServices services , RegionInfo a , RegionInfo b )
145150 throws IOException {
146151 RegionInfo overlapRegion = RegionInfoBuilder .newBuilder (a .getTable ()).
147152 setStartKey (a .getStartKey ()).
@@ -152,6 +157,7 @@ private static void makeOverlap(MasterServices services, RegionInfo a, RegionInf
152157 System .currentTimeMillis ())));
153158 // TODO: Add checks at assign time to PREVENT being able to assign over existing assign.
154159 services .getAssignmentManager ().assign (overlapRegion );
160+ return overlapRegion ;
155161 }
156162
157163 private void testOverlapCommon (final TableName tn ) throws Exception {
@@ -167,7 +173,6 @@ private void testOverlapCommon(final TableName tn) throws Exception {
167173 makeOverlap (services , ris .get (1 ), ris .get (3 ));
168174 makeOverlap (services , ris .get (2 ), ris .get (3 ));
169175 makeOverlap (services , ris .get (2 ), ris .get (4 ));
170- Threads .sleep (10000 );
171176 }
172177
173178 @ Test
@@ -308,6 +313,74 @@ public void testOverlapWithSmallMergeCount() throws Exception {
308313 }
309314 }
310315
316+ /**
317+ * This test covers the case that one of merged parent regions is a merged child region that
318+ * has not been GCed but there is no reference files anymore. In this case, it will kick off
319+ * a GC procedure, but no merge will happen.
320+ */
321+ @ Test
322+ public void testMergeWithMergedChildRegion () throws Exception {
323+ TableName tn = TableName .valueOf (this .name .getMethodName ());
324+ Table t = TEST_UTIL .createMultiRegionTable (tn , HConstants .CATALOG_FAMILY );
325+ List <RegionInfo > ris = MetaTableAccessor .getTableRegions (TEST_UTIL .getConnection (), tn );
326+ assertTrue (ris .size () > 5 );
327+ HMaster services = TEST_UTIL .getHBaseCluster ().getMaster ();
328+ CatalogJanitor cj = services .getCatalogJanitor ();
329+ cj .scan ();
330+ CatalogJanitor .Report report = cj .getLastReport ();
331+ assertTrue (report .isEmpty ());
332+ RegionInfo overlapRegion = makeOverlap (services , ris .get (1 ), ris .get (2 ));
333+
334+ cj .scan ();
335+ report = cj .getLastReport ();
336+ assertEquals (2 , report .getOverlaps ().size ());
337+
338+ // Mark it as a merged child region.
339+ RegionInfo fakedParentRegion = RegionInfoBuilder .newBuilder (tn ).
340+ setStartKey (overlapRegion .getStartKey ()).
341+ build ();
342+
343+ Table meta = MetaTableAccessor .getMetaHTable (TEST_UTIL .getConnection ());
344+ Put putOfMerged = MetaTableAccessor .makePutFromRegionInfo (overlapRegion ,
345+ HConstants .LATEST_TIMESTAMP );
346+ String qualifier = String .format (HConstants .MERGE_QUALIFIER_PREFIX_STR + "%04d" , 0 );
347+ putOfMerged .add (CellBuilderFactory .create (CellBuilderType .SHALLOW_COPY ).setRow (
348+ putOfMerged .getRow ()).
349+ setFamily (HConstants .CATALOG_FAMILY ).
350+ setQualifier (Bytes .toBytes (qualifier )).
351+ setTimestamp (putOfMerged .getTimestamp ()).
352+ setType (Cell .Type .Put ).
353+ setValue (RegionInfo .toByteArray (fakedParentRegion )).
354+ build ());
355+
356+ meta .put (putOfMerged );
357+
358+ MetaFixer fixer = new MetaFixer (services );
359+ fixer .fixOverlaps (report );
360+
361+ // Wait until all procedures settled down
362+ await (200 , () -> {
363+ return services .getMasterProcedureExecutor ().getActiveProcIds ().isEmpty ();
364+ });
365+
366+ // No merge is done, overlap is still there.
367+ cj .scan ();
368+ report = cj .getLastReport ();
369+ assertEquals (2 , report .getOverlaps ().size ());
370+
371+ fixer .fixOverlaps (report );
372+
373+ // Wait until all procedures settled down
374+ await (200 , () -> {
375+ return services .getMasterProcedureExecutor ().getActiveProcIds ().isEmpty ();
376+ });
377+
378+ // Merge is done and no more overlaps
379+ cj .scan ();
380+ report = cj .getLastReport ();
381+ assertEquals (0 , report .getOverlaps ().size ());
382+ }
383+
311384 /**
312385 * Make it so a big overlap spans many Regions, some of which are non-contiguous. Make it so
313386 * we can fix this condition. HBASE-24247
@@ -336,7 +409,6 @@ public void testOverlapWithMergeOfNonContiguous() throws Exception {
336409 while (!services .getMasterProcedureExecutor ().isFinished (pid )) {
337410 Threads .sleep (100 );
338411 }
339- Threads .sleep (10000 );
340412 services .getCatalogJanitor ().scan ();
341413 report = services .getCatalogJanitor ().getLastReport ();
342414 assertEquals (1 , MetaFixer .calculateMerges (10 , report .getOverlaps ()).size ());
0 commit comments