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.Optional;
022import java.util.concurrent.CountDownLatch;
023import org.apache.hadoop.hbase.HBaseClassTestRule;
024import org.apache.hadoop.hbase.HBaseTestingUtil;
025import org.apache.hadoop.hbase.TableName;
026import org.apache.hadoop.hbase.client.RegionInfo;
027import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
028import org.apache.hadoop.hbase.coprocessor.ObserverContext;
029import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor;
030import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
031import org.apache.hadoop.hbase.coprocessor.RegionObserver;
032import org.apache.hadoop.hbase.master.assignment.RegionStateNode;
033import org.apache.hadoop.hbase.master.assignment.TransitRegionStateProcedure;
034import org.apache.hadoop.hbase.regionserver.HRegionServer;
035import org.apache.hadoop.hbase.testclassification.MasterTests;
036import org.apache.hadoop.hbase.testclassification.MediumTests;
037import org.apache.hadoop.hbase.util.Bytes;
038import org.apache.hadoop.hbase.util.JVMClusterUtil;
039import org.apache.hadoop.hbase.util.Threads;
040import org.junit.AfterClass;
041import org.junit.Assert;
042import org.junit.BeforeClass;
043import org.junit.ClassRule;
044import org.junit.Test;
045import org.junit.experimental.categories.Category;
046import org.slf4j.Logger;
047import org.slf4j.LoggerFactory;
048
049@Category({ MasterTests.class, MediumTests.class })
050public class TestMasterAbortAndRSGotKilled {
051  private static Logger LOG =
052    LoggerFactory.getLogger(TestMasterAbortAndRSGotKilled.class.getName());
053
054  @ClassRule
055  public static final HBaseClassTestRule CLASS_RULE =
056    HBaseClassTestRule.forClass(TestMasterAbortAndRSGotKilled.class);
057
058  private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
059
060  private static TableName TABLE_NAME = TableName.valueOf("test");
061
062  private static CountDownLatch countDownLatch = new CountDownLatch(1);
063
064  private static byte[] CF = Bytes.toBytes("cf");
065
066  @BeforeClass
067  public static void setUp() throws Exception {
068    UTIL.getConfiguration().setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
069      DelayCloseCP.class.getName());
070    UTIL.startMiniCluster(3);
071    UTIL.getAdmin().balancerSwitch(false, true);
072    UTIL.createTable(TABLE_NAME, CF);
073    UTIL.waitTableAvailable(TABLE_NAME);
074  }
075
076  @AfterClass
077  public static void tearDown() throws Exception {
078    UTIL.shutdownMiniCluster();
079  }
080
081  @Test
082  public void test() throws Exception {
083    JVMClusterUtil.RegionServerThread rsThread = null;
084    for (JVMClusterUtil.RegionServerThread t : UTIL.getMiniHBaseCluster()
085      .getRegionServerThreads()) {
086      if (!t.getRegionServer().getRegions(TABLE_NAME).isEmpty()) {
087        rsThread = t;
088        break;
089      }
090    }
091    // find the rs and hri of the table
092    HRegionServer rs = rsThread.getRegionServer();
093    RegionInfo hri = rs.getRegions(TABLE_NAME).get(0).getRegionInfo();
094    TransitRegionStateProcedure moveRegionProcedure = TransitRegionStateProcedure.reopen(
095      UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor().getEnvironment(), hri);
096    RegionStateNode regionNode = UTIL.getMiniHBaseCluster().getMaster().getAssignmentManager()
097      .getRegionStates().getOrCreateRegionStateNode(hri);
098    regionNode.setProcedure(moveRegionProcedure);
099    UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor()
100      .submitProcedure(moveRegionProcedure);
101    countDownLatch.await();
102    UTIL.getMiniHBaseCluster().stopMaster(0);
103    UTIL.getMiniHBaseCluster().startMaster();
104    // wait until master initialized
105    UTIL.waitFor(30000, () -> UTIL.getMiniHBaseCluster().getMaster() != null
106      && UTIL.getMiniHBaseCluster().getMaster().isInitialized());
107    Assert.assertTrue("Should be 3 RS after master restart",
108      UTIL.getMiniHBaseCluster().getLiveRegionServerThreads().size() == 3);
109
110  }
111
112  public static class DelayCloseCP implements RegionCoprocessor, RegionObserver {
113
114    @Override
115    public void preClose(ObserverContext<? extends RegionCoprocessorEnvironment> c,
116      boolean abortRequested) throws IOException {
117      if (!c.getEnvironment().getRegion().getRegionInfo().getTable().isSystemTable()) {
118        LOG.info("begin to sleep");
119        countDownLatch.countDown();
120        // Sleep here so we can stuck the RPC call
121        Threads.sleep(10000);
122        LOG.info("finish sleep");
123      }
124    }
125
126    @Override
127    public Optional<RegionObserver> getRegionObserver() {
128      return Optional.of(this);
129    }
130  }
131}