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