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