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.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023
024import java.io.IOException;
025import java.util.List;
026import java.util.Set;
027import org.apache.hadoop.hbase.NamespaceDescriptor;
028import org.apache.hadoop.hbase.ServerName;
029import org.apache.hadoop.hbase.TableName;
030import org.apache.hadoop.hbase.Waiter;
031import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
032import org.apache.hadoop.hbase.client.TableDescriptor;
033import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
034import org.apache.hadoop.hbase.net.Address;
035import org.apache.hadoop.hbase.quotas.QuotaTableUtil;
036import org.apache.hadoop.hbase.testclassification.MediumTests;
037import org.apache.hadoop.hbase.testclassification.RSGroupTests;
038import org.apache.hadoop.hbase.util.Bytes;
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
049import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
050
051@Tag(RSGroupTests.TAG)
052@Tag(MediumTests.TAG)
053public class TestRSGroupsBasics extends TestRSGroupsBase {
054
055  protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsBasics.class);
056
057  @BeforeAll
058  public static void setUp() throws Exception {
059    setUpTestBeforeClass();
060  }
061
062  @AfterAll
063  public static void tearDown() throws Exception {
064    tearDownAfterClass();
065  }
066
067  @BeforeEach
068  public void beforeMethod(TestInfo testInfo) throws Exception {
069    setUpBeforeMethod(testInfo);
070  }
071
072  @AfterEach
073  public void afterMethod() throws Exception {
074    tearDownAfterMethod();
075  }
076
077  @Test
078  public void testBasicStartUp() throws IOException {
079    RSGroupInfo defaultInfo = ADMIN.getRSGroup(RSGroupInfo.DEFAULT_GROUP);
080    assertEquals(NUM_SLAVES_BASE, defaultInfo.getServers().size());
081    // Assignment of meta and rsgroup regions.
082    int count = MASTER.getAssignmentManager().getRegionStates().getRegionAssignments().size();
083    LOG.info("regions assignments are"
084      + MASTER.getAssignmentManager().getRegionStates().getRegionAssignments().toString());
085    // 2 (meta and rsgroup)
086    assertEquals(2, count);
087  }
088
089  @Test
090  public void testCreateAndDrop() throws Exception {
091    TEST_UTIL.createTable(tableName, Bytes.toBytes("cf"));
092    // wait for created table to be assigned
093    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
094      @Override
095      public boolean evaluate() throws Exception {
096        return getTableRegionMap().get(tableName) != null;
097      }
098    });
099    TEST_UTIL.deleteTable(tableName);
100  }
101
102  @Test
103  public void testCreateMultiRegion() throws IOException {
104    byte[] end = { 1, 3, 5, 7, 9 };
105    byte[] start = { 0, 2, 4, 6, 8 };
106    byte[][] f = { Bytes.toBytes("f") };
107    TEST_UTIL.createTable(tableName, f, 1, start, end, 10);
108  }
109
110  @Test
111  public void testNamespaceCreateAndAssign() throws Exception {
112    LOG.info("testNamespaceCreateAndAssign");
113    String nsName = TABLE_PREFIX + "_foo";
114    final TableName tableName = TableName.valueOf(nsName, TABLE_PREFIX + "_testCreateAndAssign");
115    RSGroupInfo appInfo = addGroup("appInfo", 1);
116    ADMIN.createNamespace(NamespaceDescriptor.create(nsName)
117      .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "appInfo").build());
118    final TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
119      .setColumnFamily(ColumnFamilyDescriptorBuilder.of("f")).build();
120    ADMIN.createTable(desc);
121    // wait for created table to be assigned
122    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
123      @Override
124      public boolean evaluate() throws Exception {
125        return getTableRegionMap().get(desc.getTableName()) != null;
126      }
127    });
128    ServerName targetServer = getServerName(appInfo.getServers().iterator().next());
129    // verify it was assigned to the right group
130    assertEquals(1, ADMIN.getRegions(targetServer).size());
131  }
132
133  @Test
134  public void testDefaultNamespaceCreateAndAssign() throws Exception {
135    LOG.info("testDefaultNamespaceCreateAndAssign");
136    String tableName = TABLE_PREFIX + "_testCreateAndAssign";
137    ADMIN.modifyNamespace(NamespaceDescriptor.create("default")
138      .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "default").build());
139    final TableDescriptor desc = TableDescriptorBuilder.newBuilder(TableName.valueOf(tableName))
140      .setColumnFamily(ColumnFamilyDescriptorBuilder.of("f")).build();
141    ADMIN.createTable(desc);
142    // wait for created table to be assigned
143    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
144      @Override
145      public boolean evaluate() throws Exception {
146        return getTableRegionMap().get(desc.getTableName()) != null;
147      }
148    });
149  }
150
151  @Test
152  public void testCloneSnapshot() throws Exception {
153    byte[] FAMILY = Bytes.toBytes("test");
154    String snapshotName = tableName.getNameAsString() + "_snap";
155    TableName clonedTableName = TableName.valueOf(tableName.getNameAsString() + "_clone");
156
157    // create base table
158    TEST_UTIL.createTable(tableName, FAMILY);
159
160    // create snapshot
161    ADMIN.snapshot(snapshotName, tableName);
162
163    // clone
164    ADMIN.cloneSnapshot(snapshotName, clonedTableName);
165    ADMIN.deleteSnapshot(snapshotName);
166  }
167
168  @Test
169  public void testClearDeadServers() throws Exception {
170    LOG.info("testClearDeadServers");
171
172    // move region servers from default group to new group
173    final int serverCountToMoveToNewGroup = 3;
174    final RSGroupInfo newGroup =
175      addGroup(getGroupName(name.getMethodName()), serverCountToMoveToNewGroup);
176
177    // get the existing dead servers
178    NUM_DEAD_SERVERS = CLUSTER.getClusterMetrics().getDeadServerNames().size();
179
180    // stop 1 region server in new group
181    ServerName serverToStop = getServerName(newGroup.getServers().iterator().next());
182    try {
183      // stopping may cause an exception
184      // due to the connection loss
185      ADMIN.stopRegionServer(serverToStop.getAddress().toString());
186      NUM_DEAD_SERVERS++;
187    } catch (Exception e) {
188    }
189
190    // wait for stopped regionserver to dead server list
191    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
192      @Override
193      public boolean evaluate() throws Exception {
194        return CLUSTER.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS
195          && !MASTER.getServerManager().areDeadServersInProgress();
196      }
197    });
198    assertFalse(CLUSTER.getClusterMetrics().getLiveServerMetrics().containsKey(serverToStop));
199    assertTrue(CLUSTER.getClusterMetrics().getDeadServerNames().contains(serverToStop));
200    assertTrue(newGroup.getServers().contains(serverToStop.getAddress()));
201
202    // clear dead servers list
203    List<ServerName> notClearedServers = ADMIN.clearDeadServers(Lists.newArrayList(serverToStop));
204    assertEquals(0, notClearedServers.size());
205
206    // the stopped region server gets cleared and removed from the group
207    Set<Address> newGroupServers = ADMIN.getRSGroup(newGroup.getName()).getServers();
208    assertFalse(newGroupServers.contains(serverToStop.getAddress()));
209    assertEquals(serverCountToMoveToNewGroup - 1 /* 1 stopped */, newGroupServers.size());
210  }
211
212  @Test
213  public void testClearNotProcessedDeadServer() throws Exception {
214    LOG.info("testClearNotProcessedDeadServer");
215
216    // get the existing dead servers
217    NUM_DEAD_SERVERS = CLUSTER.getClusterMetrics().getDeadServerNames().size();
218
219    // move region servers from default group to "dead server" group
220    final int serverCountToMoveToDeadServerGroup = 1;
221    RSGroupInfo deadServerGroup = addGroup("deadServerGroup", serverCountToMoveToDeadServerGroup);
222
223    // stop 1 region servers in "dead server" group
224    ServerName serverToStop = getServerName(deadServerGroup.getServers().iterator().next());
225    try {
226      // stopping may cause an exception
227      // due to the connection loss
228      ADMIN.stopRegionServer(serverToStop.getAddress().toString());
229      NUM_DEAD_SERVERS++;
230    } catch (Exception e) {
231    }
232    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
233      @Override
234      public boolean evaluate() throws Exception {
235        return CLUSTER.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS;
236      }
237    });
238
239    Set<Address> ServersInDeadServerGroup =
240      ADMIN.getRSGroup(deadServerGroup.getName()).getServers();
241    assertEquals(serverCountToMoveToDeadServerGroup, ServersInDeadServerGroup.size());
242    assertTrue(ServersInDeadServerGroup.contains(serverToStop.getAddress()));
243  }
244
245  @Test
246  public void testRSGroupsWithHBaseQuota() throws Exception {
247    toggleQuotaCheckAndRestartMiniCluster(true);
248    TEST_UTIL.waitFor(90000, new Waiter.Predicate<Exception>() {
249      @Override
250      public boolean evaluate() throws Exception {
251        return ADMIN.isTableAvailable(QuotaTableUtil.QUOTA_TABLE_NAME);
252      }
253    });
254    toggleQuotaCheckAndRestartMiniCluster(false);
255  }
256}