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