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.client; 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.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.TableNameTestRule; 031import org.apache.hadoop.hbase.exceptions.DeserializationException; 032import org.apache.hadoop.hbase.testclassification.ClientTests; 033import org.apache.hadoop.hbase.testclassification.SmallTests; 034import org.apache.hadoop.hbase.util.Bytes; 035import org.apache.hadoop.hbase.util.MD5Hash; 036import org.junit.ClassRule; 037import org.junit.Rule; 038import org.junit.Test; 039import org.junit.experimental.categories.Category; 040 041import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations; 042 043import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 044import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; 045 046@Category({ ClientTests.class, SmallTests.class }) 047public class TestRegionInfoBuilder { 048 049 @ClassRule 050 public static final HBaseClassTestRule CLASS_RULE = 051 HBaseClassTestRule.forClass(TestRegionInfoBuilder.class); 052 053 @Rule 054 public TableNameTestRule name = new TableNameTestRule(); 055 056 @Test 057 public void testBuilder() { 058 TableName tn = TableName.valueOf("test"); 059 RegionInfoBuilder builder = RegionInfoBuilder.newBuilder(tn); 060 byte[] startKey = Bytes.toBytes("a"); 061 builder.setStartKey(startKey); 062 byte[] endKey = Bytes.toBytes("z"); 063 builder.setEndKey(endKey); 064 int regionId = 1; 065 builder.setRegionId(1); 066 int replicaId = 2; 067 builder.setReplicaId(replicaId); 068 boolean offline = true; 069 builder.setOffline(offline); 070 boolean isSplit = true; 071 builder.setSplit(isSplit); 072 RegionInfo ri = builder.build(); 073 074 assertEquals(tn, ri.getTable()); 075 assertArrayEquals(startKey, ri.getStartKey()); 076 assertArrayEquals(endKey, ri.getEndKey()); 077 assertEquals(regionId, ri.getRegionId()); 078 assertEquals(replicaId, ri.getReplicaId()); 079 assertEquals(offline, ri.isOffline()); 080 assertEquals(isSplit, ri.isSplit()); 081 } 082 083 @Test 084 public void testPb() throws DeserializationException { 085 RegionInfo ri = RegionInfoBuilder.FIRST_META_REGIONINFO; 086 byte[] bytes = RegionInfo.toByteArray(ri); 087 RegionInfo pbri = RegionInfo.parseFrom(bytes); 088 assertTrue(RegionInfo.COMPARATOR.compare(ri, pbri) == 0); 089 } 090 091 @Test 092 public void testCreateRegionInfoName() throws Exception { 093 final TableName tn = name.getTableName(); 094 String startKey = "startkey"; 095 final byte[] sk = Bytes.toBytes(startKey); 096 String id = "id"; 097 098 // old format region name 099 byte[] name = RegionInfo.createRegionName(tn, sk, id, false); 100 String nameStr = Bytes.toString(name); 101 assertEquals(tn + "," + startKey + "," + id, nameStr); 102 103 // new format region name. 104 String md5HashInHex = MD5Hash.getMD5AsHex(name); 105 assertEquals(RegionInfo.MD5_HEX_LENGTH, md5HashInHex.length()); 106 name = RegionInfo.createRegionName(tn, sk, id, true); 107 nameStr = Bytes.toString(name); 108 assertEquals(tn + "," + startKey + "," + id + "." + md5HashInHex + ".", nameStr); 109 } 110 111 @Test 112 public void testContainsRange() { 113 TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(name.getTableName()).build(); 114 RegionInfo ri = RegionInfoBuilder.newBuilder(tableDesc.getTableName()) 115 .setStartKey(Bytes.toBytes("a")).setEndKey(Bytes.toBytes("g")).build(); 116 // Single row range at start of region 117 assertTrue(ri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("a"))); 118 // Fully contained range 119 assertTrue(ri.containsRange(Bytes.toBytes("b"), Bytes.toBytes("c"))); 120 // Range overlapping start of region 121 assertTrue(ri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("c"))); 122 // Fully contained single-row range 123 assertTrue(ri.containsRange(Bytes.toBytes("c"), Bytes.toBytes("c"))); 124 // Range that overlaps end key and hence doesn't fit 125 assertFalse(ri.containsRange(Bytes.toBytes("a"), Bytes.toBytes("g"))); 126 // Single row range on end key 127 assertFalse(ri.containsRange(Bytes.toBytes("g"), Bytes.toBytes("g"))); 128 // Single row range entirely outside 129 assertFalse(ri.containsRange(Bytes.toBytes("z"), Bytes.toBytes("z"))); 130 131 // Degenerate range 132 try { 133 ri.containsRange(Bytes.toBytes("z"), Bytes.toBytes("a")); 134 fail("Invalid range did not throw IAE"); 135 } catch (IllegalArgumentException iae) { 136 } 137 } 138 139 @Test 140 public void testLastRegionCompare() { 141 TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(name.getTableName()).build(); 142 RegionInfo rip = RegionInfoBuilder.newBuilder(tableDesc.getTableName()) 143 .setStartKey(Bytes.toBytes("a")).setEndKey(new byte[0]).build(); 144 RegionInfo ric = RegionInfoBuilder.newBuilder(tableDesc.getTableName()) 145 .setStartKey(Bytes.toBytes("a")).setEndKey(Bytes.toBytes("b")).build(); 146 assertTrue(RegionInfo.COMPARATOR.compare(rip, ric) > 0); 147 } 148 149 @Test 150 public void testMetaTables() { 151 assertTrue(RegionInfoBuilder.FIRST_META_REGIONINFO.isMetaRegion()); 152 } 153 154 @Test 155 public void testComparator() { 156 final TableName tableName = name.getTableName(); 157 byte[] empty = new byte[0]; 158 RegionInfo older = RegionInfoBuilder.newBuilder(tableName).setStartKey(empty).setEndKey(empty) 159 .setSplit(false).setRegionId(0L).build(); 160 RegionInfo newer = RegionInfoBuilder.newBuilder(tableName).setStartKey(empty).setEndKey(empty) 161 .setSplit(false).setRegionId(1L).build(); 162 assertTrue(RegionInfo.COMPARATOR.compare(older, newer) < 0); 163 assertTrue(RegionInfo.COMPARATOR.compare(newer, older) > 0); 164 assertTrue(RegionInfo.COMPARATOR.compare(older, older) == 0); 165 assertTrue(RegionInfo.COMPARATOR.compare(newer, newer) == 0); 166 } 167 168 @Test 169 public void testRegionNameForRegionReplicas() throws Exception { 170 final TableName tn = name.getTableName(); 171 String startKey = "startkey"; 172 final byte[] sk = Bytes.toBytes(startKey); 173 String id = "id"; 174 175 // assert with only the region name without encoding 176 177 // primary, replicaId = 0 178 byte[] name = RegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 0, false); 179 String nameStr = Bytes.toString(name); 180 assertEquals(tn + "," + startKey + "," + id, nameStr); 181 182 // replicaId = 1 183 name = RegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 1, false); 184 nameStr = Bytes.toString(name); 185 assertEquals( 186 tn + "," + startKey + "," + id + "_" + String.format(RegionInfo.REPLICA_ID_FORMAT, 1), 187 nameStr); 188 189 // replicaId = max 190 name = RegionInfo.createRegionName(tn, sk, Bytes.toBytes(id), 0xFFFF, false); 191 nameStr = Bytes.toString(name); 192 assertEquals( 193 tn + "," + startKey + "," + id + "_" + String.format(RegionInfo.REPLICA_ID_FORMAT, 0xFFFF), 194 nameStr); 195 } 196 197 @Test 198 public void testParseName() throws IOException { 199 final TableName tableName = name.getTableName(); 200 byte[] startKey = Bytes.toBytes("startKey"); 201 long regionId = System.currentTimeMillis(); 202 int replicaId = 42; 203 204 // test without replicaId 205 byte[] regionName = RegionInfo.createRegionName(tableName, startKey, regionId, false); 206 207 byte[][] fields = RegionInfo.parseRegionName(regionName); 208 assertArrayEquals(Bytes.toString(fields[0]), tableName.getName(), fields[0]); 209 assertArrayEquals(Bytes.toString(fields[1]), startKey, fields[1]); 210 assertArrayEquals(Bytes.toString(fields[2]), Bytes.toBytes(Long.toString(regionId)), fields[2]); 211 assertEquals(3, fields.length); 212 213 // test with replicaId 214 regionName = RegionInfo.createRegionName(tableName, startKey, regionId, replicaId, false); 215 216 fields = RegionInfo.parseRegionName(regionName); 217 assertArrayEquals(Bytes.toString(fields[0]), tableName.getName(), fields[0]); 218 assertArrayEquals(Bytes.toString(fields[1]), startKey, fields[1]); 219 assertArrayEquals(Bytes.toString(fields[2]), Bytes.toBytes(Long.toString(regionId)), fields[2]); 220 assertArrayEquals(Bytes.toString(fields[3]), 221 Bytes.toBytes(String.format(RegionInfo.REPLICA_ID_FORMAT, replicaId)), fields[3]); 222 } 223 224 @Test 225 public void testConvert() { 226 final TableName tableName = 227 TableName.valueOf("ns1:" + name.getTableName().getQualifierAsString()); 228 byte[] startKey = Bytes.toBytes("startKey"); 229 byte[] endKey = Bytes.toBytes("endKey"); 230 boolean split = false; 231 long regionId = System.currentTimeMillis(); 232 int replicaId = 42; 233 234 RegionInfo ri = RegionInfoBuilder.newBuilder(tableName).setStartKey(startKey).setEndKey(endKey) 235 .setSplit(split).setRegionId(regionId).setReplicaId(replicaId).build(); 236 237 // convert two times, compare 238 RegionInfo convertedRi = ProtobufUtil.toRegionInfo(ProtobufUtil.toRegionInfo(ri)); 239 240 assertEquals(ri, convertedRi); 241 242 // test convert RegionInfo without replicaId 243 HBaseProtos.RegionInfo info = HBaseProtos.RegionInfo.newBuilder() 244 .setTableName(HBaseProtos.TableName.newBuilder() 245 .setQualifier(UnsafeByteOperations.unsafeWrap(tableName.getQualifier())) 246 .setNamespace(UnsafeByteOperations.unsafeWrap(tableName.getNamespace())).build()) 247 .setStartKey(UnsafeByteOperations.unsafeWrap(startKey)) 248 .setEndKey(UnsafeByteOperations.unsafeWrap(endKey)).setSplit(split).setRegionId(regionId) 249 .build(); 250 251 convertedRi = ProtobufUtil.toRegionInfo(info); 252 RegionInfo expectedRi = RegionInfoBuilder.newBuilder(tableName).setStartKey(startKey) 253 .setEndKey(endKey).setSplit(split).setRegionId(regionId).setReplicaId(0).build(); 254 255 assertEquals(expectedRi, convertedRi); 256 } 257 258 private void assertRegionNameNotEquals(RegionInfo expected, RegionInfo actual) { 259 assertNotEquals(expected.getRegionNameAsString(), actual.getRegionNameAsString()); 260 assertNotEquals(expected.getEncodedName(), actual.getEncodedName()); 261 } 262 263 private void assertRegionNameEquals(RegionInfo expected, RegionInfo actual) { 264 assertEquals(expected.getRegionNameAsString(), actual.getRegionNameAsString()); 265 assertEquals(expected.getEncodedName(), actual.getEncodedName()); 266 } 267 268 @Test 269 public void testNewBuilderWithRegionInfo() { 270 RegionInfo ri = RegionInfoBuilder.newBuilder(name.getTableName()).build(); 271 assertEquals(ri, RegionInfoBuilder.newBuilder(ri).build()); 272 273 // make sure that the region name and encoded name are changed, see HBASE-24500 for more 274 // details. 275 assertRegionNameNotEquals(ri, 276 RegionInfoBuilder.newBuilder(ri).setStartKey(new byte[1]).build()); 277 assertRegionNameNotEquals(ri, 278 RegionInfoBuilder.newBuilder(ri).setRegionId(ri.getRegionId() + 1).build()); 279 assertRegionNameNotEquals(ri, RegionInfoBuilder.newBuilder(ri).setReplicaId(1).build()); 280 281 // these fields are not in region name 282 assertRegionNameEquals(ri, RegionInfoBuilder.newBuilder(ri).setEndKey(new byte[1]).build()); 283 assertRegionNameEquals(ri, RegionInfoBuilder.newBuilder(ri).setSplit(true).build()); 284 assertRegionNameEquals(ri, RegionInfoBuilder.newBuilder(ri).setOffline(true).build()); 285 } 286}