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.Assert.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertTrue;
023import static org.junit.Assert.fail;
024
025import java.io.IOException;
026import java.util.ArrayList;
027import java.util.Iterator;
028import java.util.List;
029import java.util.Set;
030import org.apache.hadoop.hbase.HBaseClassTestRule;
031import org.apache.hadoop.hbase.NamespaceDescriptor;
032import org.apache.hadoop.hbase.ServerName;
033import org.apache.hadoop.hbase.TableName;
034import org.apache.hadoop.hbase.Waiter;
035import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
036import org.apache.hadoop.hbase.client.TableDescriptor;
037import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
038import org.apache.hadoop.hbase.net.Address;
039import org.apache.hadoop.hbase.quotas.QuotaTableUtil;
040import org.apache.hadoop.hbase.quotas.QuotaUtil;
041import org.apache.hadoop.hbase.testclassification.MediumTests;
042import org.apache.hadoop.hbase.util.Bytes;
043import org.junit.After;
044import org.junit.AfterClass;
045import org.junit.Assert;
046import org.junit.Before;
047import org.junit.BeforeClass;
048import org.junit.ClassRule;
049import org.junit.Test;
050import org.junit.experimental.categories.Category;
051import org.slf4j.Logger;
052import org.slf4j.LoggerFactory;
053
054import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
055
056@Category({ MediumTests.class })
057public class TestRSGroupsBasics extends TestRSGroupsBase {
058
059  @ClassRule
060  public static final HBaseClassTestRule CLASS_RULE =
061    HBaseClassTestRule.forClass(TestRSGroupsBasics.class);
062
063  protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsBasics.class);
064
065  @BeforeClass
066  public static void setUp() throws Exception {
067    setUpTestBeforeClass();
068  }
069
070  @AfterClass
071  public static void tearDown() throws Exception {
072    tearDownAfterClass();
073  }
074
075  @Before
076  public void beforeMethod() throws Exception {
077    setUpBeforeMethod();
078  }
079
080  @After
081  public void afterMethod() throws Exception {
082    tearDownAfterMethod();
083  }
084
085  @Test
086  public void testBasicStartUp() throws IOException {
087    RSGroupInfo defaultInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
088    assertEquals(NUM_SLAVES_BASE, defaultInfo.getServers().size());
089    // Assignment of meta, namespace and rsgroup regions.
090    int count = master.getAssignmentManager().getRegionStates().getRegionAssignments().size();
091    // 3 (meta, namespace and rsgroup)
092    assertEquals(3, count);
093  }
094
095  @Test
096  public void testCreateAndDrop() throws Exception {
097    TEST_UTIL.createTable(tableName, Bytes.toBytes("cf"));
098    // wait for created table to be assigned
099    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
100      @Override
101      public boolean evaluate() throws Exception {
102        return getTableRegionMap().get(tableName) != null;
103      }
104    });
105    TEST_UTIL.deleteTable(tableName);
106  }
107
108  @Test
109  public void testCreateMultiRegion() throws IOException {
110    byte[] end = { 1, 3, 5, 7, 9 };
111    byte[] start = { 0, 2, 4, 6, 8 };
112    byte[][] f = { Bytes.toBytes("f") };
113    TEST_UTIL.createTable(tableName, f, 1, start, end, 10);
114  }
115
116  @Test
117  public void testNamespaceCreateAndAssign() throws Exception {
118    LOG.info("testNamespaceCreateAndAssign");
119    String nsName = tablePrefix + "_foo";
120    final TableName tableName = TableName.valueOf(nsName, tablePrefix + "_testCreateAndAssign");
121    RSGroupInfo appInfo = addGroup("appInfo", 1);
122    admin.createNamespace(NamespaceDescriptor.create(nsName)
123      .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "appInfo").build());
124    final TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
125      .setColumnFamily(ColumnFamilyDescriptorBuilder.of("f")).build();
126    admin.createTable(desc);
127    // wait for created table to be assigned
128    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
129      @Override
130      public boolean evaluate() throws Exception {
131        return getTableRegionMap().get(desc.getTableName()) != null;
132      }
133    });
134    ServerName targetServer = getServerName(appInfo.getServers().iterator().next());
135    // verify it was assigned to the right group
136    Assert.assertEquals(1, admin.getRegions(targetServer).size());
137  }
138
139  @Test
140  public void testCreateWhenRsgroupNoOnlineServers() throws Exception {
141    LOG.info("testCreateWhenRsgroupNoOnlineServers");
142
143    // set rsgroup has no online servers and test create table
144    final RSGroupInfo appInfo = addGroup("appInfo", 1);
145    Iterator<Address> iterator = appInfo.getServers().iterator();
146    List<ServerName> serversToDecommission = new ArrayList<>();
147    ServerName targetServer = getServerName(iterator.next());
148    assertTrue(master.getServerManager().getOnlineServers().containsKey(targetServer));
149    serversToDecommission.add(targetServer);
150    admin.decommissionRegionServers(serversToDecommission, true);
151    assertEquals(1, admin.listDecommissionedRegionServers().size());
152
153    final TableName tableName = TableName.valueOf(tablePrefix + "_ns", name.getMethodName());
154    admin.createNamespace(NamespaceDescriptor.create(tableName.getNamespaceAsString())
155      .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, appInfo.getName()).build());
156    final TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
157      .setColumnFamily(ColumnFamilyDescriptorBuilder.of("f")).build();
158    try {
159      admin.createTable(desc);
160      fail("Shouldn't create table successfully!");
161    } catch (Exception e) {
162      LOG.debug("create table error", e);
163    }
164
165    // recommission and test create table
166    admin.recommissionRegionServer(targetServer, null);
167    assertEquals(0, admin.listDecommissionedRegionServers().size());
168    admin.createTable(desc);
169    // wait for created table to be assigned
170    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
171      @Override
172      public boolean evaluate() throws Exception {
173        return getTableRegionMap().get(desc.getTableName()) != null;
174      }
175    });
176  }
177
178  @Test
179  public void testDefaultNamespaceCreateAndAssign() throws Exception {
180    LOG.info("testDefaultNamespaceCreateAndAssign");
181    String tableName = tablePrefix + "_testCreateAndAssign";
182    admin.modifyNamespace(NamespaceDescriptor.create("default")
183      .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "default").build());
184    final TableDescriptor desc = TableDescriptorBuilder.newBuilder(TableName.valueOf(tableName))
185      .setColumnFamily(ColumnFamilyDescriptorBuilder.of("f")).build();
186    admin.createTable(desc);
187    // wait for created table to be assigned
188    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
189      @Override
190      public boolean evaluate() throws Exception {
191        return getTableRegionMap().get(desc.getTableName()) != null;
192      }
193    });
194  }
195
196  @Test
197  public void testCloneSnapshot() throws Exception {
198    byte[] FAMILY = Bytes.toBytes("test");
199    String snapshotName = tableName.getNameAsString() + "_snap";
200    TableName clonedTableName = TableName.valueOf(tableName.getNameAsString() + "_clone");
201
202    // create base table
203    TEST_UTIL.createTable(tableName, FAMILY);
204
205    // create snapshot
206    admin.snapshot(snapshotName, tableName);
207
208    // clone
209    admin.cloneSnapshot(snapshotName, clonedTableName);
210  }
211
212  @Test
213  public void testClearDeadServers() throws Exception {
214    LOG.info("testClearDeadServers");
215
216    // move region servers from default group to new group
217    final int serverCountToMoveToNewGroup = 3;
218    final RSGroupInfo newGroup =
219        addGroup(getGroupName(name.getMethodName()), serverCountToMoveToNewGroup);
220
221    // get the existing dead servers
222    NUM_DEAD_SERVERS = cluster.getClusterMetrics().getDeadServerNames().size();
223
224    // stop 1 region server in new group
225    ServerName serverToStop = getServerName(newGroup.getServers().iterator().next());
226    try {
227      // stopping may cause an exception
228      // due to the connection loss
229      admin.stopRegionServer(serverToStop.getAddress().toString());
230      NUM_DEAD_SERVERS++;
231    } catch (Exception e) {
232    }
233
234    // wait for the stopped region server to show up in the dead server list
235    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
236      @Override
237      public boolean evaluate() throws Exception {
238        return cluster.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS &&
239          !master.getServerManager().areDeadServersInProgress();
240      }
241    });
242
243    // verify
244    assertFalse(cluster.getClusterMetrics().getLiveServerMetrics().containsKey(serverToStop));
245    assertTrue(cluster.getClusterMetrics().getDeadServerNames().contains(serverToStop));
246    assertTrue(newGroup.getServers().contains(serverToStop.getAddress()));
247
248    // clear dead servers list
249    List<ServerName> notClearedServers = admin.clearDeadServers(Lists.newArrayList(serverToStop));
250    assertEquals(0, notClearedServers.size());
251
252    // verify if the stopped region server gets cleared and removed from the group
253    Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
254    assertFalse(newGroupServers.contains(serverToStop.getAddress()));
255    assertEquals(serverCountToMoveToNewGroup - 1 /* 1 stopped */, newGroupServers.size());
256  }
257
258  @Test
259  public void testClearNotProcessedDeadServer() throws Exception {
260    LOG.info("testClearNotProcessedDeadServer");
261
262    // get the existing dead servers
263    NUM_DEAD_SERVERS = cluster.getClusterMetrics().getDeadServerNames().size();
264
265    // move region servers from default group to "dead server" group
266    final int serverCountToMoveToDeadServerGroup = 1;
267    RSGroupInfo deadServerGroup =
268        addGroup("deadServerGroup", serverCountToMoveToDeadServerGroup);
269
270    // stop 1 region server in "dead server" group
271    ServerName serverToStop = getServerName(deadServerGroup.getServers().iterator().next());
272    try {
273      // stopping may cause an exception
274      // due to the connection loss
275      admin.stopRegionServer(serverToStop.getAddress().toString());
276      NUM_DEAD_SERVERS++;
277    } catch (Exception e) {
278    }
279    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
280      @Override
281      public boolean evaluate() throws Exception {
282        return cluster.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS;
283      }
284    });
285
286    Set<Address> ServersInDeadServerGroup =
287        rsGroupAdmin.getRSGroupInfo(deadServerGroup.getName()).getServers();
288    assertEquals(serverCountToMoveToDeadServerGroup, ServersInDeadServerGroup.size());
289    assertTrue(ServersInDeadServerGroup.contains(serverToStop.getAddress()));
290  }
291
292  @Test
293  public void testRSGroupsWithHBaseQuota() throws Exception {
294    TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, true);
295    restartHBaseCluster();
296    try {
297      TEST_UTIL.waitFor(90000, new Waiter.Predicate<Exception>() {
298        @Override
299        public boolean evaluate() throws Exception {
300          return admin.isTableAvailable(QuotaTableUtil.QUOTA_TABLE_NAME);
301        }
302      });
303    } finally {
304      TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, false);
305      restartHBaseCluster();
306    }
307  }
308
309  private void restartHBaseCluster() throws Exception {
310    LOG.info("\n\nShutting down cluster");
311    TEST_UTIL.shutdownMiniHBaseCluster();
312    LOG.info("\n\nSleeping a bit");
313    Thread.sleep(2000);
314    TEST_UTIL.restartHBaseCluster(NUM_SLAVES_BASE - 1);
315    initialize();
316  }
317}