Author: stack
Date: Thu Mar 1 20:12:07 2012
New Revision: 1295767
URL: http://svn.apache.org/viewvc?rev=1295767&view=rev
Log:
HBASE-5489 Add HTable accessor to get regions for a key range
Modified:
hbase/branches/0.92/CHANGES.txt
hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/client/HTable.java
hbase/branches/0.92/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
Modified: hbase/branches/0.92/CHANGES.txt
URL:
http://svn.apache.org/viewvc/hbase/branches/0.92/CHANGES.txt?rev=1295767&r1=1295766&r2=1295767&view=diff
==============================================================================
--- hbase/branches/0.92/CHANGES.txt (original)
+++ hbase/branches/0.92/CHANGES.txt Thu Mar 1 20:12:07 2012
@@ -56,6 +56,8 @@ Release 0.92.1 - Unreleased
HBASE-5502 region_mover.rb fails to load regions back to original
server for regions only containing empty tables.
(James Page)
+ HBASE-5489 Add HTable accessor to get regions for a key range
+ (David S. Wang)
IMPROVEMENTS
Modified:
hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/client/HTable.java
URL:
http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/client/HTable.java?rev=1295767&r1=1295766&r2=1295767&view=diff
==============================================================================
---
hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/client/HTable.java
(original)
+++
hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/client/HTable.java
Thu Mar 1 20:12:07 2012
@@ -348,6 +348,7 @@ public class HTable implements HTableInt
* @param row Row to find.
* @return Location of the row.
* @throws IOException if a remote or network exception occurs
+ * @deprecated use {@link #getRegionLocation(byte [], boolean)} instead
*/
public HRegionLocation getRegionLocation(final byte [] row)
throws IOException {
@@ -355,6 +356,19 @@ public class HTable implements HTableInt
}
/**
+ * Finds the region on which the given row is being served.
+ * @param row Row to find.
+ * @param reload whether or not to reload information or just use cached
+ * information
+ * @return Location of the row.
+ * @throws IOException if a remote or network exception occurs
+ */
+ public HRegionLocation getRegionLocation(final byte [] row, boolean reload)
+ throws IOException {
+ return connection.getRegionLocation(tableName, row, reload);
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -515,6 +529,35 @@ public class HTable implements HTableInt
}
/**
+ * Get the corresponding regions for an arbitrary range of keys.
+ * <p>
+ * @param startRow Starting row in range, inclusive
+ * @param endRow Ending row in range, inclusive
+ * @return A list of HRegionLocations corresponding to the regions that
+ * contain the specified range
+ * @throws IOException if a remote or network exception occurs
+ */
+ public List<HRegionLocation> getRegionsInRange(final byte [] startKey,
+ final byte [] endKey) throws IOException {
+ final boolean endKeyIsEndOfTable = Bytes.equals(endKey,
+ HConstants.EMPTY_END_ROW);
+ if ((Bytes.compareTo(startKey, endKey) > 0) && !endKeyIsEndOfTable) {
+ throw new IllegalArgumentException(
+ "Invalid range: " + Bytes.toStringBinary(startKey) +
+ " > " + Bytes.toStringBinary(endKey));
+ }
+ final List<HRegionLocation> regionList = new ArrayList<HRegionLocation>();
+ byte [] currentKey = startKey;
+ do {
+ HRegionLocation regionLocation = getRegionLocation(currentKey, false);
+ regionList.add(regionLocation);
+ currentKey = regionLocation.getRegionInfo().getEndKey();
+ } while (!Bytes.equals(currentKey, HConstants.EMPTY_END_ROW) &&
+ (endKeyIsEndOfTable || Bytes.compareTo(currentKey, endKey) < 0));
+ return regionList;
+ }
+
+ /**
* Save the passed region information and the table's regions
* cache.
* <p>
Modified:
hbase/branches/0.92/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
URL:
http://svn.apache.org/viewvc/hbase/branches/0.92/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java?rev=1295767&r1=1295766&r2=1295767&view=diff
==============================================================================
---
hbase/branches/0.92/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
(original)
+++
hbase/branches/0.92/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
Thu Mar 1 20:12:07 2012
@@ -21,6 +21,7 @@ package org.apache.hadoop.hbase.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -51,11 +52,14 @@ import org.apache.hadoop.hbase.HBaseTest
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.HServerAddress;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.filter.BinaryComparator;
import org.apache.hadoop.hbase.filter.CompareFilter;
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.FilterList;
import org.apache.hadoop.hbase.filter.KeyOnlyFilter;
@@ -65,10 +69,10 @@ import org.apache.hadoop.hbase.filter.Re
import org.apache.hadoop.hbase.filter.RowFilter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.filter.WhileMatchFilter;
-import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.io.hfile.BlockCache;
import org.apache.hadoop.hbase.io.hfile.CacheConfig;
import org.apache.hadoop.hbase.regionserver.HRegion;
+import org.apache.hadoop.hbase.regionserver.HRegionServer;
import org.apache.hadoop.hbase.regionserver.Store;
import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest;
import org.apache.hadoop.hbase.util.Bytes;
@@ -91,6 +95,7 @@ public class TestFromClientSide {
private static byte [] FAMILY = Bytes.toBytes("testFamily");
private static byte [] QUALIFIER = Bytes.toBytes("testQualifier");
private static byte [] VALUE = Bytes.toBytes("testValue");
+ private static int SLAVES = 3;
/**
* @throws java.lang.Exception
@@ -98,7 +103,7 @@ public class TestFromClientSide {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
// We need more than one region server in this test
- TEST_UTIL.startMiniCluster(3);
+ TEST_UTIL.startMiniCluster(SLAVES);
}
/**
@@ -4308,4 +4313,115 @@ public class TestFromClientSide {
System.currentTimeMillis() + ", cur=" + store.getNumberOfstorefiles());
assertEquals(count, store.getNumberOfstorefiles());
}
+
+ @Test
+ /**
+ * Tests the non cached version of getRegionLocation by moving a region.
+ */
+ public void testNonCachedGetRegionLocation() throws Exception {
+ // Test Initialization.
+ String tableName = "testNonCachedGetRegionLocation";
+ byte [] TABLE = Bytes.toBytes(tableName);
+ byte [] family1 = Bytes.toBytes("f1");
+ byte [] family2 = Bytes.toBytes("f2");
+ HTable table = TEST_UTIL.createTable(TABLE, new byte[][] {family1,
family2}, 10);
+ HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
+ Map <HRegionInfo, ServerName> regionsMap = table.getRegionLocations();
+ assertEquals(1, regionsMap.size());
+ HRegionInfo regionInfo = regionsMap.keySet().iterator().next();
+ ServerName addrBefore = regionsMap.get(regionInfo);
+ // Verify region location before move.
+ HServerAddress addrCache =
+ table.getRegionLocation(regionInfo.getStartKey(),
false).getServerAddress();
+ HServerAddress addrNoCache =
+ table.getRegionLocation(regionInfo.getStartKey(),
+ true).getServerAddress();
+
+ assertEquals(addrBefore.getPort(), addrCache.getPort());
+ assertEquals(addrBefore.getPort(), addrNoCache.getPort());
+
+ ServerName addrAfter = null;
+ // Now move the region to a different server.
+ for (int i = 0; i < SLAVES; i++) {
+ HRegionServer regionServer =
TEST_UTIL.getHBaseCluster().getRegionServer(i);
+ ServerName addr = regionServer.getServerName();
+ if (addr.getPort() != addrBefore.getPort()) {
+ admin.move(regionInfo.getEncodedNameAsBytes(),
+ Bytes.toBytes(addr.toString()));
+ // Wait for the region to move.
+ Thread.sleep(5000);
+ addrAfter = addr;
+ break;
+ }
+ }
+
+ // Verify the region was moved.
+ addrCache =
+ table.getRegionLocation(regionInfo.getStartKey(),
false).getServerAddress();
+ addrNoCache =
+ table.getRegionLocation(regionInfo.getStartKey(),
+ true).getServerAddress();
+ assertNotNull(addrAfter);
+ assertTrue(addrAfter.getPort() != addrCache.getPort());
+ assertEquals(addrAfter.getPort(), addrNoCache.getPort());
+ }
+
+ @Test
+ /**
+ * Tests getRegionsInRange by creating some regions over which a range of
+ * keys spans; then changing the key range.
+ */
+ public void testGetRegionsInRange() throws Exception {
+ // Test Initialization.
+ byte [] startKey = Bytes.toBytes("ddc");
+ byte [] endKey = Bytes.toBytes("mmm");
+ byte [] TABLE = Bytes.toBytes("testGetRegionsInRange");
+ HTable table = TEST_UTIL.createTable(TABLE, new byte[][] {FAMILY}, 10);
+ int numOfRegions = TEST_UTIL.createMultiRegions(table, FAMILY);
+ assertEquals(25, numOfRegions);
+ HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
+
+ // Get the regions in this range
+ List<HRegionLocation> regionsList = table.getRegionsInRange(startKey,
+ endKey);
+ assertEquals(10, regionsList.size());
+
+ // Change the start key
+ startKey = Bytes.toBytes("fff");
+ regionsList = table.getRegionsInRange(startKey, endKey);
+ assertEquals(7, regionsList.size());
+
+ // Change the end key
+ endKey = Bytes.toBytes("nnn");
+ regionsList = table.getRegionsInRange(startKey, endKey);
+ assertEquals(8, regionsList.size());
+
+ // Empty start key
+ regionsList = table.getRegionsInRange(HConstants.EMPTY_START_ROW, endKey);
+ assertEquals(13, regionsList.size());
+
+ // Empty end key
+ regionsList = table.getRegionsInRange(startKey, HConstants.EMPTY_END_ROW);
+ assertEquals(20, regionsList.size());
+
+ // Both start and end keys empty
+ regionsList = table.getRegionsInRange(HConstants.EMPTY_START_ROW,
+ HConstants.EMPTY_END_ROW);
+ assertEquals(25, regionsList.size());
+
+ // Change the end key to somewhere in the last block
+ endKey = Bytes.toBytes("yyz");
+ regionsList = table.getRegionsInRange(startKey, endKey);
+ assertEquals(20, regionsList.size());
+
+ // Change the start key to somewhere in the first block
+ startKey = Bytes.toBytes("aac");
+ regionsList = table.getRegionsInRange(startKey, endKey);
+ assertEquals(25, regionsList.size());
+
+ // Make start and end key the same
+ startKey = endKey = Bytes.toBytes("ccc");
+ regionsList = table.getRegionsInRange(startKey, endKey);
+ assertEquals(1, regionsList.size());
+ }
}