From 142be461c82bb744357893e5e0727eec19fbd1a0 Mon Sep 17 00:00:00 2001 From: "shuai.lou" Date: Sun, 10 Aug 2014 18:14:17 +0800 Subject: [PATCH] HBASE-11708 RegionSplitter incorrectly calculates splitcount when split table using the util(UniformSplit or HexStringSplit), with "-r" option, the caculation of splitCount in funciton rollingSplit may be wrong. --- .../apache/hadoop/hbase/util/RegionSplitter.java | 13 +- .../hadoop/hbase/util/TestRegionSplitter.java | 153 ++++++++++++--------- 2 files changed, 96 insertions(+), 70 deletions(-) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/RegionSplitter.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/RegionSplitter.java index 8a2ffaa..58e7a8b 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/RegionSplitter.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/RegionSplitter.java @@ -532,16 +532,20 @@ public class RegionSplitter { admin.split(table.getTableName(), split); LinkedList> finished = Lists.newLinkedList(); + LinkedList> local_finished = Lists.newLinkedList(); if (conf.getBoolean("split.verify", true)) { // we need to verify and rate-limit our splits outstanding.addLast(dr); // with too many outstanding splits, wait for some to finish while (outstanding.size() >= MAX_OUTSTANDING) { - finished = splitScan(outstanding, table, splitAlgo); - if (finished.isEmpty()) { + LOG.debug("Wait for outstanding splits " + outstanding.size()); + local_finished = splitScan(outstanding, table, splitAlgo); + if (local_finished.isEmpty()) { Thread.sleep(30 * 1000); } else { - outstanding.removeAll(finished); + finished.addAll(local_finished); + outstanding.removeAll(local_finished); + LOG.debug(local_finished.size() + " outstanding splits finished"); } } } else { @@ -565,6 +569,7 @@ public class RegionSplitter { } if (conf.getBoolean("split.verify", true)) { while (!outstanding.isEmpty()) { + LOG.debug("Finally Wait for outstanding splits " + outstanding.size()); LinkedList> finished = splitScan(outstanding, table, splitAlgo); if (finished.isEmpty()) { @@ -574,7 +579,9 @@ public class RegionSplitter { for (Pair region : finished) { splitOut.writeChars("- " + splitAlgo.rowToStr(region.getFirst()) + " " + splitAlgo.rowToStr(region.getSecond()) + "\n"); + splitCount++; } + LOG.debug("Finally " + finished.size() + " outstanding splits finished"); } } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestRegionSplitter.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestRegionSplitter.java index 407be0d..a9603fe 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestRegionSplitter.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestRegionSplitter.java @@ -53,6 +53,7 @@ import org.junit.experimental.categories.Category; public class TestRegionSplitter { private final static Log LOG = LogFactory.getLog(TestRegionSplitter.class); private final static HBaseTestingUtility UTIL = new HBaseTestingUtility(); + private final static String TABLE_NAME = "SPLIT_TEST_TABLE"; private final static String CF_NAME = "SPLIT_TEST_CF"; private final static byte xFF = (byte) 0xff; @@ -265,77 +266,95 @@ public class TestRegionSplitter { } } - /** - * Creates a pre-split table with expectedBounds.size()+1 regions, then - * verifies that the region boundaries are the same as the expected - * region boundaries in expectedBounds. - * @throws Various junit assertions - */ - private void preSplitTableAndVerify(List expectedBounds, - String splitClass, String tableName) throws Exception { - final int numRegions = expectedBounds.size()-1; - final Configuration conf = UTIL.getConfiguration(); - conf.setInt("split.count", numRegions); - SplitAlgorithm splitAlgo = RegionSplitter.newSplitAlgoInstance(conf, splitClass); - RegionSplitter.createPresplitTable(tableName, splitAlgo, - new String[] {CF_NAME}, conf); - verifyBounds(expectedBounds, tableName); - } + /** + * Creates a pre-split table with expectedBounds.size()+1 regions, then + * verifies that the region boundaries are the same as the expected + * region boundaries in expectedBounds. + * @throws Various junit assertions + */ + private void preSplitTableAndVerify(List expectedBounds, + String splitClass, String tableName) throws Exception { + final int numRegions = expectedBounds.size()-1; + final Configuration conf = UTIL.getConfiguration(); + conf.setInt("split.count", numRegions); + SplitAlgorithm splitAlgo = RegionSplitter.newSplitAlgoInstance(conf, splitClass); + RegionSplitter.createPresplitTable(tableName, splitAlgo, + new String[] {CF_NAME}, conf); + verifyBounds(expectedBounds, tableName); + } - private void rollingSplitAndVerify(String tableName, String splitClass, - List expectedBounds) throws Exception { - final Configuration conf = UTIL.getConfiguration(); + @Test + public void splitCountTest() throws Exception { + final Configuration conf = UTIL.getConfiguration(); + final List expectedBounds = new ArrayList(); + final byte[] TEST_TABLE = Bytes.toBytes(TABLE_NAME); + final byte[] TEST_FAMILY = Bytes.toBytes(CF_NAME); - // Set this larger than the number of splits so RegionSplitter won't block - conf.setInt("split.outstanding", 5); - SplitAlgorithm splitAlgo = RegionSplitter.newSplitAlgoInstance(conf, splitClass); - RegionSplitter.rollingSplit(tableName, splitAlgo, conf); - verifyBounds(expectedBounds, tableName); - } + UTIL.createTable(TEST_TABLE, TEST_FAMILY); - private void verifyBounds(List expectedBounds, String tableName) - throws Exception { - // Get region boundaries from the cluster and verify their endpoints - final Configuration conf = UTIL.getConfiguration(); - final int numRegions = expectedBounds.size()-1; - final HTable hTable = new HTable(conf, tableName.getBytes()); - final Map regionInfoMap = hTable.getRegionLocations(); - assertEquals(numRegions, regionInfoMap.size()); - for (Map.Entry entry: regionInfoMap.entrySet()) { - final HRegionInfo regionInfo = entry.getKey(); - byte[] regionStart = regionInfo.getStartKey(); - byte[] regionEnd = regionInfo.getEndKey(); - - // This region's start key should be one of the region boundaries - int startBoundaryIndex = indexOfBytes(expectedBounds, regionStart); - assertNotSame(-1, startBoundaryIndex); - - // This region's end key should be the region boundary that comes - // after the starting boundary. - byte[] expectedRegionEnd = expectedBounds.get( - startBoundaryIndex+1); - assertEquals(0, Bytes.compareTo(regionEnd, expectedRegionEnd)); - } - } + expectedBounds.add(ArrayUtils.EMPTY_BYTE_ARRAY); + expectedBounds.add(new byte[] {0x7f, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}); + expectedBounds.add(ArrayUtils.EMPTY_BYTE_ARRAY); - /** - * List.indexOf() doesn't really work for a List, because byte[] - * doesn't override equals(). This method checks whether a list contains - * a given element by checking each element using the byte array - * comparator. - * @return the index of the first element that equals compareTo, or -1 - * if no elements are equal. - */ - static private int indexOfBytes(List list, byte[] compareTo) { - int listIndex = 0; - for(byte[] elem: list) { - if(Bytes.BYTES_COMPARATOR.compare(elem, compareTo) == 0) { - return listIndex; - } - listIndex++; - } - return -1; - } + conf.setBoolean("split.verify", true); + rollingSplitAndVerify(TABLE_NAME, "UniformSplit", expectedBounds); + } + + private void rollingSplitAndVerify(String tableName, String splitClass, + List expectedBounds) throws Exception { + final Configuration conf = UTIL.getConfiguration(); + + // Set this larger than the number of splits so RegionSplitter won't block + conf.setInt("split.outstanding", 5); + SplitAlgorithm splitAlgo = RegionSplitter.newSplitAlgoInstance(conf, splitClass); + RegionSplitter.rollingSplit(tableName, splitAlgo, conf); + verifyBounds(expectedBounds, tableName); + } + + private void verifyBounds(List expectedBounds, String tableName) + throws Exception { + // Get region boundaries from the cluster and verify their endpoints + final Configuration conf = UTIL.getConfiguration(); + final int numRegions = expectedBounds.size()-1; + final HTable hTable = new HTable(conf, tableName.getBytes()); + final Map regionInfoMap = hTable.getRegionLocations(); + assertEquals(numRegions, regionInfoMap.size()); + for (Map.Entry entry: regionInfoMap.entrySet()) { + final HRegionInfo regionInfo = entry.getKey(); + byte[] regionStart = regionInfo.getStartKey(); + byte[] regionEnd = regionInfo.getEndKey(); + + // This region's start key should be one of the region boundaries + int startBoundaryIndex = indexOfBytes(expectedBounds, regionStart); + assertNotSame(-1, startBoundaryIndex); + + // This region's end key should be the region boundary that comes + // after the starting boundary. + byte[] expectedRegionEnd = expectedBounds.get( + startBoundaryIndex+1); + assertEquals(0, Bytes.compareTo(regionEnd, expectedRegionEnd)); + } + } + + /** + * List.indexOf() doesn't really work for a List, because byte[] + * doesn't override equals(). This method checks whether a list contains + * a given element by checking each element using the byte array + * comparator. + * @return the index of the first element that equals compareTo, or -1 + * if no elements are equal. + */ + static private int indexOfBytes(List list, byte[] compareTo) { + int listIndex = 0; + for(byte[] elem: list) { + if(Bytes.BYTES_COMPARATOR.compare(elem, compareTo) == 0) { + return listIndex; + } + listIndex++; + } + return -1; + } } -- 1.8.5.2 (Apple Git-48)