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.regionserver;
019
020import static org.junit.jupiter.api.Assertions.assertTrue;
021import static org.junit.jupiter.api.Assertions.fail;
022
023import java.io.IOException;
024import java.util.List;
025import java.util.stream.Collectors;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.DoNotRetryIOException;
028import org.apache.hadoop.hbase.HBaseTestingUtil;
029import org.apache.hadoop.hbase.TableName;
030import org.apache.hadoop.hbase.client.Admin;
031import org.apache.hadoop.hbase.client.DoNotRetryRegionException;
032import org.apache.hadoop.hbase.client.Put;
033import org.apache.hadoop.hbase.client.RegionInfo;
034import org.apache.hadoop.hbase.client.Table;
035import org.apache.hadoop.hbase.testclassification.MediumTests;
036import org.apache.hadoop.hbase.util.Bytes;
037import org.junit.jupiter.api.AfterAll;
038import org.junit.jupiter.api.BeforeAll;
039import org.junit.jupiter.api.BeforeEach;
040import org.junit.jupiter.api.Tag;
041import org.junit.jupiter.api.Test;
042import org.junit.jupiter.api.TestInfo;
043
044/**
045 * Test move fails when table disabled
046 */
047@Tag(MediumTests.TAG)
048public class TestRegionMove {
049
050  private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
051  public static Configuration CONF;
052  protected static final String F1 = "f1";
053
054  // Test names
055  protected TableName tableName;
056  protected String method;
057
058  @BeforeAll
059  public static void startCluster() throws Exception {
060    TEST_UTIL.startMiniCluster(2);
061  }
062
063  @AfterAll
064  public static void stopCluster() throws Exception {
065    TEST_UTIL.shutdownMiniCluster();
066  }
067
068  @BeforeEach
069  public void setup(TestInfo testInfo) throws IOException {
070    CONF = TEST_UTIL.getConfiguration();
071    method = testInfo.getTestMethod().get().getName();
072    tableName = TableName.valueOf(method);
073  }
074
075  @Test
076  public void testDisableAndMove() throws Exception {
077    Admin admin = TEST_UTIL.getAdmin();
078
079    // Create a table with more than one region
080    Table t = TEST_UTIL.createMultiRegionTable(tableName, Bytes.toBytes(F1), 10);
081    TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
082
083    // Write an update to each region
084    for (RegionInfo regionInfo : admin.getRegions(tableName)) {
085      byte[] startKey = regionInfo.getStartKey();
086      // The startKey of the first region is "empty", which would throw an error if we try to
087      // Put that.
088      byte[] rowKey = org.apache.hbase.thirdparty.com.google.common.primitives.Bytes
089        .concat(startKey, Bytes.toBytes("1"));
090      Put p = new Put(rowKey);
091      p.addColumn(Bytes.toBytes(F1), Bytes.toBytes("q1"), Bytes.toBytes("value"));
092      t.put(p);
093    }
094
095    // Get a Region which is on the first RS
096    HRegionServer rs1 = TEST_UTIL.getRSForFirstRegionInTable(tableName);
097    HRegionServer rs2 = TEST_UTIL.getOtherRegionServer(rs1);
098    List<RegionInfo> regionsOnRS1ForTable = admin.getRegions(rs1.getServerName()).stream()
099      .filter((regionInfo) -> regionInfo.getTable().equals(tableName)).collect(Collectors.toList());
100    assertTrue(!regionsOnRS1ForTable.isEmpty(), "Expected to find at least one region for "
101      + tableName + " on " + rs1.getServerName() + ", but found none");
102    final RegionInfo regionToMove = regionsOnRS1ForTable.get(0);
103
104    // Offline the region and then try to move it. Should fail.
105    admin.unassign(regionToMove.getRegionName(), true);
106    try {
107      admin.move(regionToMove.getEncodedNameAsBytes(), rs2.getServerName());
108      fail();
109    } catch (DoNotRetryRegionException e) {
110      // We got expected exception
111    }
112    // Reassign for next stage of test.
113    admin.assign(regionToMove.getRegionName());
114
115    // Disable the table
116    admin.disableTable(tableName);
117
118    try {
119      // Move the region to the other RS -- should fail
120      admin.move(regionToMove.getEncodedNameAsBytes(), rs2.getServerName());
121      fail();
122    } catch (DoNotRetryIOException e) {
123      // We got expected exception
124    }
125  }
126}