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;
019
020import static org.junit.Assert.assertEquals;
021
022import org.apache.hadoop.conf.Configuration;
023import org.apache.hadoop.hbase.Waiter.ExplainingPredicate;
024import org.apache.hadoop.hbase.client.Table;
025import org.apache.hadoop.hbase.testclassification.LargeTests;
026import org.apache.hadoop.hbase.testclassification.MiscTests;
027import org.apache.hadoop.hbase.util.Bytes;
028import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
029import org.junit.AfterClass;
030import org.junit.BeforeClass;
031import org.junit.ClassRule;
032import org.junit.Test;
033import org.junit.experimental.categories.Category;
034
035@Category({ MiscTests.class, LargeTests.class })
036public class TestFullLogReconstruction {
037
038  @ClassRule
039  public static final HBaseClassTestRule CLASS_RULE =
040      HBaseClassTestRule.forClass(TestFullLogReconstruction.class);
041
042  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
043
044  private final static TableName TABLE_NAME = TableName.valueOf("tabletest");
045  private final static byte[] FAMILY = Bytes.toBytes("family");
046
047  @BeforeClass
048  public static void setUpBeforeClass() throws Exception {
049    Configuration c = TEST_UTIL.getConfiguration();
050    // quicker heartbeat interval for faster DN death notification
051    c.setInt("dfs.namenode.heartbeat.recheck-interval", 5000);
052    c.setInt("dfs.heartbeat.interval", 1);
053    c.setInt("dfs.client.socket-timeout", 5000);
054    // faster failover with cluster.shutdown();fs.close() idiom
055    c.setInt("hbase.ipc.client.connect.max.retries", 1);
056    c.setInt("dfs.client.block.recovery.retries", 1);
057    c.setInt(HConstants.ZK_SESSION_TIMEOUT, 1000);
058    TEST_UTIL.startMiniCluster(3);
059  }
060
061  @AfterClass
062  public static void tearDownAfterClass() throws Exception {
063    TEST_UTIL.shutdownMiniCluster();
064  }
065
066  /**
067   * Test the whole reconstruction loop. Build a table with regions aaa to zzz and load every one of
068   * them multiple times with the same date and do a flush at some point. Kill one of the region
069   * servers and scan the table. We should see all the rows.
070   */
071  @Test
072  public void testReconstruction() throws Exception {
073    Table table = TEST_UTIL.createMultiRegionTable(TABLE_NAME, FAMILY);
074
075    // Load up the table with simple rows and count them
076    int initialCount = TEST_UTIL.loadTable(table, FAMILY);
077    int count = TEST_UTIL.countRows(table);
078
079    assertEquals(initialCount, count);
080
081    for (int i = 0; i < 4; i++) {
082      TEST_UTIL.loadTable(table, FAMILY);
083    }
084    RegionServerThread rsThread = TEST_UTIL.getHBaseCluster().getRegionServerThreads().get(0);
085    TEST_UTIL.expireRegionServerSession(0);
086    // make sure that the RS is fully down before reading, so that we will read the data from other
087    // RSes.
088    TEST_UTIL.waitFor(30000, new ExplainingPredicate<Exception>() {
089
090      @Override
091      public boolean evaluate() throws Exception {
092        return !rsThread.isAlive();
093      }
094
095      @Override
096      public String explainFailure() throws Exception {
097        return rsThread.getRegionServer() + " is still alive";
098      }
099    });
100
101    int newCount = TEST_UTIL.countRows(table);
102    assertEquals(count, newCount);
103    table.close();
104  }
105}