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.master;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertTrue;
023
024import java.io.IOException;
025import java.util.Arrays;
026import java.util.List;
027
028import org.apache.hadoop.hbase.HBaseClassTestRule;
029import org.apache.hadoop.hbase.HBaseTestingUtility;
030import org.apache.hadoop.hbase.HConstants;
031import org.apache.hadoop.hbase.MetaTableAccessor;
032import org.apache.hadoop.hbase.TableName;
033import org.apache.hadoop.hbase.client.Put;
034import org.apache.hadoop.hbase.client.RegionInfo;
035import org.apache.hadoop.hbase.client.RegionInfoBuilder;
036import org.apache.hadoop.hbase.testclassification.LargeTests;
037import org.apache.hadoop.hbase.testclassification.MasterTests;
038import org.apache.hadoop.hbase.util.Bytes;
039import org.junit.After;
040import org.junit.Before;
041import org.junit.ClassRule;
042import org.junit.Rule;
043import org.junit.Test;
044import org.junit.experimental.categories.Category;
045import org.junit.rules.TestName;
046
047@Category({MasterTests.class, LargeTests.class})
048public class TestCatalogJanitorCluster {
049  @ClassRule
050  public static final HBaseClassTestRule CLASS_RULE =
051      HBaseClassTestRule.forClass(TestCatalogJanitorCluster.class);
052
053  @Rule
054  public final TestName name = new TestName();
055
056  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
057  private static final TableName T1 = TableName.valueOf("t1");
058  private static final TableName T2 = TableName.valueOf("t2");
059  private static final TableName T3 = TableName.valueOf("t3");
060
061  @Before
062  public void before() throws Exception {
063    TEST_UTIL.startMiniCluster();
064    TEST_UTIL.createMultiRegionTable(T1, new byte [][] {HConstants.CATALOG_FAMILY});
065    TEST_UTIL.createMultiRegionTable(T2, new byte [][] {HConstants.CATALOG_FAMILY});
066    TEST_UTIL.createMultiRegionTable(T3, new byte [][] {HConstants.CATALOG_FAMILY});
067  }
068
069  @After
070  public void after() throws Exception {
071    TEST_UTIL.shutdownMiniCluster();
072  }
073
074  /**
075   * Fat method where we start with a fat hbase:meta and then gradually intro
076   * problems running catalogjanitor for each to ensure it triggers complaint.
077   * Do one big method because takes a while to build up the context we need.
078   * We create three tables and then make holes, overlaps, add unknown servers
079   * and empty out regioninfo columns. Each should up counts in the
080   * CatalogJanitor.Report produced.
081   */
082  @Test
083  public void testConsistency() throws IOException {
084    CatalogJanitor janitor = TEST_UTIL.getHBaseCluster().getMaster().getCatalogJanitor();
085    int gc = janitor.scan();
086    CatalogJanitor.Report report = janitor.getLastReport();
087    // Assert no problems.
088    assertTrue(report.isEmpty());
089    // Now remove first region in table t2 to see if catalogjanitor scan notices.
090    List<RegionInfo> t2Ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), T2);
091    MetaTableAccessor.deleteRegionInfo(TEST_UTIL.getConnection(), t2Ris.get(0));
092    gc = janitor.scan();
093    report = janitor.getLastReport();
094    assertFalse(report.isEmpty());
095    assertEquals(1, report.getHoles().size());
096    assertTrue(report.getHoles().get(0).getFirst().getTable().equals(T1));
097    assertTrue(report.getHoles().get(0).getFirst().isLast());
098    assertTrue(report.getHoles().get(0).getSecond().getTable().equals(T2));
099    assertEquals(0, report.getOverlaps().size());
100    // Next, add overlaps to first row in t3
101    List<RegionInfo> t3Ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), T3);
102    RegionInfo ri = t3Ris.get(0);
103    RegionInfo newRi1 = RegionInfoBuilder.newBuilder(ri.getTable()).
104        setStartKey(incrementRow(ri.getStartKey())).
105        setEndKey(incrementRow(ri.getEndKey())).build();
106    Put p1 = MetaTableAccessor.makePutFromRegionInfo(newRi1, System.currentTimeMillis());
107    RegionInfo newRi2 = RegionInfoBuilder.newBuilder(newRi1.getTable()).
108        setStartKey(incrementRow(newRi1.getStartKey())).
109        setEndKey(incrementRow(newRi1.getEndKey())).build();
110    Put p2 = MetaTableAccessor.makePutFromRegionInfo(newRi2, System.currentTimeMillis());
111    MetaTableAccessor.putsToMetaTable(TEST_UTIL.getConnection(), Arrays.asList(p1, p2));
112    gc = janitor.scan();
113    report = janitor.getLastReport();
114    assertFalse(report.isEmpty());
115    // We added two overlaps so total three.
116    assertEquals(3, report.getOverlaps().size());
117    // Assert hole is still there.
118    assertEquals(1, report.getHoles().size());
119    // Assert other attributes are empty still.
120    assertTrue(report.getEmptyRegionInfo().isEmpty());
121    assertTrue(report.getUnknownServers().isEmpty());
122    // Now make bad server in t1.
123    List<RegionInfo> t1Ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), T1);
124    RegionInfo t1Ri1 = t1Ris.get(1);
125    Put pServer = new Put(t1Ri1.getRegionName());
126    pServer.addColumn(MetaTableAccessor.getCatalogFamily(),
127        MetaTableAccessor.getServerColumn(0), Bytes.toBytes("bad.server.example.org:1234"));
128    MetaTableAccessor.putsToMetaTable(TEST_UTIL.getConnection(), Arrays.asList(pServer));
129    gc = janitor.scan();
130    report = janitor.getLastReport();
131    assertFalse(report.isEmpty());
132    // Finally, make an empty regioninfo in t1.
133    RegionInfo t1Ri2 = t1Ris.get(2);
134    Put pEmptyRI = new Put(t1Ri2.getRegionName());
135    pEmptyRI.addColumn(MetaTableAccessor.getCatalogFamily(),
136        MetaTableAccessor.getRegionInfoColumn(), HConstants.EMPTY_BYTE_ARRAY);
137    MetaTableAccessor.putsToMetaTable(TEST_UTIL.getConnection(), Arrays.asList(pEmptyRI));
138    gc = janitor.scan();
139    report = janitor.getLastReport();
140    assertEquals(1, report.getEmptyRegionInfo().size());
141  }
142
143  /**
144   * Take last byte and add one to it.
145   */
146  private static byte [] incrementRow(byte [] row) {
147    if (row.length == 0) {
148      return new byte []{'0'};
149    }
150    row[row.length - 1] = (byte)(((int)row[row.length - 1]) + 1);
151    return row;
152  }
153}