HBASE-14824 HBaseAdmin.mergeRegions should recognize both full region names and encoded region names (Eungsop Yoo)

This commit is contained in:
tedyu 2015-11-18 14:24:47 -08:00
parent b2187c31ab
commit d738aade2e
4 changed files with 73 additions and 11 deletions

View File

@ -118,6 +118,9 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
private static final int MAX_REPLICA_ID = 0xFFFF; private static final int MAX_REPLICA_ID = 0xFFFF;
public static final int DEFAULT_REPLICA_ID = 0; public static final int DEFAULT_REPLICA_ID = 0;
public static final String INVALID_REGION_NAME_FORMAT_MESSAGE = "Invalid regionName format";
/** /**
* Does region name contain its encoded name? * Does region name contain its encoded name?
* @param regionName region name * @param regionName region name
@ -521,7 +524,8 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
} }
} }
if (offset == -1) { if (offset == -1) {
throw new IOException("Invalid regionName format: " + Bytes.toStringBinary(regionName)); throw new IOException(INVALID_REGION_NAME_FORMAT_MESSAGE
+ ": " + Bytes.toStringBinary(regionName));
} }
byte[] tableName = new byte[offset]; byte[] tableName = new byte[offset];
System.arraycopy(regionName, 0, tableName, 0, offset); System.arraycopy(regionName, 0, tableName, 0, offset);
@ -552,7 +556,8 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
} }
} }
if (offset == -1) { if (offset == -1) {
throw new IOException("Invalid regionName format: " + Bytes.toStringBinary(regionName)); throw new IOException(INVALID_REGION_NAME_FORMAT_MESSAGE
+ ": " + Bytes.toStringBinary(regionName));
} }
byte [] startKey = HConstants.EMPTY_BYTE_ARRAY; byte [] startKey = HConstants.EMPTY_BYTE_ARRAY;
if(offset != tableName.length + 1) { if(offset != tableName.length + 1) {

View File

@ -864,13 +864,13 @@ public interface Admin extends Abortable, Closeable {
/** /**
* Merge two regions. Asynchronous operation. * Merge two regions. Asynchronous operation.
* *
* @param encodedNameOfRegionA encoded name of region a * @param nameOfRegionA encoded or full name of region a
* @param encodedNameOfRegionB encoded name of region b * @param nameOfRegionB encoded or full name of region b
* @param forcible true if do a compulsory merge, otherwise we will only merge two adjacent * @param forcible true if do a compulsory merge, otherwise we will only merge two adjacent
* regions * regions
* @throws IOException * @throws IOException
*/ */
void mergeRegions(final byte[] encodedNameOfRegionA, final byte[] encodedNameOfRegionB, void mergeRegions(final byte[] nameOfRegionA, final byte[] nameOfRegionB,
final boolean forcible) throws IOException; final boolean forcible) throws IOException;
/** /**

View File

@ -2267,22 +2267,40 @@ public class HBaseAdmin implements Admin {
}); });
} }
private boolean isEncodedRegionName(byte[] regionName) throws IOException {
try {
HRegionInfo.parseRegionName(regionName);
return false;
} catch (IOException e) {
if (StringUtils.stringifyException(e)
.contains(HRegionInfo.INVALID_REGION_NAME_FORMAT_MESSAGE)) {
return true;
}
throw e;
}
}
/** /**
* Merge two regions. Asynchronous operation. * Merge two regions. Asynchronous operation.
* @param encodedNameOfRegionA encoded name of region a * @param nameOfRegionA encoded or full name of region a
* @param encodedNameOfRegionB encoded name of region b * @param nameOfRegionB encoded or full name of region b
* @param forcible true if do a compulsory merge, otherwise we will only merge * @param forcible true if do a compulsory merge, otherwise we will only merge
* two adjacent regions * two adjacent regions
* @throws IOException * @throws IOException
*/ */
@Override @Override
public void mergeRegions(final byte[] encodedNameOfRegionA, public void mergeRegions(final byte[] nameOfRegionA,
final byte[] encodedNameOfRegionB, final boolean forcible) final byte[] nameOfRegionB, final boolean forcible)
throws IOException { throws IOException {
Pair<HRegionInfo, ServerName> pair = getRegion(encodedNameOfRegionA); final byte[] encodedNameOfRegionA = isEncodedRegionName(nameOfRegionA) ?
nameOfRegionA : HRegionInfo.encodeRegionName(nameOfRegionA).getBytes();
final byte[] encodedNameOfRegionB = isEncodedRegionName(nameOfRegionB) ?
nameOfRegionB : HRegionInfo.encodeRegionName(nameOfRegionB).getBytes();
Pair<HRegionInfo, ServerName> pair = getRegion(nameOfRegionA);
if (pair != null && pair.getFirst().getReplicaId() != HRegionInfo.DEFAULT_REPLICA_ID) if (pair != null && pair.getFirst().getReplicaId() != HRegionInfo.DEFAULT_REPLICA_ID)
throw new IllegalArgumentException("Can't invoke merge on non-default regions directly"); throw new IllegalArgumentException("Can't invoke merge on non-default regions directly");
pair = getRegion(encodedNameOfRegionB); pair = getRegion(nameOfRegionB);
if (pair != null && pair.getFirst().getReplicaId() != HRegionInfo.DEFAULT_REPLICA_ID) if (pair != null && pair.getFirst().getReplicaId() != HRegionInfo.DEFAULT_REPLICA_ID)
throw new IllegalArgumentException("Can't invoke merge on non-default regions directly"); throw new IllegalArgumentException("Can't invoke merge on non-default regions directly");
executeCallable(new MasterCallable<Void>(getConnection()) { executeCallable(new MasterCallable<Void>(getConnection()) {

View File

@ -1393,4 +1393,43 @@ public class TestAdmin1 {
} }
} }
} }
@Test
public void testMergeRegions() throws Exception {
TableName tableName = TableName.valueOf("testMergeWithFullRegionName");
HColumnDescriptor cd = new HColumnDescriptor("d");
HTableDescriptor td = new HTableDescriptor(tableName);
td.addFamily(cd);
byte[][] splitRows = new byte[2][];
splitRows[0] = new byte[]{(byte)'3'};
splitRows[1] = new byte[]{(byte)'6'};
try {
TEST_UTIL.createTable(td, splitRows);
TEST_UTIL.waitTableAvailable(tableName);
List<HRegionInfo> tableRegions;
HRegionInfo regionA;
HRegionInfo regionB;
// merge with full name
tableRegions = admin.getTableRegions(tableName);
assertEquals(3, admin.getTableRegions(tableName).size());
regionA = tableRegions.get(0);
regionB = tableRegions.get(1);
admin.mergeRegions(regionA.getRegionName(), regionB.getRegionName(), false);
Thread.sleep(1000);
assertEquals(2, admin.getTableRegions(tableName).size());
// merge with encoded name
tableRegions = admin.getTableRegions(tableName);
regionA = tableRegions.get(0);
regionB = tableRegions.get(1);
admin.mergeRegions(regionA.getEncodedNameAsBytes(), regionB.getEncodedNameAsBytes(), false);
Thread.sleep(1000);
assertEquals(1, admin.getTableRegions(tableName).size());
} finally {
this.admin.disableTable(tableName);
this.admin.deleteTable(tableName);
}
}
} }