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 java.io.IOException;
021import java.util.List;
022
023import org.apache.hadoop.hbase.HBaseClassTestRule;
024import org.apache.hadoop.hbase.HBaseTestingUtility;
025import org.apache.hadoop.hbase.HConstants;
026import org.apache.hadoop.hbase.MetaTableAccessor;
027import org.apache.hadoop.hbase.TableName;
028import org.apache.hadoop.hbase.client.RegionInfo;
029import org.apache.hadoop.hbase.testclassification.LargeTests;
030import org.apache.hadoop.hbase.testclassification.MasterTests;
031import org.junit.AfterClass;
032import org.junit.Assert;
033import org.junit.BeforeClass;
034import org.junit.ClassRule;
035import org.junit.Rule;
036import org.junit.Test;
037import org.junit.experimental.categories.Category;
038import org.junit.rules.TestName;
039import org.slf4j.Logger;
040import org.slf4j.LoggerFactory;
041
042
043@Category({MasterTests.class, LargeTests.class})
044public class TestMetaFixer {
045  @ClassRule
046  public static final HBaseClassTestRule CLASS_RULE =
047      HBaseClassTestRule.forClass(TestMetaFixer.class);
048  @Rule
049  public TestName name = new TestName();
050  private static final Logger LOG = LoggerFactory.getLogger(TestMetaFixer.class);
051
052  private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
053
054  @BeforeClass
055  public static void setupBeforeClass() throws Exception {
056    TEST_UTIL.startMiniCluster();
057  }
058
059  @AfterClass
060  public static void tearDownAfterClass() throws Exception {
061    TEST_UTIL.shutdownMiniCluster();
062  }
063
064  private void deleteRegion(MasterServices services, RegionInfo ri) throws IOException {
065    MetaTableAccessor.deleteRegionInfo(TEST_UTIL.getConnection(), ri);
066    // Delete it from Master context too else it sticks around.
067    services.getAssignmentManager().getRegionStates().deleteRegion(ri);
068  }
069
070  @Test
071  public void testPlugsHoles() throws IOException {
072    TableName tn = TableName.valueOf(this.name.getMethodName());
073    TEST_UTIL.createMultiRegionTable(tn, HConstants.CATALOG_FAMILY);
074    List<RegionInfo> ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), tn);
075    MasterServices services = TEST_UTIL.getHBaseCluster().getMaster();
076    services.getCatalogJanitor().scan();
077    CatalogJanitor.Report report = services.getCatalogJanitor().getLastReport();
078    Assert.assertTrue(report.isEmpty());
079    int originalCount = ris.size();
080    // Remove first, last and middle region. See if hole gets plugged. Table has 26 regions.
081    deleteRegion(services, ris.get(ris.size() -1));
082    deleteRegion(services, ris.get(3));
083    deleteRegion(services, ris.get(0));
084    ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), tn);
085    services.getCatalogJanitor().scan();
086    report = services.getCatalogJanitor().getLastReport();
087    Assert.assertEquals(report.toString(), 3, report.getHoles().size());
088    MetaFixer fixer = new MetaFixer(services);
089    Assert.assertTrue(fixer.fixHoles(report));
090    services.getCatalogJanitor().scan();
091    report = services.getCatalogJanitor().getLastReport();
092    Assert.assertTrue(report.toString(), report.isEmpty());
093    // Disable and reenable so the added regions get reassigned.
094    TEST_UTIL.getAdmin().disableTable(tn);
095    TEST_UTIL.getAdmin().enableTable(tn);
096    ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), tn);
097    Assert.assertEquals(originalCount, ris.size());
098  }
099
100  /**
101   * Just make sure running fixMeta does right thing for the case
102   * of a single-region Table where the region gets dropped.
103   * There is nothing much we can do. We can't restore what
104   * we don't know about (at least from a read of hbase:meta).
105   */
106  @Test
107  public void testOneRegionTable() throws IOException {
108    TableName tn = TableName.valueOf(this.name.getMethodName());
109    TEST_UTIL.createTable(tn, HConstants.CATALOG_FAMILY);
110    List<RegionInfo> ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), tn);
111    MasterServices services = TEST_UTIL.getHBaseCluster().getMaster();
112    services.getCatalogJanitor().scan();
113    CatalogJanitor.Report report = services.getCatalogJanitor().getLastReport();
114    int originalCount = ris.size();
115    deleteRegion(services, ris.get(0));
116    services.getCatalogJanitor().scan();
117    report = services.getCatalogJanitor().getLastReport();
118    ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), tn);
119    Assert.assertTrue(ris.isEmpty());
120    MetaFixer fixer = new MetaFixer(services);
121    Assert.assertFalse(fixer.fixHoles(report));
122    report = services.getCatalogJanitor().getLastReport();
123    Assert.assertTrue(report.isEmpty());
124    ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), tn);
125    Assert.assertEquals(0, ris.size());
126  }
127}