Index: src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegionInfo.java =================================================================== --- src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegionInfo.java (revision 1211064) +++ src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegionInfo.java (working copy) @@ -116,6 +116,16 @@ } @Test + public void testLastRegionCompare() { + HTableDescriptor tableDesc = new HTableDescriptor("testtable"); + HRegionInfo hrip = new HRegionInfo( + tableDesc.getName(), Bytes.toBytes("a"), new byte[0]); + HRegionInfo hric = new HRegionInfo( + tableDesc.getName(), Bytes.toBytes("a"), Bytes.toBytes("b")); + assertTrue(hrip.compareTo(hric) > 0); + } + + @Test public void testMetaTables() { assertTrue(HRegionInfo.ROOT_REGIONINFO.isMetaTable()); assertTrue(HRegionInfo.FIRST_META_REGIONINFO.isMetaTable()); Index: src/test/java/org/apache/hadoop/hbase/master/TestCatalogJanitor.java =================================================================== --- src/test/java/org/apache/hadoop/hbase/master/TestCatalogJanitor.java (revision 1211064) +++ src/test/java/org/apache/hadoop/hbase/master/TestCatalogJanitor.java (working copy) @@ -333,23 +333,50 @@ /** * Make sure parent gets cleaned up even if daughter is cleaned up before it. * @throws IOException - * @throws InterruptedException + * @throws InterruptedException */ @Test public void testParentCleanedEvenIfDaughterGoneFirst() throws IOException, InterruptedException { + parentWithSpecifiedEndKeyCleanedEvenIfDaughterGoneFirst( + "testParentCleanedEvenIfDaughterGoneFirst", Bytes.toBytes("eee")); + } + + /** + * Make sure last parent with empty end key gets cleaned up even if daughter is cleaned up before it. + * @throws IOException + * @throws InterruptedException + */ + @Test + public void testLastParentCleanedEvenIfDaughterGoneFirst() + throws IOException, InterruptedException { + parentWithSpecifiedEndKeyCleanedEvenIfDaughterGoneFirst( + "testLastParentCleanedEvenIfDaughterGoneFirst", new byte[0]); + } + + /** + * Make sure parent with specified end key gets cleaned up even if daughter is cleaned up before it. + * + * @param rootDir the test case name, used as the HBase testing utility root + * @param lastEndKey the end key of the split parent + * @throws IOException + * @throws InterruptedException + */ + private void parentWithSpecifiedEndKeyCleanedEvenIfDaughterGoneFirst( + final String rootDir, final byte[] lastEndKey) + throws IOException, InterruptedException { HBaseTestingUtility htu = new HBaseTestingUtility(); - setRootDirAndCleanIt(htu, "testParentCleanedEvenIfDaughterGoneFirst"); + setRootDirAndCleanIt(htu, rootDir); Server server = new MockServer(htu); MasterServices services = new MockMasterServices(server); CatalogJanitor janitor = new CatalogJanitor(server, services); final HTableDescriptor htd = createHTableDescriptor(); - // Create regions: aaa->eee, aaa->ccc, aaa->bbb, bbb->ccc, etc. + // Create regions: aaa->{lastEndKey}, aaa->ccc, aaa->bbb, bbb->ccc, etc. // Parent HRegionInfo parent = new HRegionInfo(htd.getName(), Bytes.toBytes("aaa"), - Bytes.toBytes("eee")); + lastEndKey); // Sleep a second else the encoded name on these regions comes out // same for all with same start key and made in same second. Thread.sleep(1001); @@ -366,13 +393,13 @@ // Daughter b HRegionInfo splitb = new HRegionInfo(htd.getName(), Bytes.toBytes("ccc"), - Bytes.toBytes("eee")); + lastEndKey); Thread.sleep(1001); // Make Daughters of daughterb; splitba and splitbb. HRegionInfo splitba = new HRegionInfo(htd.getName(), Bytes.toBytes("ccc"), Bytes.toBytes("ddd")); HRegionInfo splitbb = new HRegionInfo(htd.getName(), Bytes.toBytes("ddd"), - Bytes.toBytes("eee")); + lastEndKey); // First test that our Comparator works right up in CatalogJanitor. // Just fo kicks. Index: src/main/java/org/apache/hadoop/hbase/HRegionInfo.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/HRegionInfo.java (revision 1211064) +++ src/main/java/org/apache/hadoop/hbase/HRegionInfo.java (working copy) @@ -775,11 +775,14 @@ // Compare end keys. result = Bytes.compareTo(this.endKey, o.endKey); + if (result != 0) { + if (this.getEndKey().length == 0) return 1; // this is last region + if (o.getEndKey().length == 0) return -1; // o is the last region return result; } if (this.offLine == o.offLine) - return 0; + return 0; if (this.offLine == true) return -1; return 1; Index: src/main/java/org/apache/hadoop/hbase/master/CatalogJanitor.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/CatalogJanitor.java (revision 1211064) +++ src/main/java/org/apache/hadoop/hbase/master/CatalogJanitor.java (working copy) @@ -157,7 +157,11 @@ if (result != 0) return result; // Compare end keys. result = Bytes.compareTo(left.getEndKey(), right.getEndKey()); - if (result != 0) return -result; // Flip the result so parent comes first. + if (result != 0) { + if (left.getEndKey().length == 0) return -1; // left is last region + if (right.getEndKey().length == 0) return 1; // right is the last region + return -result; // Flip the result so parent comes first. + } return result; } }