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.rsgroup;
019
020import static org.junit.jupiter.api.Assertions.assertTrue;
021
022import java.io.IOException;
023import java.util.Collections;
024import org.apache.hadoop.conf.Configuration;
025import org.apache.hadoop.hbase.HBaseTestingUtil;
026import org.apache.hadoop.hbase.HConstants;
027import org.apache.hadoop.hbase.TableName;
028import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
029import org.apache.hadoop.hbase.client.TableDescriptor;
030import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
031import org.apache.hadoop.hbase.master.assignment.AssignmentTestingUtil;
032import org.apache.hadoop.hbase.net.Address;
033import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility;
034import org.apache.hadoop.hbase.testclassification.MediumTests;
035import org.apache.hadoop.hbase.testclassification.RSGroupTests;
036import org.apache.hadoop.hbase.util.Bytes;
037import org.apache.hadoop.hbase.util.JVMClusterUtil;
038import org.apache.hadoop.hbase.util.Threads;
039import org.junit.jupiter.api.AfterAll;
040import org.junit.jupiter.api.AfterEach;
041import org.junit.jupiter.api.BeforeAll;
042import org.junit.jupiter.api.BeforeEach;
043import org.junit.jupiter.api.Tag;
044import org.junit.jupiter.api.Test;
045import org.junit.jupiter.api.TestInfo;
046import org.slf4j.Logger;
047import org.slf4j.LoggerFactory;
048
049@Tag(RSGroupTests.TAG)
050@Tag(MediumTests.TAG)
051public class TestRSGroupsFallback extends TestRSGroupsBase {
052
053  protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsFallback.class);
054
055  private static final String FALLBACK_GROUP = "fallback";
056
057  @BeforeAll
058  public static void setUp() throws Exception {
059    Configuration conf = TEST_UTIL.getConfiguration();
060    conf.setBoolean(RSGroupBasedLoadBalancer.FALLBACK_GROUP_ENABLE_KEY, true);
061    conf.setInt(HConstants.HBASE_BALANCER_MAX_BALANCING, 0);
062    setUpTestBeforeClass();
063    MASTER.balanceSwitch(true);
064  }
065
066  @AfterAll
067  public static void tearDown() throws Exception {
068    tearDownAfterClass();
069  }
070
071  @BeforeEach
072  public void beforeMethod(TestInfo testInfo) throws Exception {
073    setUpBeforeMethod(testInfo);
074  }
075
076  @AfterEach
077  public void afterMethod() throws Exception {
078    tearDownAfterMethod();
079  }
080
081  @Test
082  public void testFallback() throws Exception {
083    // add fallback group
084    addGroup(FALLBACK_GROUP, 1);
085    // add test group
086    String groupName = getGroupName(name.getMethodName());
087    addGroup(groupName, 1);
088    TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
089      .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("f")).build())
090      .setRegionServerGroup(groupName).build();
091    ADMIN.createTable(desc, HBaseTestingUtil.KEYS_FOR_HBA_CREATE_TABLE);
092    TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
093    // server of test group crash, regions move to default group
094    crashRsInGroup(groupName);
095    assertRegionsInGroup(tableName, RSGroupInfo.DEFAULT_GROUP);
096
097    // server of default group crash, regions move to any other group
098    crashRsInGroup(RSGroupInfo.DEFAULT_GROUP);
099    assertRegionsInGroup(tableName, FALLBACK_GROUP);
100
101    // add a new server to default group, regions move to default group
102    TEST_UTIL.getMiniHBaseCluster().startRegionServerAndWait(60000);
103    assertTrue(MASTER.balance().isBalancerRan());
104    assertRegionsInGroup(tableName, RSGroupInfo.DEFAULT_GROUP);
105
106    // add a new server to test group, regions move back
107    JVMClusterUtil.RegionServerThread t =
108      TEST_UTIL.getMiniHBaseCluster().startRegionServerAndWait(60000);
109    ADMIN.moveServersToRSGroup(
110      Collections.singleton(t.getRegionServer().getServerName().getAddress()), groupName);
111    assertTrue(MASTER.balance().isBalancerRan());
112    assertRegionsInGroup(tableName, groupName);
113
114    TEST_UTIL.deleteTable(tableName);
115  }
116
117  private void assertRegionsInGroup(TableName table, String group) throws IOException {
118    ProcedureTestingUtility
119      .waitAllProcedures(TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor());
120    RSGroupInfo rsGroup = ADMIN.getRSGroup(group);
121    MASTER.getAssignmentManager().getRegionStates().getRegionsOfTable(table).forEach(region -> {
122      Address regionOnServer = MASTER.getAssignmentManager().getRegionStates()
123        .getRegionAssignments().get(region).getAddress();
124      assertTrue(rsGroup.getServers().contains(regionOnServer));
125    });
126  }
127
128  private void crashRsInGroup(String groupName) throws Exception {
129    for (Address server : ADMIN.getRSGroup(groupName).getServers()) {
130      AssignmentTestingUtil.crashRs(TEST_UTIL, getServerName(server), true);
131    }
132    Threads.sleep(1000);
133    TEST_UTIL.waitUntilNoRegionsInTransition(60000);
134  }
135}