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; 019import static org.junit.Assert.assertArrayEquals; 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertNotEquals; 023import static org.junit.Assert.assertTrue; 024import static org.junit.Assert.fail; 025import java.io.IOException; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.fs.FileStatus; 028import org.apache.hadoop.fs.Path; 029import org.apache.hadoop.hbase.HBaseClassTestRule; 030import org.apache.hadoop.hbase.HBaseTestingUtility; 031import org.apache.hadoop.hbase.HRegionInfo; 032import org.apache.hadoop.hbase.HTableDescriptor; 033import org.apache.hadoop.hbase.TableName; 034import org.apache.hadoop.hbase.client.RegionInfo; 035import org.apache.hadoop.hbase.client.RegionInfoBuilder; 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; 049import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations; 050import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; 051 052@Category({RegionServerTests.class, SmallTests.class}) 053public class TestHRegionInfo { 054 055 @ClassRule 056 public static final HBaseClassTestRule CLASS_RULE = 057 HBaseClassTestRule.forClass(TestHRegionInfo.class); 058 059 @Rule 060 public TestName name = new TestName(); 061 062 @Test 063 public void testIsStart() { 064 assertTrue(RegionInfoBuilder.FIRST_META_REGIONINFO.isFirst()); 065 org.apache.hadoop.hbase.client.RegionInfo ri = 066 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 067 setStartKey(Bytes.toBytes("not_start")).build(); 068 assertFalse(ri.isFirst()); 069 } 070 071 @Test 072 public void testIsEnd() { 073 assertTrue(RegionInfoBuilder.FIRST_META_REGIONINFO.isFirst()); 074 org.apache.hadoop.hbase.client.RegionInfo ri = 075 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 076 setEndKey(Bytes.toBytes("not_end")).build(); 077 assertFalse(ri.isLast()); 078 } 079 080 @Test 081 public void testIsNext() { 082 byte [] bytes = Bytes.toBytes("row"); 083 org.apache.hadoop.hbase.client.RegionInfo ri = 084 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 085 setEndKey(bytes).build(); 086 org.apache.hadoop.hbase.client.RegionInfo ri2 = 087 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 088 setStartKey(bytes).build(); 089 assertFalse(ri.isNext(RegionInfoBuilder.FIRST_META_REGIONINFO)); 090 assertTrue(ri.isNext(ri2)); 091 } 092 093 @Test 094 public void testIsOverlap() { 095 byte [] a = Bytes.toBytes("a"); 096 byte [] b = Bytes.toBytes("b"); 097 byte [] c = Bytes.toBytes("c"); 098 byte [] d = Bytes.toBytes("d"); 099 org.apache.hadoop.hbase.client.RegionInfo all = 100 RegionInfoBuilder.FIRST_META_REGIONINFO; 101 org.apache.hadoop.hbase.client.RegionInfo ari = 102 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 103 setEndKey(a).build(); 104 org.apache.hadoop.hbase.client.RegionInfo abri = 105 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 106 setStartKey(a).setEndKey(b).build(); 107 org.apache.hadoop.hbase.client.RegionInfo adri = 108 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 109 setStartKey(a).setEndKey(d).build(); 110 org.apache.hadoop.hbase.client.RegionInfo cdri = 111 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 112 setStartKey(c).setEndKey(d).build(); 113 org.apache.hadoop.hbase.client.RegionInfo dri = 114 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 115 setStartKey(d).build(); 116 assertTrue(all.isOverlap(all)); 117 assertTrue(all.isOverlap(abri)); 118 assertFalse(abri.isOverlap(cdri)); 119 assertTrue(all.isOverlap(ari)); 120 assertFalse(ari.isOverlap(abri)); 121 assertFalse(ari.isOverlap(abri)); 122 assertTrue(ari.isOverlap(all)); 123 assertTrue(dri.isOverlap(all)); 124 assertTrue(abri.isOverlap(adri)); 125 assertFalse(dri.isOverlap(ari)); 126 assertTrue(abri.isOverlap(adri)); 127 assertTrue(adri.isOverlap(abri)); 128 } 129 130 /** 131 * Tests {@link RegionInfo#isOverlap(RegionInfo[])} 132 */ 133 @Test 134 public void testIsOverlaps() { 135 byte[] a = Bytes.toBytes("a"); 136 byte[] b = Bytes.toBytes("b"); 137 byte[] c = Bytes.toBytes("c"); 138 byte[] d = Bytes.toBytes("d"); 139 byte[] e = Bytes.toBytes("e"); 140 byte[] f = Bytes.toBytes("f"); 141 org.apache.hadoop.hbase.client.RegionInfo ari = 142 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 143 setEndKey(a).build(); 144 org.apache.hadoop.hbase.client.RegionInfo abri = 145 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 146 setStartKey(a).setEndKey(b).build(); 147 org.apache.hadoop.hbase.client.RegionInfo eri = 148 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 149 setEndKey(e).build(); 150 org.apache.hadoop.hbase.client.RegionInfo cdri = 151 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 152 setStartKey(c).setEndKey(d).build(); 153 org.apache.hadoop.hbase.client.RegionInfo efri = 154 org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME). 155 setStartKey(e).setEndKey(f).build(); 156 } 157 158 @Test 159 public void testPb() throws DeserializationException { 160 HRegionInfo hri = HRegionInfo.FIRST_META_REGIONINFO; 161 byte [] bytes = hri.toByteArray(); 162 HRegionInfo pbhri = HRegionInfo.parseFrom(bytes); 163 assertTrue(hri.equals(pbhri)); 164 } 165 166 @Test 167 public void testReadAndWriteHRegionInfoFile() throws IOException, InterruptedException { 168 HBaseTestingUtility htu = new HBaseTestingUtility(); 169 HRegionInfo hri = HRegionInfo.FIRST_META_REGIONINFO; 170 Path basedir = htu.getDataTestDir(); 171 // Create a region. That'll write the .regioninfo file. 172 FSTableDescriptors fsTableDescriptors = new FSTableDescriptors(htu.getConfiguration()); 173 FSTableDescriptors.tryUpdateMetaTableDescriptor(htu.getConfiguration()); 174 HRegion r = HBaseTestingUtility.createRegionAndWAL(hri, basedir, htu.getConfiguration(), 175 fsTableDescriptors.get(TableName.META_TABLE_NAME)); 176 // Get modtime on the file. 177 long modtime = getModTime(r); 178 HBaseTestingUtility.closeRegionAndWAL(r); 179 Thread.sleep(1001); 180 r = HRegion.openHRegion(basedir, hri, fsTableDescriptors.get(TableName.META_TABLE_NAME), 181 null, htu.getConfiguration()); 182 // Ensure the file is not written for a second time. 183 long modtime2 = getModTime(r); 184 assertEquals(modtime, modtime2); 185 // Now load the file. 186 org.apache.hadoop.hbase.client.RegionInfo deserializedHri = 187 HRegionFileSystem.loadRegionInfoFileContent( 188 r.getRegionFileSystem().getFileSystem(), r.getRegionFileSystem().getRegionDir()); 189 assertEquals(0, 190 org.apache.hadoop.hbase.client.RegionInfo.COMPARATOR.compare(hri, deserializedHri)); 191 HBaseTestingUtility.closeRegionAndWAL(r); 192 } 193 194 long getModTime(final HRegion r) throws IOException { 195 FileStatus[] statuses = r.getRegionFileSystem().getFileSystem().listStatus( 196 new Path(r.getRegionFileSystem().getRegionDir(), HRegionFileSystem.REGION_INFO_FILE)); 197 assertTrue(statuses != null && statuses.length == 1); 198 return statuses[0].getModificationTime(); 199 } 200 201 @Test 202 public void testCreateHRegionInfoName() throws Exception { 203 final String tableName = name.getMethodName(); 204 final TableName tn = TableName.valueOf(tableName); 205 String startKey = "startkey"; 206 final byte[] sk = Bytes.toBytes(startKey); 207 String id = "id"; 208 209 // old format region name 210 byte [] name = HRegionInfo.createRegionName(tn, sk, id, false); 211 String nameStr = Bytes.toString(name); 212 assertEquals(tableName + "," + startKey + "," + id, nameStr); 213 214 215 // new format region name. 216 String md5HashInHex = MD5Hash.getMD5AsHex(name); 217 assertEquals(HRegionInfo.MD5_HEX_LENGTH, md5HashInHex.length()); 218 name = HRegionInfo.createRegionName(tn, sk, id, true); 219 nameStr = Bytes.toString(name); 220 assertEquals(tableName + "," + startKey + "," 221 + id + "." + md5HashInHex + ".", 222 nameStr); 223 } 224 225 @Test 226 public void testContainsRange() { 227 HTableDescriptor tableDesc = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 228 HRegionInfo hri = new HRegionInfo( 229 tableDesc.getTableName(), Bytes.toBytes("a"), Bytes.toBytes("g")); 230 // Single row range at start of region 231 assertTrue(hri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("a"))); 232 // Fully contained range 233 assertTrue(hri.containsRange(Bytes.toBytes("b"), Bytes.toBytes("c"))); 234 // Range overlapping start of region 235 assertTrue(hri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("c"))); 236 // Fully contained single-row range 237 assertTrue(hri.containsRange(Bytes.toBytes("c"), Bytes.toBytes("c"))); 238 // Range that overlaps end key and hence doesn't fit 239 assertFalse(hri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("g"))); 240 // Single row range on end key 241 assertFalse(hri.containsRange(Bytes.toBytes("g"), Bytes.toBytes("g"))); 242 // Single row range entirely outside 243 assertFalse(hri.containsRange(Bytes.toBytes("z"), Bytes.toBytes("z"))); 244 245 // Degenerate range 246 try { 247 hri.containsRange(Bytes.toBytes("z"), Bytes.toBytes("a")); 248 fail("Invalid range did not throw IAE"); 249 } catch (IllegalArgumentException iae) { 250 } 251 } 252 253 @Test 254 public void testLastRegionCompare() { 255 HTableDescriptor tableDesc = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 256 HRegionInfo hrip = new HRegionInfo( 257 tableDesc.getTableName(), Bytes.toBytes("a"), new byte[0]); 258 HRegionInfo hric = new HRegionInfo( 259 tableDesc.getTableName(), Bytes.toBytes("a"), Bytes.toBytes("b")); 260 assertTrue(hrip.compareTo(hric) > 0); 261 } 262 263 @Test 264 public void testMetaTables() { 265 assertTrue(HRegionInfo.FIRST_META_REGIONINFO.isMetaRegion()); 266 } 267 268 @SuppressWarnings("SelfComparison") 269 @Test 270 public void testComparator() { 271 final TableName tableName = TableName.valueOf(name.getMethodName()); 272 byte[] empty = new byte[0]; 273 HRegionInfo older = new HRegionInfo(tableName, empty, empty, false, 0L); 274 HRegionInfo newer = new HRegionInfo(tableName, empty, empty, false, 1L); 275 assertTrue(older.compareTo(newer) < 0); 276 assertTrue(newer.compareTo(older) > 0); 277 assertEquals(0, older.compareTo(older)); 278 assertEquals(0, newer.compareTo(newer)); 279 280 HRegionInfo a = new HRegionInfo(TableName.valueOf("a"), null, null); 281 HRegionInfo b = new HRegionInfo(TableName.valueOf("b"), null, null); 282 assertNotEquals(0, a.compareTo(b)); 283 HTableDescriptor t = new HTableDescriptor(TableName.valueOf("t")); 284 byte [] midway = Bytes.toBytes("midway"); 285 a = new HRegionInfo(t.getTableName(), null, midway); 286 b = new HRegionInfo(t.getTableName(), midway, null); 287 assertTrue(a.compareTo(b) < 0); 288 assertTrue(b.compareTo(a) > 0); 289 assertEquals(a, a); 290 assertEquals(0, a.compareTo(a)); 291 a = new HRegionInfo(t.getTableName(), Bytes.toBytes("a"), Bytes.toBytes("d")); 292 b = new HRegionInfo(t.getTableName(), Bytes.toBytes("e"), Bytes.toBytes("g")); 293 assertTrue(a.compareTo(b) < 0); 294 a = new HRegionInfo(t.getTableName(), Bytes.toBytes("aaaa"), Bytes.toBytes("dddd")); 295 b = new HRegionInfo(t.getTableName(), Bytes.toBytes("e"), Bytes.toBytes("g")); 296 assertTrue(a.compareTo(b) < 0); 297 a = new HRegionInfo(t.getTableName(), Bytes.toBytes("aaaa"), Bytes.toBytes("dddd")); 298 b = new HRegionInfo(t.getTableName(), Bytes.toBytes("aaaa"), Bytes.toBytes("eeee")); 299 assertTrue(a.compareTo(b) < 0); 300 301 } 302 303 @Test 304 public void testRegionNameForRegionReplicas() throws Exception { 305 String tableName = name.getMethodName(); 306 final TableName tn = TableName.valueOf(tableName); 307 String startKey = "startkey"; 308 final byte[] sk = Bytes.toBytes(startKey); 309 String id = "id"; 310 311 // assert with only the region name without encoding 312 313 // primary, replicaId = 0 314 byte [] name = HRegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 0, false); 315 String nameStr = Bytes.toString(name); 316 assertEquals(tableName + "," + startKey + "," + id, nameStr); 317 318 // replicaId = 1 319 name = HRegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 1, false); 320 nameStr = Bytes.toString(name); 321 assertEquals(tableName + "," + startKey + "," + id + "_" + 322 String.format(HRegionInfo.REPLICA_ID_FORMAT, 1), nameStr); 323 324 // replicaId = max 325 name = HRegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 0xFFFF, false); 326 nameStr = Bytes.toString(name); 327 assertEquals(tableName + "," + startKey + "," + id + "_" + 328 String.format(HRegionInfo.REPLICA_ID_FORMAT, 0xFFFF), nameStr); 329 } 330 331 @Test 332 public void testParseName() throws IOException { 333 final TableName tableName = TableName.valueOf(name.getMethodName()); 334 byte[] startKey = Bytes.toBytes("startKey"); 335 long regionId = System.currentTimeMillis(); 336 int replicaId = 42; 337 338 // test without replicaId 339 byte[] regionName = HRegionInfo.createRegionName(tableName, startKey, regionId, false); 340 341 byte[][] fields = HRegionInfo.parseRegionName(regionName); 342 assertArrayEquals(Bytes.toString(fields[0]),tableName.getName(), fields[0]); 343 assertArrayEquals(Bytes.toString(fields[1]),startKey, fields[1]); 344 assertArrayEquals(Bytes.toString(fields[2]), Bytes.toBytes(Long.toString(regionId)),fields[2]); 345 assertEquals(3, fields.length); 346 347 // test with replicaId 348 regionName = HRegionInfo.createRegionName(tableName, startKey, regionId, 349 replicaId, false); 350 351 fields = HRegionInfo.parseRegionName(regionName); 352 assertArrayEquals(Bytes.toString(fields[0]),tableName.getName(), fields[0]); 353 assertArrayEquals(Bytes.toString(fields[1]),startKey, fields[1]); 354 assertArrayEquals(Bytes.toString(fields[2]), Bytes.toBytes(Long.toString(regionId)),fields[2]); 355 assertArrayEquals(Bytes.toString(fields[3]), Bytes.toBytes( 356 String.format(HRegionInfo.REPLICA_ID_FORMAT, replicaId)), fields[3]); 357 } 358 359 @Test 360 public void testConvert() { 361 final TableName tableName = TableName.valueOf("ns1:" + name.getMethodName()); 362 byte[] startKey = Bytes.toBytes("startKey"); 363 byte[] endKey = Bytes.toBytes("endKey"); 364 boolean split = false; 365 long regionId = System.currentTimeMillis(); 366 int replicaId = 42; 367 368 369 HRegionInfo hri = new HRegionInfo(tableName, startKey, endKey, split, 370 regionId, replicaId); 371 372 // convert two times, compare 373 HRegionInfo convertedHri = HRegionInfo.convert(HRegionInfo.convert(hri)); 374 375 assertEquals(hri, convertedHri); 376 377 // test convert RegionInfo without replicaId 378 HBaseProtos.RegionInfo info = HBaseProtos.RegionInfo.newBuilder() 379 .setTableName(HBaseProtos.TableName.newBuilder() 380 .setQualifier(UnsafeByteOperations.unsafeWrap(tableName.getQualifier())) 381 .setNamespace(UnsafeByteOperations.unsafeWrap(tableName.getNamespace())) 382 .build()) 383 .setStartKey(UnsafeByteOperations.unsafeWrap(startKey)) 384 .setEndKey(UnsafeByteOperations.unsafeWrap(endKey)) 385 .setSplit(split) 386 .setRegionId(regionId) 387 .build(); 388 389 convertedHri = HRegionInfo.convert(info); 390 HRegionInfo expectedHri = new HRegionInfo(tableName, startKey, endKey, split, 391 regionId, 0); // expecting default replicaId 392 393 assertEquals(expectedHri, convertedHri); 394 } 395 @Test 396 public void testRegionDetailsForDisplay() throws IOException { 397 byte[] startKey = new byte[] {0x01, 0x01, 0x02, 0x03}; 398 byte[] endKey = new byte[] {0x01, 0x01, 0x02, 0x04}; 399 Configuration conf = new Configuration(); 400 conf.setBoolean("hbase.display.keys", false); 401 HRegionInfo h = new HRegionInfo(TableName.valueOf(name.getMethodName()), startKey, endKey); 402 checkEquality(h, conf); 403 // check HRIs with non-default replicaId 404 h = new HRegionInfo(TableName.valueOf(name.getMethodName()), startKey, endKey, false, 405 System.currentTimeMillis(), 1); 406 checkEquality(h, conf); 407 Assert.assertArrayEquals(HRegionInfo.HIDDEN_END_KEY, 408 HRegionInfo.getEndKeyForDisplay(h, conf)); 409 Assert.assertArrayEquals(HRegionInfo.HIDDEN_START_KEY, 410 HRegionInfo.getStartKeyForDisplay(h, conf)); 411 412 RegionState state = RegionState.createForTesting(h, RegionState.State.OPEN); 413 String descriptiveNameForDisplay = 414 HRegionInfo.getDescriptiveNameFromRegionStateForDisplay(state, conf); 415 checkDescriptiveNameEquality(descriptiveNameForDisplay,state.toDescriptiveString(), startKey); 416 417 conf.setBoolean("hbase.display.keys", true); 418 Assert.assertArrayEquals(endKey, HRegionInfo.getEndKeyForDisplay(h, conf)); 419 Assert.assertArrayEquals(startKey, HRegionInfo.getStartKeyForDisplay(h, conf)); 420 Assert.assertEquals(state.toDescriptiveString(), 421 HRegionInfo.getDescriptiveNameFromRegionStateForDisplay(state, conf)); 422 } 423 424 private void checkDescriptiveNameEquality(String descriptiveNameForDisplay, String origDesc, 425 byte[] startKey) { 426 // except for the "hidden-start-key" substring everything else should exactly match 427 String firstPart = descriptiveNameForDisplay.substring(0, 428 descriptiveNameForDisplay.indexOf(new String(HRegionInfo.HIDDEN_START_KEY))); 429 String secondPart = descriptiveNameForDisplay.substring( 430 descriptiveNameForDisplay.indexOf(new String(HRegionInfo.HIDDEN_START_KEY)) + 431 HRegionInfo.HIDDEN_START_KEY.length); 432 String firstPartOrig = origDesc.substring(0, 433 origDesc.indexOf(Bytes.toStringBinary(startKey))); 434 String secondPartOrig = origDesc.substring( 435 origDesc.indexOf(Bytes.toStringBinary(startKey)) + 436 Bytes.toStringBinary(startKey).length()); 437 assert(firstPart.equals(firstPartOrig)); 438 assert(secondPart.equals(secondPartOrig)); 439 } 440 441 private void checkEquality(HRegionInfo h, Configuration conf) throws IOException { 442 byte[] modifiedRegionName = HRegionInfo.getRegionNameForDisplay(h, conf); 443 byte[][] modifiedRegionNameParts = HRegionInfo.parseRegionName(modifiedRegionName); 444 byte[][] regionNameParts = HRegionInfo.parseRegionName(h.getRegionName()); 445 446 //same number of parts 447 assert(modifiedRegionNameParts.length == regionNameParts.length); 448 449 for (int i = 0; i < regionNameParts.length; i++) { 450 // all parts should match except for [1] where in the modified one, 451 // we should have "hidden_start_key" 452 if (i != 1) { 453 Assert.assertArrayEquals(regionNameParts[i], modifiedRegionNameParts[i]); 454 } else { 455 assertNotEquals(regionNameParts[i][0], modifiedRegionNameParts[i][0]); 456 Assert.assertArrayEquals(modifiedRegionNameParts[1], 457 HRegionInfo.getStartKeyForDisplay(h, conf)); 458 } 459 } 460 } 461} 462