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