Author: tedyu
Date: Tue Aug 16 01:16:43 2011
New Revision: 1158080
URL: http://svn.apache.org/viewvc?rev=1158080&view=rev
Log:
HBASE-2399 Forced splits only act on the first family in a table (Ming Ma)
Modified:
hbase/trunk/CHANGES.txt
hbase/trunk/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
hbase/trunk/src/test/java/org/apache/hadoop/hbase/HBaseTestingUtility.java
hbase/trunk/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java
Modified: hbase/trunk/CHANGES.txt
URL:
http://svn.apache.org/viewvc/hbase/trunk/CHANGES.txt?rev=1158080&r1=1158079&r2=1158080&view=diff
==============================================================================
--- hbase/trunk/CHANGES.txt (original)
+++ hbase/trunk/CHANGES.txt Tue Aug 16 01:16:43 2011
@@ -199,6 +199,7 @@ Release 0.91.0 - Unreleased
set in config file (Ming Ma)
HBASE-4186 No region is added to regionsInTransitionInRS
HBASE-4194 RegionSplitter: Split on under-loaded region servers first
+ HBASE-2399 Forced splits only act on the first family in a table (Ming Ma)
IMPROVEMENTS
HBASE-3290 Max Compaction Size (Nicolas Spiegelberg via Stack)
Modified:
hbase/trunk/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
URL:
http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java?rev=1158080&r1=1158079&r2=1158080&view=diff
==============================================================================
--- hbase/trunk/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
(original)
+++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
Tue Aug 16 01:16:43 2011
@@ -3875,18 +3875,27 @@ public class HRegion implements HeapSize
// nothing
}
+ /**
+ * Return the splitpoint. null indicates the region isn't splittable
+ * If the splitpoint isn't explicitly specified, it will go over the stores
+ * to find the best splitpoint. Currently the criteria of best splitpoint
+ * is based on the size of the store.
+ */
public byte[] checkSplit() {
if (this.splitPoint != null) {
return this.splitPoint;
}
- byte[] splitPoint = null;
+ byte[] splitPointFromLargestStore = null;
+ long largestStoreSize = 0;
for (Store s : stores.values()) {
- splitPoint = s.checkSplit();
- if (splitPoint != null) {
- return splitPoint;
+ byte[] splitPoint = s.checkSplit();
+ long storeSize = s.getSize();
+ if (splitPoint != null && largestStoreSize < storeSize) {
+ splitPointFromLargestStore = splitPoint;
+ largestStoreSize = storeSize;
}
}
- return null;
+ return splitPointFromLargestStore;
}
/**
Modified:
hbase/trunk/src/test/java/org/apache/hadoop/hbase/HBaseTestingUtility.java
URL:
http://svn.apache.org/viewvc/hbase/trunk/src/test/java/org/apache/hadoop/hbase/HBaseTestingUtility.java?rev=1158080&r1=1158079&r2=1158080&view=diff
==============================================================================
--- hbase/trunk/src/test/java/org/apache/hadoop/hbase/HBaseTestingUtility.java
(original)
+++ hbase/trunk/src/test/java/org/apache/hadoop/hbase/HBaseTestingUtility.java
Tue Aug 16 01:16:43 2011
@@ -708,6 +708,31 @@ public class HBaseTestingUtility {
* @throws IOException
*/
public HTable createTable(byte[] tableName, byte[][] families,
+ int numVersions, int blockSize) throws IOException {
+ HTableDescriptor desc = new HTableDescriptor(tableName);
+ for (byte[] family : families) {
+ HColumnDescriptor hcd = new HColumnDescriptor(family, numVersions,
+ HColumnDescriptor.DEFAULT_COMPRESSION,
+ HColumnDescriptor.DEFAULT_IN_MEMORY,
+ HColumnDescriptor.DEFAULT_BLOCKCACHE,
+ blockSize, HColumnDescriptor.DEFAULT_TTL,
+ HColumnDescriptor.DEFAULT_BLOOMFILTER,
+ HColumnDescriptor.DEFAULT_REPLICATION_SCOPE);
+ desc.addFamily(hcd);
+ }
+ getHBaseAdmin().createTable(desc);
+ return new HTable(new Configuration(getConfiguration()), tableName);
+ }
+
+ /**
+ * Create a table.
+ * @param tableName
+ * @param families
+ * @param numVersions
+ * @return An HTable instance for the created table.
+ * @throws IOException
+ */
+ public HTable createTable(byte[] tableName, byte[][] families,
int[] numVersions)
throws IOException {
HTableDescriptor desc = new HTableDescriptor(tableName);
Modified:
hbase/trunk/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java
URL:
http://svn.apache.org/viewvc/hbase/trunk/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java?rev=1158080&r1=1158079&r2=1158080&view=diff
==============================================================================
--- hbase/trunk/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java
(original)
+++ hbase/trunk/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java Tue
Aug 16 01:16:43 2011
@@ -564,29 +564,71 @@ public class TestAdmin {
*/
@Test
public void testForceSplit() throws Exception {
- splitTest(null);
- splitTest(Bytes.toBytes("pwn"));
- }
+ byte[][] familyNames = new byte[][] { Bytes.toBytes("cf") };
+ int[] rowCounts = new int[] { 6000 };
+ int numVersions = HColumnDescriptor.DEFAULT_VERSIONS;
+ int blockSize = 256;
+ splitTest(null, familyNames, rowCounts, numVersions, blockSize);
+
+ byte[] splitKey = Bytes.toBytes(3500);
+ splitTest(splitKey, familyNames, rowCounts, numVersions, blockSize);
+ }
+
+ /**
+ * Multi-family scenario. Tests forcing split from client and
+ * having scanners successfully ride over split.
+ * @throws Exception
+ * @throws IOException
+ */
+ @Test
+ public void testForceSplitMultiFamily() throws Exception {
+ int numVersions = HColumnDescriptor.DEFAULT_VERSIONS;
+
+ // use small HFile block size so that we can have lots of blocks in HFile
+ // Otherwise, if there is only one block,
+ // HFileBlockIndex.midKey()'s value == startKey
+ int blockSize = 256;
+ byte[][] familyNames = new byte[][] { Bytes.toBytes("cf1"),
+ Bytes.toBytes("cf2") };
+
+ // one of the column families isn't splittable
+ int[] rowCounts = new int[] { 6000, 1 };
+ splitTest(null, familyNames, rowCounts, numVersions, blockSize);
+
+ rowCounts = new int[] { 1, 6000 };
+ splitTest(null, familyNames, rowCounts, numVersions, blockSize);
+
+ // one column family has much smaller data than the other
+ // the split key should be based on the largest column family
+ rowCounts = new int[] { 6000, 300 };
+ splitTest(null, familyNames, rowCounts, numVersions, blockSize);
- void splitTest(byte[] splitPoint) throws Exception {
- byte [] familyName = HConstants.CATALOG_FAMILY;
+ rowCounts = new int[] { 300, 6000 };
+ splitTest(null, familyNames, rowCounts, numVersions, blockSize);
+
+ }
+
+ void splitTest(byte[] splitPoint, byte[][] familyNames, int[] rowCounts,
+ int numVersions, int blockSize) throws Exception {
byte [] tableName = Bytes.toBytes("testForceSplit");
assertFalse(admin.tableExists(tableName));
- final HTable table = TEST_UTIL.createTable(tableName, familyName);
+ final HTable table = TEST_UTIL.createTable(tableName, familyNames,
+ numVersions, blockSize);
try {
- byte[] k = new byte[3];
int rowCount = 0;
- for (byte b1 = 'a'; b1 < 'z'; b1++) {
- for (byte b2 = 'a'; b2 < 'z'; b2++) {
- for (byte b3 = 'a'; b3 < 'z'; b3++) {
- k[0] = b1;
- k[1] = b2;
- k[2] = b3;
- Put put = new Put(k);
- put.add(familyName, new byte[0], k);
- table.put(put);
- rowCount++;
- }
+
+ // insert rows into column families. The number of rows that have values
+ // in a specific column family is decided by rowCounts[familyIndex]
+ for (int index = 0; index < familyNames.length; index++) {
+ for (int i = 0; i < rowCounts[index]; i++) {
+ byte[] k = Bytes.toBytes(i);
+ Put put = new Put(k);
+ put.add(familyNames[index], new byte[0], k);
+ table.put(put);
+ }
+
+ if ( rowCount < rowCounts[index] ) {
+ rowCount = rowCounts[index];
}
}
@@ -651,21 +693,32 @@ public class TestAdmin {
scanner.close();
assertEquals(rowCount, rows);
+ Map<HRegionInfo, HServerAddress> regions = null;
+ try {
+ regions = table.getRegionsInfo();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ assertEquals(2, regions.size());
+ HRegionInfo[] r = regions.keySet().toArray(new HRegionInfo[0]);
if (splitPoint != null) {
// make sure the split point matches our explicit configuration
- Map<HRegionInfo, HServerAddress> regions = null;
- try {
- regions = table.getRegionsInfo();
- } catch (IOException e) {
- e.printStackTrace();
- }
- assertEquals(2, regions.size());
- HRegionInfo[] r = regions.keySet().toArray(new HRegionInfo[0]);
assertEquals(Bytes.toString(splitPoint),
Bytes.toString(r[0].getEndKey()));
assertEquals(Bytes.toString(splitPoint),
Bytes.toString(r[1].getStartKey()));
LOG.debug("Properly split on " + Bytes.toString(splitPoint));
+ } else {
+ if (familyNames.length > 1) {
+ int splitKey = Bytes.toInt(r[0].getEndKey());
+ // check if splitKey is based on the largest column family
+ // in terms of it store size
+ int deltaForLargestFamily = Math.abs(rowCount/2 - splitKey);
+ for (int index = 0; index < familyNames.length; index++) {
+ int delta = Math.abs(rowCounts[index]/2 - splitKey);
+ assertTrue(delta >= deltaForLargestFamily);
+ }
+ }
}
} finally {
TEST_UTIL.deleteTable(tableName);