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.HBaseTestingUtil;
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 HBaseTestingUtil 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 HBaseTestingUtil();
071
072    setupConf(UTIL.getConfiguration());
073    UTIL.startMiniCluster(NUM_RS);
074
075    UTIL.createTable(TEST_TABLE, new byte[][] { FAMILY }, new byte[][] { Bytes.toBytes("B"),
076      Bytes.toBytes("D"), Bytes.toBytes("F"), Bytes.toBytes("L") });
077  }
078
079  @After
080  public void tearDown() throws Exception {
081    UTIL.shutdownMiniCluster();
082  }
083
084  @Test
085  public void testKillRsWithUserRegionWithData() throws Exception {
086    testCrashRsWithUserRegion(true, true);
087  }
088
089  @Test
090  public void testKillRsWithUserRegionWithoutData() throws Exception {
091    testCrashRsWithUserRegion(true, false);
092  }
093
094  @Test
095  public void testStopRsWithUserRegionWithData() throws Exception {
096    testCrashRsWithUserRegion(false, true);
097  }
098
099  @Test
100  public void testStopRsWithUserRegionWithoutData() throws Exception {
101    testCrashRsWithUserRegion(false, false);
102  }
103
104  private void testCrashRsWithUserRegion(final boolean kill, final boolean withData)
105    throws Exception {
106    final int NROWS = 100;
107    int nkilled = 0;
108    for (RegionInfo hri : UTIL.getAdmin().getRegions(TEST_TABLE)) {
109      ServerName serverName = AssignmentTestingUtil.getServerHoldingRegion(UTIL, hri);
110      if (AssignmentTestingUtil.isServerHoldingMeta(UTIL, serverName)) continue;
111
112      if (withData) {
113        testInsert(hri, NROWS);
114      }
115
116      // wait for regions to enter in transition and then to get out of transition
117      AssignmentTestingUtil.crashRs(UTIL, serverName, kill);
118      AssignmentTestingUtil.waitForRegionToBeInTransition(UTIL, hri);
119      UTIL.waitUntilNoRegionsInTransition();
120
121      if (withData) {
122        assertEquals(NROWS, testGet(hri, NROWS));
123      }
124
125      // region should be moved to another RS
126      assertNotEquals(serverName, AssignmentTestingUtil.getServerHoldingRegion(UTIL, hri));
127
128      if (++nkilled == (NUM_RS - 1)) {
129        break;
130      }
131    }
132    assertTrue("expected RSs to be killed", nkilled > 0);
133  }
134
135  @Test
136  public void testKillRsWithMetaRegion() throws Exception {
137    testCrashRsWithMetaRegion(true);
138  }
139
140  @Test
141  public void testStopRsWithMetaRegion() throws Exception {
142    testCrashRsWithMetaRegion(false);
143  }
144
145  private void testCrashRsWithMetaRegion(final boolean kill) throws Exception {
146    int nkilled = 0;
147    for (RegionInfo hri : AssignmentTestingUtil.getMetaRegions(UTIL)) {
148      ServerName serverName = AssignmentTestingUtil.crashRsWithRegion(UTIL, hri, kill);
149
150      // wait for region to enter in transition and then to get out of transition
151      AssignmentTestingUtil.waitForRegionToBeInTransition(UTIL, hri);
152      UTIL.waitUntilNoRegionsInTransition();
153      testGet(hri, 10);
154
155      // region should be moved to another RS
156      assertNotEquals(serverName, AssignmentTestingUtil.getServerHoldingRegion(UTIL, hri));
157
158      if (++nkilled == (NUM_RS - 1)) {
159        break;
160      }
161    }
162    assertTrue("expected RSs to be killed", nkilled > 0);
163  }
164
165  private void testInsert(final RegionInfo hri, final int nrows) throws IOException {
166    final Table table = UTIL.getConnection().getTable(hri.getTable());
167    for (int i = 0; i < nrows; ++i) {
168      final byte[] row = Bytes.add(hri.getStartKey(), Bytes.toBytes(i));
169      final Put put = new Put(row);
170      put.addColumn(FAMILY, null, row);
171      table.put(put);
172    }
173  }
174
175  public int testGet(final RegionInfo hri, final int nrows) throws IOException {
176    int nresults = 0;
177    final Table table = UTIL.getConnection().getTable(hri.getTable());
178    for (int i = 0; i < nrows; ++i) {
179      final byte[] row = Bytes.add(hri.getStartKey(), Bytes.toBytes(i));
180      final Result result = table.get(new Get(row));
181      if (result != null && !result.isEmpty() && Bytes.equals(row, result.getValue(FAMILY, null))) {
182        nresults++;
183      }
184    }
185    return nresults;
186  }
187}