blob: 3b66f7eb2e60a51c94c2e3d0639b85c3af952664 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.client;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNameTestRule;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.testclassification.ClientTests;
import org.apache.hadoop.hbase.testclassification.SmallTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
import org.apache.hadoop.hbase.util.MD5Hash;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
@Category({ ClientTests.class, SmallTests.class })
public class TestRegionInfoBuilder {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestRegionInfoBuilder.class);
@Rule
public TableNameTestRule name = new TableNameTestRule();
@Test
public void testBuilder() {
TableName tn = TableName.valueOf("test");
RegionInfoBuilder builder = RegionInfoBuilder.newBuilder(tn);
byte[] startKey = Bytes.toBytes("a");
builder.setStartKey(startKey);
byte[] endKey = Bytes.toBytes("z");
builder.setEndKey(endKey);
int regionId = 1;
builder.setRegionId(1);
int replicaId = 2;
builder.setReplicaId(replicaId);
boolean offline = true;
builder.setOffline(offline);
boolean isSplit = true;
builder.setSplit(isSplit);
RegionInfo ri = builder.build();
assertEquals(tn, ri.getTable());
assertArrayEquals(startKey, ri.getStartKey());
assertArrayEquals(endKey, ri.getEndKey());
assertEquals(regionId, ri.getRegionId());
assertEquals(replicaId, ri.getReplicaId());
assertEquals(offline, ri.isOffline());
assertEquals(isSplit, ri.isSplit());
}
@Test
public void testPb() throws DeserializationException {
RegionInfo ri = RegionInfoBuilder.FIRST_META_REGIONINFO;
byte[] bytes = RegionInfo.toByteArray(ri);
RegionInfo pbri = RegionInfo.parseFrom(bytes);
assertTrue(RegionInfo.COMPARATOR.compare(ri, pbri) == 0);
}
@Test
public void testCreateRegionInfoName() throws Exception {
final TableName tn = name.getTableName();
String startKey = "startkey";
final byte[] sk = Bytes.toBytes(startKey);
String id = "id";
// old format region name
byte[] name = RegionInfo.createRegionName(tn, sk, id, false);
String nameStr = Bytes.toString(name);
assertEquals(tn + "," + startKey + "," + id, nameStr);
// new format region name.
String md5HashInHex = MD5Hash.getMD5AsHex(name);
assertEquals(RegionInfo.MD5_HEX_LENGTH, md5HashInHex.length());
name = RegionInfo.createRegionName(tn, sk, id, true);
nameStr = Bytes.toString(name);
assertEquals(tn + "," + startKey + "," + id + "." + md5HashInHex + ".", nameStr);
}
@Test
public void testContainsRange() {
TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(name.getTableName()).build();
RegionInfo ri = RegionInfoBuilder.newBuilder(tableDesc.getTableName())
.setStartKey(Bytes.toBytes("a")).setEndKey(Bytes.toBytes("g")).build();
// Single row range at start of region
assertTrue(ri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("a")));
// Fully contained range
assertTrue(ri.containsRange(Bytes.toBytes("b"), Bytes.toBytes("c")));
// Range overlapping start of region
assertTrue(ri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("c")));
// Fully contained single-row range
assertTrue(ri.containsRange(Bytes.toBytes("c"), Bytes.toBytes("c")));
// Range that overlaps end key and hence doesn't fit
assertFalse(ri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("g")));
// Single row range on end key
assertFalse(ri.containsRange(Bytes.toBytes("g"), Bytes.toBytes("g")));
// Single row range entirely outside
assertFalse(ri.containsRange(Bytes.toBytes("z"), Bytes.toBytes("z")));
// Degenerate range
try {
ri.containsRange(Bytes.toBytes("z"), Bytes.toBytes("a"));
fail("Invalid range did not throw IAE");
} catch (IllegalArgumentException iae) {
}
}
@Test
public void testContainsRangeForMetaTable() {
TableDescriptor tableDesc =
TableDescriptorBuilder.newBuilder(TableName.META_TABLE_NAME).build();
RegionInfo hri = RegionInfoBuilder.newBuilder(tableDesc.getTableName()).build();
byte[] startRow = HConstants.EMPTY_START_ROW;
byte[] row1 = Bytes.toBytes("a,a,0");
byte[] row2 = Bytes.toBytes("aaaaa,,1");
byte[] row3 = Bytes.toBytes("aaaaa,\u0000\u0000,2");
byte[] row4 = Bytes.toBytes("aaaaa,\u0001,3");
byte[] row5 = Bytes.toBytes("aaaaa,a,4");
byte[] row6 = Bytes.toBytes("aaaaa,\u1000,5");
// Single row range at start of region
assertTrue(hri.containsRange(startRow, startRow));
// Fully contained range
assertTrue(hri.containsRange(row1, row2));
assertTrue(hri.containsRange(row2, row3));
assertTrue(hri.containsRange(row3, row4));
assertTrue(hri.containsRange(row4, row5));
assertTrue(hri.containsRange(row5, row6));
// Range overlapping start of region
assertTrue(hri.containsRange(startRow, row2));
// Fully contained single-row range
assertTrue(hri.containsRange(row1, row1));
// Degenerate range
try {
hri.containsRange(row3, row2);
fail("Invalid range did not throw IAE");
} catch (IllegalArgumentException iae) {
}
}
@Test
public void testLastRegionCompare() {
TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(name.getTableName()).build();
RegionInfo rip = RegionInfoBuilder.newBuilder(tableDesc.getTableName())
.setStartKey(Bytes.toBytes("a")).setEndKey(new byte[0]).build();
RegionInfo ric = RegionInfoBuilder.newBuilder(tableDesc.getTableName())
.setStartKey(Bytes.toBytes("a")).setEndKey(Bytes.toBytes("b")).build();
assertTrue(RegionInfo.COMPARATOR.compare(rip, ric) > 0);
}
@Test
public void testMetaTables() {
assertTrue(RegionInfoBuilder.FIRST_META_REGIONINFO.isMetaRegion());
}
@Test
public void testComparator() {
final TableName tableName = name.getTableName();
byte[] empty = new byte[0];
RegionInfo older = RegionInfoBuilder.newBuilder(tableName).setStartKey(empty).setEndKey(empty)
.setSplit(false).setRegionId(0L).build();
RegionInfo newer = RegionInfoBuilder.newBuilder(tableName).setStartKey(empty).setEndKey(empty)
.setSplit(false).setRegionId(1L).build();
assertTrue(RegionInfo.COMPARATOR.compare(older, newer) < 0);
assertTrue(RegionInfo.COMPARATOR.compare(newer, older) > 0);
assertTrue(RegionInfo.COMPARATOR.compare(older, older) == 0);
assertTrue(RegionInfo.COMPARATOR.compare(newer, newer) == 0);
}
@Test
public void testRegionNameForRegionReplicas() throws Exception {
final TableName tn = name.getTableName();
String startKey = "startkey";
final byte[] sk = Bytes.toBytes(startKey);
String id = "id";
// assert with only the region name without encoding
// primary, replicaId = 0
byte[] name = RegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 0, false);
String nameStr = Bytes.toString(name);
assertEquals(tn + "," + startKey + "," + id, nameStr);
// replicaId = 1
name = RegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 1, false);
nameStr = Bytes.toString(name);
assertEquals(
tn + "," + startKey + "," + id + "_" + String.format(RegionInfo.REPLICA_ID_FORMAT, 1),
nameStr);
// replicaId = max
name = RegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 0xFFFF, false);
nameStr = Bytes.toString(name);
assertEquals(
tn + "," + startKey + "," + id + "_" + String.format(RegionInfo.REPLICA_ID_FORMAT, 0xFFFF),
nameStr);
}
@Test
public void testParseName() throws IOException {
final TableName tableName = name.getTableName();
byte[] startKey = Bytes.toBytes("startKey");
long regionId = EnvironmentEdgeManager.currentTime();
int replicaId = 42;
// test without replicaId
byte[] regionName = RegionInfo.createRegionName(tableName, startKey, regionId, false);
byte[][] fields = RegionInfo.parseRegionName(regionName);
assertArrayEquals(Bytes.toString(fields[0]), tableName.getName(), fields[0]);
assertArrayEquals(Bytes.toString(fields[1]), startKey, fields[1]);
assertArrayEquals(Bytes.toString(fields[2]), Bytes.toBytes(Long.toString(regionId)), fields[2]);
assertEquals(3, fields.length);
// test with replicaId
regionName = RegionInfo.createRegionName(tableName, startKey, regionId, replicaId, false);
fields = RegionInfo.parseRegionName(regionName);
assertArrayEquals(Bytes.toString(fields[0]), tableName.getName(), fields[0]);
assertArrayEquals(Bytes.toString(fields[1]), startKey, fields[1]);
assertArrayEquals(Bytes.toString(fields[2]), Bytes.toBytes(Long.toString(regionId)), fields[2]);
assertArrayEquals(Bytes.toString(fields[3]),
Bytes.toBytes(String.format(RegionInfo.REPLICA_ID_FORMAT, replicaId)), fields[3]);
}
@Test
public void testConvert() {
final TableName tableName =
TableName.valueOf("ns1:" + name.getTableName().getQualifierAsString());
byte[] startKey = Bytes.toBytes("startKey");
byte[] endKey = Bytes.toBytes("endKey");
boolean split = false;
long regionId = EnvironmentEdgeManager.currentTime();
int replicaId = 42;
RegionInfo ri = RegionInfoBuilder.newBuilder(tableName).setStartKey(startKey).setEndKey(endKey)
.setSplit(split).setRegionId(regionId).setReplicaId(replicaId).build();
// convert two times, compare
RegionInfo convertedRi = ProtobufUtil.toRegionInfo(ProtobufUtil.toRegionInfo(ri));
assertEquals(ri, convertedRi);
// test convert RegionInfo without replicaId
HBaseProtos.RegionInfo info = HBaseProtos.RegionInfo.newBuilder()
.setTableName(HBaseProtos.TableName.newBuilder()
.setQualifier(UnsafeByteOperations.unsafeWrap(tableName.getQualifier()))
.setNamespace(UnsafeByteOperations.unsafeWrap(tableName.getNamespace())).build())
.setStartKey(UnsafeByteOperations.unsafeWrap(startKey))
.setEndKey(UnsafeByteOperations.unsafeWrap(endKey)).setSplit(split).setRegionId(regionId)
.build();
convertedRi = ProtobufUtil.toRegionInfo(info);
RegionInfo expectedRi = RegionInfoBuilder.newBuilder(tableName).setStartKey(startKey)
.setEndKey(endKey).setSplit(split).setRegionId(regionId).setReplicaId(0).build();
assertEquals(expectedRi, convertedRi);
}
private void assertRegionNameNotEquals(RegionInfo expected, RegionInfo actual) {
assertNotEquals(expected.getRegionNameAsString(), actual.getRegionNameAsString());
assertNotEquals(expected.getEncodedName(), actual.getEncodedName());
}
private void assertRegionNameEquals(RegionInfo expected, RegionInfo actual) {
assertEquals(expected.getRegionNameAsString(), actual.getRegionNameAsString());
assertEquals(expected.getEncodedName(), actual.getEncodedName());
}
@Test
public void testNewBuilderWithRegionInfo() {
RegionInfo ri = RegionInfoBuilder.newBuilder(name.getTableName()).build();
assertEquals(ri, RegionInfoBuilder.newBuilder(ri).build());
// make sure that the region name and encoded name are changed, see HBASE-24500 for more
// details.
assertRegionNameNotEquals(ri,
RegionInfoBuilder.newBuilder(ri).setStartKey(new byte[1]).build());
assertRegionNameNotEquals(ri,
RegionInfoBuilder.newBuilder(ri).setRegionId(ri.getRegionId() + 1).build());
assertRegionNameNotEquals(ri, RegionInfoBuilder.newBuilder(ri).setReplicaId(1).build());
// these fields are not in region name
assertRegionNameEquals(ri, RegionInfoBuilder.newBuilder(ri).setEndKey(new byte[1]).build());
assertRegionNameEquals(ri, RegionInfoBuilder.newBuilder(ri).setSplit(true).build());
assertRegionNameEquals(ri, RegionInfoBuilder.newBuilder(ri).setOffline(true).build());
}
}