| /** |
| * |
| * 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.regionserver; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.io.IOException; |
| |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.fs.FileStatus; |
| import org.apache.hadoop.fs.Path; |
| import org.apache.hadoop.hbase.HBaseTestingUtility; |
| import org.apache.hadoop.hbase.HRegionInfo; |
| import org.apache.hadoop.hbase.HTableDescriptor; |
| import org.apache.hadoop.hbase.testclassification.RegionServerTests; |
| import org.apache.hadoop.hbase.testclassification.SmallTests; |
| import org.apache.hadoop.hbase.TableName; |
| import org.apache.hadoop.hbase.exceptions.DeserializationException; |
| import org.apache.hadoop.hbase.fs.RegionStorage; |
| import org.apache.hadoop.hbase.fs.legacy.LegacyLayout; |
| import org.apache.hadoop.hbase.master.RegionState; |
| import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos; |
| import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionInfo; |
| import org.apache.hadoop.hbase.util.Bytes; |
| import org.apache.hadoop.hbase.util.FSTableDescriptors; |
| import org.apache.hadoop.hbase.util.MD5Hash; |
| import org.junit.Assert; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| |
| import com.google.protobuf.ByteString; |
| |
| @Category({RegionServerTests.class, SmallTests.class}) |
| public class TestHRegionInfo { |
| @Test |
| public void testPb() throws DeserializationException { |
| HRegionInfo hri = HRegionInfo.FIRST_META_REGIONINFO; |
| byte [] bytes = hri.toByteArray(); |
| HRegionInfo pbhri = HRegionInfo.parseFrom(bytes); |
| assertTrue(hri.equals(pbhri)); |
| } |
| |
| // @Test |
| // public void testReadAndWriteHRegionInfoFile() throws IOException, InterruptedException { |
| // HBaseTestingUtility htu = new HBaseTestingUtility(); |
| // HRegionInfo hri = HRegionInfo.FIRST_META_REGIONINFO; |
| // Path basedir = htu.getDataTestDir(); |
| // // Create a region. That'll write the .regioninfo file. |
| // FSTableDescriptors fsTableDescriptors = new FSTableDescriptors(htu.getConfiguration()); |
| // HRegion r = HBaseTestingUtility.createRegionAndWAL(hri, basedir, htu.getConfiguration(), |
| // fsTableDescriptors.get(TableName.META_TABLE_NAME)); |
| // // Get modtime on the file. |
| // long modtime = getModTime(r); |
| // HBaseTestingUtility.closeRegionAndWAL(r); |
| // Thread.sleep(1001); |
| // r = HRegion.openHRegion(basedir, hri, fsTableDescriptors.get(TableName.META_TABLE_NAME), |
| // null, htu.getConfiguration()); |
| // // Ensure the file is not written for a second time. |
| // long modtime2 = getModTime(r); |
| // assertEquals(modtime, modtime2); |
| // // Now load the file. |
| // HRegionInfo deserializedHri = RegionStorage.open(r.getRegionStorage().getConfiguration(), |
| // r.getRegionStorage.getRegionContainer(), false).getRegionInfo(); |
| // assertTrue(hri.equals(deserializedHri)); |
| // HBaseTestingUtility.closeRegionAndWAL(r); |
| // } |
| // |
| // long getModTime(final HRegion r) throws IOException { |
| // FileStatus[] statuses = r.getRegionStorage().getFileSystem().listStatus( |
| // LegacyLayout.getRegionInfoFile(r.getRegionStorage().getRegionDir())); |
| // assertTrue(statuses != null && statuses.length == 1); |
| // return statuses[0].getModificationTime(); |
| // } |
| |
| @Test |
| public void testCreateHRegionInfoName() throws Exception { |
| String tableName = "tablename"; |
| final TableName tn = TableName.valueOf(tableName); |
| String startKey = "startkey"; |
| final byte[] sk = Bytes.toBytes(startKey); |
| String id = "id"; |
| |
| // old format region name |
| byte [] name = HRegionInfo.createRegionName(tn, sk, id, false); |
| String nameStr = Bytes.toString(name); |
| assertEquals(tableName + "," + startKey + "," + id, nameStr); |
| |
| |
| // new format region name. |
| String md5HashInHex = MD5Hash.getMD5AsHex(name); |
| assertEquals(HRegionInfo.MD5_HEX_LENGTH, md5HashInHex.length()); |
| name = HRegionInfo.createRegionName(tn, sk, id, true); |
| nameStr = Bytes.toString(name); |
| assertEquals(tableName + "," + startKey + "," |
| + id + "." + md5HashInHex + ".", |
| nameStr); |
| } |
| |
| @Test |
| public void testContainsRange() { |
| HTableDescriptor tableDesc = new HTableDescriptor(TableName.valueOf("testtable")); |
| HRegionInfo hri = new HRegionInfo( |
| tableDesc.getTableName(), Bytes.toBytes("a"), Bytes.toBytes("g")); |
| // Single row range at start of region |
| assertTrue(hri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("a"))); |
| // Fully contained range |
| assertTrue(hri.containsRange(Bytes.toBytes("b"), Bytes.toBytes("c"))); |
| // Range overlapping start of region |
| assertTrue(hri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("c"))); |
| // Fully contained single-row range |
| assertTrue(hri.containsRange(Bytes.toBytes("c"), Bytes.toBytes("c"))); |
| // Range that overlaps end key and hence doesn't fit |
| assertFalse(hri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("g"))); |
| // Single row range on end key |
| assertFalse(hri.containsRange(Bytes.toBytes("g"), Bytes.toBytes("g"))); |
| // Single row range entirely outside |
| assertFalse(hri.containsRange(Bytes.toBytes("z"), Bytes.toBytes("z"))); |
| |
| // Degenerate range |
| try { |
| hri.containsRange(Bytes.toBytes("z"), Bytes.toBytes("a")); |
| fail("Invalid range did not throw IAE"); |
| } catch (IllegalArgumentException iae) { |
| } |
| } |
| |
| @Test |
| public void testLastRegionCompare() { |
| HTableDescriptor tableDesc = new HTableDescriptor(TableName.valueOf("testtable")); |
| HRegionInfo hrip = new HRegionInfo( |
| tableDesc.getTableName(), Bytes.toBytes("a"), new byte[0]); |
| HRegionInfo hric = new HRegionInfo( |
| tableDesc.getTableName(), Bytes.toBytes("a"), Bytes.toBytes("b")); |
| assertTrue(hrip.compareTo(hric) > 0); |
| } |
| |
| @Test |
| public void testMetaTables() { |
| assertTrue(HRegionInfo.FIRST_META_REGIONINFO.isMetaTable()); |
| } |
| |
| @Test |
| public void testComparator() { |
| TableName tablename = TableName.valueOf("comparatorTablename"); |
| byte[] empty = new byte[0]; |
| HRegionInfo older = new HRegionInfo(tablename, empty, empty, false, 0L); |
| HRegionInfo newer = new HRegionInfo(tablename, empty, empty, false, 1L); |
| assertTrue(older.compareTo(newer) < 0); |
| assertTrue(newer.compareTo(older) > 0); |
| assertTrue(older.compareTo(older) == 0); |
| assertTrue(newer.compareTo(newer) == 0); |
| } |
| |
| @Test |
| public void testRegionNameForRegionReplicas() throws Exception { |
| String tableName = "tablename"; |
| final TableName tn = TableName.valueOf(tableName); |
| 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 = HRegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 0, false); |
| String nameStr = Bytes.toString(name); |
| assertEquals(tableName + "," + startKey + "," + id, nameStr); |
| |
| // replicaId = 1 |
| name = HRegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 1, false); |
| nameStr = Bytes.toString(name); |
| assertEquals(tableName + "," + startKey + "," + id + "_" + |
| String.format(HRegionInfo.REPLICA_ID_FORMAT, 1), nameStr); |
| |
| // replicaId = max |
| name = HRegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 0xFFFF, false); |
| nameStr = Bytes.toString(name); |
| assertEquals(tableName + "," + startKey + "," + id + "_" + |
| String.format(HRegionInfo.REPLICA_ID_FORMAT, 0xFFFF), nameStr); |
| } |
| |
| @Test |
| public void testParseName() throws IOException { |
| TableName tableName = TableName.valueOf("testParseName"); |
| byte[] startKey = Bytes.toBytes("startKey"); |
| long regionId = System.currentTimeMillis(); |
| int replicaId = 42; |
| |
| // test without replicaId |
| byte[] regionName = HRegionInfo.createRegionName(tableName, startKey, regionId, false); |
| |
| byte[][] fields = HRegionInfo.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 = HRegionInfo.createRegionName(tableName, startKey, regionId, |
| replicaId, false); |
| |
| fields = HRegionInfo.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(HRegionInfo.REPLICA_ID_FORMAT, replicaId)), fields[3]); |
| } |
| |
| @Test |
| public void testConvert() { |
| TableName tableName = TableName.valueOf("ns1:table1"); |
| byte[] startKey = Bytes.toBytes("startKey"); |
| byte[] endKey = Bytes.toBytes("endKey"); |
| boolean split = false; |
| long regionId = System.currentTimeMillis(); |
| int replicaId = 42; |
| |
| |
| HRegionInfo hri = new HRegionInfo(tableName, startKey, endKey, split, |
| regionId, replicaId); |
| |
| // convert two times, compare |
| HRegionInfo convertedHri = HRegionInfo.convert(HRegionInfo.convert(hri)); |
| |
| assertEquals(hri, convertedHri); |
| |
| // test convert RegionInfo without replicaId |
| RegionInfo info = RegionInfo.newBuilder() |
| .setTableName(HBaseProtos.TableName.newBuilder() |
| .setQualifier(ByteString.copyFrom(tableName.getQualifier())) |
| .setNamespace(ByteString.copyFrom(tableName.getNamespace())) |
| .build()) |
| .setStartKey(ByteString.copyFrom(startKey)) |
| .setEndKey(ByteString.copyFrom(endKey)) |
| .setSplit(split) |
| .setRegionId(regionId) |
| .build(); |
| |
| convertedHri = HRegionInfo.convert(info); |
| HRegionInfo expectedHri = new HRegionInfo(tableName, startKey, endKey, split, |
| regionId, 0); // expecting default replicaId |
| |
| assertEquals(expectedHri, convertedHri); |
| } |
| @Test |
| public void testRegionDetailsForDisplay() throws IOException { |
| byte[] startKey = new byte[] {0x01, 0x01, 0x02, 0x03}; |
| byte[] endKey = new byte[] {0x01, 0x01, 0x02, 0x04}; |
| Configuration conf = new Configuration(); |
| conf.setBoolean("hbase.display.keys", false); |
| HRegionInfo h = new HRegionInfo(TableName.valueOf("foo"), startKey, endKey); |
| checkEquality(h, conf); |
| // check HRIs with non-default replicaId |
| h = new HRegionInfo(TableName.valueOf("foo"), startKey, endKey, false, |
| System.currentTimeMillis(), 1); |
| checkEquality(h, conf); |
| Assert.assertArrayEquals(HRegionInfo.HIDDEN_END_KEY, |
| HRegionInfo.getEndKeyForDisplay(h, conf)); |
| Assert.assertArrayEquals(HRegionInfo.HIDDEN_START_KEY, |
| HRegionInfo.getStartKeyForDisplay(h, conf)); |
| |
| RegionState state = new RegionState(h, RegionState.State.OPEN); |
| String descriptiveNameForDisplay = |
| HRegionInfo.getDescriptiveNameFromRegionStateForDisplay(state, conf); |
| checkDescriptiveNameEquality(descriptiveNameForDisplay,state.toDescriptiveString(), startKey); |
| |
| conf.setBoolean("hbase.display.keys", true); |
| Assert.assertArrayEquals(endKey, HRegionInfo.getEndKeyForDisplay(h, conf)); |
| Assert.assertArrayEquals(startKey, HRegionInfo.getStartKeyForDisplay(h, conf)); |
| Assert.assertEquals(state.toDescriptiveString(), |
| HRegionInfo.getDescriptiveNameFromRegionStateForDisplay(state, conf)); |
| } |
| |
| private void checkDescriptiveNameEquality(String descriptiveNameForDisplay, String origDesc, |
| byte[] startKey) { |
| // except for the "hidden-start-key" substring everything else should exactly match |
| String firstPart = descriptiveNameForDisplay.substring(0, |
| descriptiveNameForDisplay.indexOf(new String(HRegionInfo.HIDDEN_START_KEY))); |
| String secondPart = descriptiveNameForDisplay.substring( |
| descriptiveNameForDisplay.indexOf(new String(HRegionInfo.HIDDEN_START_KEY)) + |
| HRegionInfo.HIDDEN_START_KEY.length); |
| String firstPartOrig = origDesc.substring(0, |
| origDesc.indexOf(Bytes.toStringBinary(startKey))); |
| String secondPartOrig = origDesc.substring( |
| origDesc.indexOf(Bytes.toStringBinary(startKey)) + |
| Bytes.toStringBinary(startKey).length()); |
| assert(firstPart.equals(firstPartOrig)); |
| assert(secondPart.equals(secondPartOrig)); |
| } |
| |
| private void checkEquality(HRegionInfo h, Configuration conf) throws IOException { |
| byte[] modifiedRegionName = HRegionInfo.getRegionNameForDisplay(h, conf); |
| byte[][] modifiedRegionNameParts = HRegionInfo.parseRegionName(modifiedRegionName); |
| byte[][] regionNameParts = HRegionInfo.parseRegionName(h.getRegionName()); |
| |
| //same number of parts |
| assert(modifiedRegionNameParts.length == regionNameParts.length); |
| |
| for (int i = 0; i < regionNameParts.length; i++) { |
| // all parts should match except for [1] where in the modified one, |
| // we should have "hidden_start_key" |
| if (i != 1) { |
| Assert.assertArrayEquals(regionNameParts[i], modifiedRegionNameParts[i]); |
| } else { |
| Assert.assertNotEquals(regionNameParts[i][0], modifiedRegionNameParts[i][0]); |
| Assert.assertArrayEquals(modifiedRegionNameParts[1], |
| HRegionInfo.getStartKeyForDisplay(h, conf)); |
| } |
| } |
| } |
| } |
| |