001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.regionserver; 019 020import static org.junit.Assert.assertArrayEquals; 021import static org.junit.Assert.assertEquals; 022import static org.junit.Assert.assertFalse; 023import static org.junit.Assert.assertNotEquals; 024import static org.junit.Assert.assertTrue; 025import static org.junit.Assert.fail; 026 027import java.io.IOException; 028import org.apache.hadoop.conf.Configuration; 029import org.apache.hadoop.fs.FileStatus; 030import org.apache.hadoop.fs.Path; 031import org.apache.hadoop.hbase.HBaseClassTestRule; 032import org.apache.hadoop.hbase.HBaseTestingUtility; 033import org.apache.hadoop.hbase.HRegionInfo; 034import org.apache.hadoop.hbase.HTableDescriptor; 035import org.apache.hadoop.hbase.TableName; 036import org.apache.hadoop.hbase.exceptions.DeserializationException; 037import org.apache.hadoop.hbase.master.RegionState; 038import org.apache.hadoop.hbase.testclassification.RegionServerTests; 039import org.apache.hadoop.hbase.testclassification.SmallTests; 040import org.apache.hadoop.hbase.util.Bytes; 041import org.apache.hadoop.hbase.util.FSTableDescriptors; 042import org.apache.hadoop.hbase.util.MD5Hash; 043import org.junit.Assert; 044import org.junit.ClassRule; 045import org.junit.Rule; 046import org.junit.Test; 047import org.junit.experimental.categories.Category; 048import org.junit.rules.TestName; 049 050import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations; 051 052import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; 053import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.RegionInfo; 054 055@Category({RegionServerTests.class, SmallTests.class}) 056public class TestHRegionInfo { 057 058 @ClassRule 059 public static final HBaseClassTestRule CLASS_RULE = 060 HBaseClassTestRule.forClass(TestHRegionInfo.class); 061 062 @Rule 063 public TestName name = new TestName(); 064 065 @Test 066 public void testPb() throws DeserializationException { 067 HRegionInfo hri = HRegionInfo.FIRST_META_REGIONINFO; 068 byte [] bytes = hri.toByteArray(); 069 HRegionInfo pbhri = HRegionInfo.parseFrom(bytes); 070 assertTrue(hri.equals(pbhri)); 071 } 072 073 @Test 074 public void testReadAndWriteHRegionInfoFile() throws IOException, InterruptedException { 075 HBaseTestingUtility htu = new HBaseTestingUtility(); 076 HRegionInfo hri = HRegionInfo.FIRST_META_REGIONINFO; 077 Path basedir = htu.getDataTestDir(); 078 // Create a region. That'll write the .regioninfo file. 079 FSTableDescriptors fsTableDescriptors = new FSTableDescriptors(htu.getConfiguration()); 080 HRegion r = HBaseTestingUtility.createRegionAndWAL(hri, basedir, htu.getConfiguration(), 081 fsTableDescriptors.get(TableName.META_TABLE_NAME)); 082 // Get modtime on the file. 083 long modtime = getModTime(r); 084 HBaseTestingUtility.closeRegionAndWAL(r); 085 Thread.sleep(1001); 086 r = HRegion.openHRegion(basedir, hri, fsTableDescriptors.get(TableName.META_TABLE_NAME), 087 null, htu.getConfiguration()); 088 // Ensure the file is not written for a second time. 089 long modtime2 = getModTime(r); 090 assertEquals(modtime, modtime2); 091 // Now load the file. 092 org.apache.hadoop.hbase.client.RegionInfo deserializedHri = HRegionFileSystem.loadRegionInfoFileContent( 093 r.getRegionFileSystem().getFileSystem(), r.getRegionFileSystem().getRegionDir()); 094 assertTrue(org.apache.hadoop.hbase.client.RegionInfo.COMPARATOR.compare(hri, deserializedHri) == 0); 095 HBaseTestingUtility.closeRegionAndWAL(r); 096 } 097 098 long getModTime(final HRegion r) throws IOException { 099 FileStatus[] statuses = r.getRegionFileSystem().getFileSystem().listStatus( 100 new Path(r.getRegionFileSystem().getRegionDir(), HRegionFileSystem.REGION_INFO_FILE)); 101 assertTrue(statuses != null && statuses.length == 1); 102 return statuses[0].getModificationTime(); 103 } 104 105 @Test 106 public void testCreateHRegionInfoName() throws Exception { 107 final String tableName = name.getMethodName(); 108 final TableName tn = TableName.valueOf(tableName); 109 String startKey = "startkey"; 110 final byte[] sk = Bytes.toBytes(startKey); 111 String id = "id"; 112 113 // old format region name 114 byte [] name = HRegionInfo.createRegionName(tn, sk, id, false); 115 String nameStr = Bytes.toString(name); 116 assertEquals(tableName + "," + startKey + "," + id, nameStr); 117 118 119 // new format region name. 120 String md5HashInHex = MD5Hash.getMD5AsHex(name); 121 assertEquals(HRegionInfo.MD5_HEX_LENGTH, md5HashInHex.length()); 122 name = HRegionInfo.createRegionName(tn, sk, id, true); 123 nameStr = Bytes.toString(name); 124 assertEquals(tableName + "," + startKey + "," 125 + id + "." + md5HashInHex + ".", 126 nameStr); 127 } 128 129 @Test 130 public void testContainsRange() { 131 HTableDescriptor tableDesc = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 132 HRegionInfo hri = new HRegionInfo( 133 tableDesc.getTableName(), Bytes.toBytes("a"), Bytes.toBytes("g")); 134 // Single row range at start of region 135 assertTrue(hri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("a"))); 136 // Fully contained range 137 assertTrue(hri.containsRange(Bytes.toBytes("b"), Bytes.toBytes("c"))); 138 // Range overlapping start of region 139 assertTrue(hri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("c"))); 140 // Fully contained single-row range 141 assertTrue(hri.containsRange(Bytes.toBytes("c"), Bytes.toBytes("c"))); 142 // Range that overlaps end key and hence doesn't fit 143 assertFalse(hri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("g"))); 144 // Single row range on end key 145 assertFalse(hri.containsRange(Bytes.toBytes("g"), Bytes.toBytes("g"))); 146 // Single row range entirely outside 147 assertFalse(hri.containsRange(Bytes.toBytes("z"), Bytes.toBytes("z"))); 148 149 // Degenerate range 150 try { 151 hri.containsRange(Bytes.toBytes("z"), Bytes.toBytes("a")); 152 fail("Invalid range did not throw IAE"); 153 } catch (IllegalArgumentException iae) { 154 } 155 } 156 157 @Test 158 public void testLastRegionCompare() { 159 HTableDescriptor tableDesc = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 160 HRegionInfo hrip = new HRegionInfo( 161 tableDesc.getTableName(), Bytes.toBytes("a"), new byte[0]); 162 HRegionInfo hric = new HRegionInfo( 163 tableDesc.getTableName(), Bytes.toBytes("a"), Bytes.toBytes("b")); 164 assertTrue(hrip.compareTo(hric) > 0); 165 } 166 167 @Test 168 public void testMetaTables() { 169 assertTrue(HRegionInfo.FIRST_META_REGIONINFO.isMetaRegion()); 170 } 171 172 @SuppressWarnings("SelfComparison") 173 @Test 174 public void testComparator() { 175 final TableName tableName = TableName.valueOf(name.getMethodName()); 176 byte[] empty = new byte[0]; 177 HRegionInfo older = new HRegionInfo(tableName, empty, empty, false, 0L); 178 HRegionInfo newer = new HRegionInfo(tableName, empty, empty, false, 1L); 179 assertTrue(older.compareTo(newer) < 0); 180 assertTrue(newer.compareTo(older) > 0); 181 assertEquals(0, older.compareTo(older)); 182 assertEquals(0, newer.compareTo(newer)); 183 184 HRegionInfo a = new HRegionInfo(TableName.valueOf("a"), null, null); 185 HRegionInfo b = new HRegionInfo(TableName.valueOf("b"), null, null); 186 assertNotEquals(0, a.compareTo(b)); 187 HTableDescriptor t = new HTableDescriptor(TableName.valueOf("t")); 188 byte [] midway = Bytes.toBytes("midway"); 189 a = new HRegionInfo(t.getTableName(), null, midway); 190 b = new HRegionInfo(t.getTableName(), midway, null); 191 assertTrue(a.compareTo(b) < 0); 192 assertTrue(b.compareTo(a) > 0); 193 assertEquals(a, a); 194 assertEquals(0, a.compareTo(a)); 195 a = new HRegionInfo(t.getTableName(), Bytes.toBytes("a"), Bytes.toBytes("d")); 196 b = new HRegionInfo(t.getTableName(), Bytes.toBytes("e"), Bytes.toBytes("g")); 197 assertTrue(a.compareTo(b) < 0); 198 a = new HRegionInfo(t.getTableName(), Bytes.toBytes("aaaa"), Bytes.toBytes("dddd")); 199 b = new HRegionInfo(t.getTableName(), Bytes.toBytes("e"), Bytes.toBytes("g")); 200 assertTrue(a.compareTo(b) < 0); 201 a = new HRegionInfo(t.getTableName(), Bytes.toBytes("aaaa"), Bytes.toBytes("dddd")); 202 b = new HRegionInfo(t.getTableName(), Bytes.toBytes("aaaa"), Bytes.toBytes("eeee")); 203 assertTrue(a.compareTo(b) < 0); 204 205 } 206 207 @Test 208 public void testRegionNameForRegionReplicas() throws Exception { 209 String tableName = name.getMethodName(); 210 final TableName tn = TableName.valueOf(tableName); 211 String startKey = "startkey"; 212 final byte[] sk = Bytes.toBytes(startKey); 213 String id = "id"; 214 215 // assert with only the region name without encoding 216 217 // primary, replicaId = 0 218 byte [] name = HRegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 0, false); 219 String nameStr = Bytes.toString(name); 220 assertEquals(tableName + "," + startKey + "," + id, nameStr); 221 222 // replicaId = 1 223 name = HRegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 1, false); 224 nameStr = Bytes.toString(name); 225 assertEquals(tableName + "," + startKey + "," + id + "_" + 226 String.format(HRegionInfo.REPLICA_ID_FORMAT, 1), nameStr); 227 228 // replicaId = max 229 name = HRegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 0xFFFF, false); 230 nameStr = Bytes.toString(name); 231 assertEquals(tableName + "," + startKey + "," + id + "_" + 232 String.format(HRegionInfo.REPLICA_ID_FORMAT, 0xFFFF), nameStr); 233 } 234 235 @Test 236 public void testParseName() throws IOException { 237 final TableName tableName = TableName.valueOf(name.getMethodName()); 238 byte[] startKey = Bytes.toBytes("startKey"); 239 long regionId = System.currentTimeMillis(); 240 int replicaId = 42; 241 242 // test without replicaId 243 byte[] regionName = HRegionInfo.createRegionName(tableName, startKey, regionId, false); 244 245 byte[][] fields = HRegionInfo.parseRegionName(regionName); 246 assertArrayEquals(Bytes.toString(fields[0]),tableName.getName(), fields[0]); 247 assertArrayEquals(Bytes.toString(fields[1]),startKey, fields[1]); 248 assertArrayEquals(Bytes.toString(fields[2]), Bytes.toBytes(Long.toString(regionId)),fields[2]); 249 assertEquals(3, fields.length); 250 251 // test with replicaId 252 regionName = HRegionInfo.createRegionName(tableName, startKey, regionId, 253 replicaId, false); 254 255 fields = HRegionInfo.parseRegionName(regionName); 256 assertArrayEquals(Bytes.toString(fields[0]),tableName.getName(), fields[0]); 257 assertArrayEquals(Bytes.toString(fields[1]),startKey, fields[1]); 258 assertArrayEquals(Bytes.toString(fields[2]), Bytes.toBytes(Long.toString(regionId)),fields[2]); 259 assertArrayEquals(Bytes.toString(fields[3]), Bytes.toBytes( 260 String.format(HRegionInfo.REPLICA_ID_FORMAT, replicaId)), fields[3]); 261 } 262 263 @Test 264 public void testConvert() { 265 final TableName tableName = TableName.valueOf("ns1:" + name.getMethodName()); 266 byte[] startKey = Bytes.toBytes("startKey"); 267 byte[] endKey = Bytes.toBytes("endKey"); 268 boolean split = false; 269 long regionId = System.currentTimeMillis(); 270 int replicaId = 42; 271 272 273 HRegionInfo hri = new HRegionInfo(tableName, startKey, endKey, split, 274 regionId, replicaId); 275 276 // convert two times, compare 277 HRegionInfo convertedHri = HRegionInfo.convert(HRegionInfo.convert(hri)); 278 279 assertEquals(hri, convertedHri); 280 281 // test convert RegionInfo without replicaId 282 RegionInfo info = RegionInfo.newBuilder() 283 .setTableName(HBaseProtos.TableName.newBuilder() 284 .setQualifier(UnsafeByteOperations.unsafeWrap(tableName.getQualifier())) 285 .setNamespace(UnsafeByteOperations.unsafeWrap(tableName.getNamespace())) 286 .build()) 287 .setStartKey(UnsafeByteOperations.unsafeWrap(startKey)) 288 .setEndKey(UnsafeByteOperations.unsafeWrap(endKey)) 289 .setSplit(split) 290 .setRegionId(regionId) 291 .build(); 292 293 convertedHri = HRegionInfo.convert(info); 294 HRegionInfo expectedHri = new HRegionInfo(tableName, startKey, endKey, split, 295 regionId, 0); // expecting default replicaId 296 297 assertEquals(expectedHri, convertedHri); 298 } 299} 300