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.assignment;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertNotEquals;
022import static org.junit.Assert.assertTrue;
023
024import java.io.IOException;
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.hbase.HBaseClassTestRule;
027import org.apache.hadoop.hbase.HBaseTestingUtility;
028import org.apache.hadoop.hbase.ServerName;
029import org.apache.hadoop.hbase.TableName;
030import org.apache.hadoop.hbase.client.Get;
031import org.apache.hadoop.hbase.client.Put;
032import org.apache.hadoop.hbase.client.RegionInfo;
033import org.apache.hadoop.hbase.client.Result;
034import org.apache.hadoop.hbase.client.Table;
035import org.apache.hadoop.hbase.master.procedure.MasterProcedureConstants;
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.Test;
043import org.junit.experimental.categories.Category;
044import org.slf4j.Logger;
045import org.slf4j.LoggerFactory;
046
047@Category({MasterTests.class, LargeTests.class})
048public class TestAssignmentOnRSCrash {
049
050  @ClassRule
051  public static final HBaseClassTestRule CLASS_RULE =
052      HBaseClassTestRule.forClass(TestAssignmentOnRSCrash.class);
053
054  private static final Logger LOG = LoggerFactory.getLogger(TestAssignmentOnRSCrash.class);
055
056  private static final TableName TEST_TABLE = TableName.valueOf("testb");
057  private static final String FAMILY_STR = "f";
058  private static final byte[] FAMILY = Bytes.toBytes(FAMILY_STR);
059  private static final int NUM_RS = 3;
060
061  private HBaseTestingUtility UTIL;
062
063  private static void setupConf(Configuration conf) {
064    conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1);
065    conf.set("hbase.balancer.tablesOnMaster", "none");
066  }
067
068  @Before
069  public void setup() throws Exception {
070    UTIL = new HBaseTestingUtility();
071
072    setupConf(UTIL.getConfiguration());
073    UTIL.startMiniCluster(NUM_RS);
074
075    UTIL.createTable(TEST_TABLE, new byte[][] { FAMILY }, new byte[][] {
076      Bytes.toBytes("B"), Bytes.toBytes("D"), Bytes.toBytes("F"), Bytes.toBytes("L")
077    });
078  }
079
080  @After
081  public void tearDown() throws Exception {
082    UTIL.shutdownMiniCluster();
083  }
084
085  @Test
086  public void testKillRsWithUserRegionWithData() throws Exception {
087    testCrashRsWithUserRegion(true, true);
088  }
089
090  @Test
091  public void testKillRsWithUserRegionWithoutData() throws Exception {
092    testCrashRsWithUserRegion(true, false);
093  }
094
095  @Test
096  public void testStopRsWithUserRegionWithData() throws Exception {
097    testCrashRsWithUserRegion(false, true);
098  }
099
100  @Test
101  public void testStopRsWithUserRegionWithoutData() throws Exception {
102    testCrashRsWithUserRegion(false, false);
103  }
104
105  private void testCrashRsWithUserRegion(final boolean kill, final boolean withData)
106      throws Exception {
107    final int NROWS = 100;
108    int nkilled = 0;
109    for (RegionInfo hri: UTIL.getHBaseAdmin().getTableRegions(TEST_TABLE)) {
110      ServerName serverName = AssignmentTestingUtil.getServerHoldingRegion(UTIL, hri);
111      if (AssignmentTestingUtil.isServerHoldingMeta(UTIL, serverName)) continue;
112
113      if (withData) {
114        testInsert(hri, NROWS);
115      }
116
117      // wait for regions to enter in transition and then to get out of transition
118      AssignmentTestingUtil.crashRs(UTIL, serverName, kill);
119      AssignmentTestingUtil.waitForRegionToBeInTransition(UTIL, hri);
120      UTIL.waitUntilNoRegionsInTransition();
121
122      if (withData) {
123        assertEquals(NROWS, testGet(hri, NROWS));
124      }
125
126      // region should be moved to another RS
127      assertNotEquals(serverName, AssignmentTestingUtil.getServerHoldingRegion(UTIL, hri));
128
129      if (++nkilled == (NUM_RS - 1)) {
130        break;
131      }
132    }
133    assertTrue("expected RSs to be killed", nkilled > 0);
134  }
135
136  @Test
137  public void testKillRsWithMetaRegion() throws Exception {
138    testCrashRsWithMetaRegion(true);
139  }
140
141  @Test
142  public void testStopRsWithMetaRegion() throws Exception {
143    testCrashRsWithMetaRegion(false);
144  }
145
146  private void testCrashRsWithMetaRegion(final boolean kill) throws Exception {
147    int nkilled = 0;
148    for (RegionInfo hri: AssignmentTestingUtil.getMetaRegions(UTIL)) {
149      ServerName serverName = AssignmentTestingUtil.crashRsWithRegion(UTIL, hri, kill);
150
151      // wait for region to enter in transition and then to get out of transition
152      AssignmentTestingUtil.waitForRegionToBeInTransition(UTIL, hri);
153      UTIL.waitUntilNoRegionsInTransition();
154      testGet(hri, 10);
155
156      // region should be moved to another RS
157      assertNotEquals(serverName, AssignmentTestingUtil.getServerHoldingRegion(UTIL, hri));
158
159      if (++nkilled == (NUM_RS - 1)) {
160        break;
161      }
162    }
163    assertTrue("expected RSs to be killed", nkilled > 0);
164  }
165
166  private void testInsert(final RegionInfo hri, final int nrows) throws IOException {
167    final Table table = UTIL.getConnection().getTable(hri.getTable());
168    for (int i = 0; i < nrows; ++i) {
169      final byte[] row = Bytes.add(hri.getStartKey(), Bytes.toBytes(i));
170      final Put put = new Put(row);
171      put.addColumn(FAMILY, null, row);
172      table.put(put);
173    }
174  }
175
176  public int testGet(final RegionInfo hri, final int nrows) throws IOException {
177    int nresults = 0;
178    final Table table = UTIL.getConnection().getTable(hri.getTable());
179    for (int i = 0; i < nrows; ++i) {
180      final byte[] row = Bytes.add(hri.getStartKey(), Bytes.toBytes(i));
181      final Result result = table.get(new Get(row));
182      if (result != null && !result.isEmpty() &&
183          Bytes.equals(row, result.getValue(FAMILY, null))) {
184        nresults++;
185      }
186    }
187    return nresults;
188  }
189}