2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.rsgroup
;
20 import static org
.junit
.Assert
.assertEquals
;
21 import static org
.junit
.Assert
.assertFalse
;
22 import static org
.junit
.Assert
.assertNull
;
23 import static org
.junit
.Assert
.assertTrue
;
24 import static org
.junit
.Assert
.fail
;
26 import java
.io
.IOException
;
27 import java
.util
.Iterator
;
28 import java
.util
.List
;
31 import java
.util
.SortedSet
;
33 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
34 import org
.apache
.hadoop
.hbase
.MiniHBaseCluster
;
35 import org
.apache
.hadoop
.hbase
.NamespaceDescriptor
;
36 import org
.apache
.hadoop
.hbase
.ServerName
;
37 import org
.apache
.hadoop
.hbase
.TableExistsException
;
38 import org
.apache
.hadoop
.hbase
.TableName
;
39 import org
.apache
.hadoop
.hbase
.TableNotFoundException
;
40 import org
.apache
.hadoop
.hbase
.Waiter
;
41 import org
.apache
.hadoop
.hbase
.client
.ColumnFamilyDescriptor
;
42 import org
.apache
.hadoop
.hbase
.client
.ColumnFamilyDescriptorBuilder
;
43 import org
.apache
.hadoop
.hbase
.client
.TableDescriptor
;
44 import org
.apache
.hadoop
.hbase
.client
.TableDescriptorBuilder
;
45 import org
.apache
.hadoop
.hbase
.constraint
.ConstraintException
;
46 import org
.apache
.hadoop
.hbase
.master
.ServerManager
;
47 import org
.apache
.hadoop
.hbase
.master
.TableNamespaceManager
;
48 import org
.apache
.hadoop
.hbase
.master
.snapshot
.SnapshotManager
;
49 import org
.apache
.hadoop
.hbase
.net
.Address
;
50 import org
.apache
.hadoop
.hbase
.quotas
.QuotaUtil
;
51 import org
.apache
.hadoop
.hbase
.testclassification
.MediumTests
;
52 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
53 import org
.junit
.After
;
54 import org
.junit
.AfterClass
;
55 import org
.junit
.Assert
;
56 import org
.junit
.Before
;
57 import org
.junit
.BeforeClass
;
58 import org
.junit
.ClassRule
;
59 import org
.junit
.Test
;
60 import org
.junit
.experimental
.categories
.Category
;
61 import org
.slf4j
.Logger
;
62 import org
.slf4j
.LoggerFactory
;
64 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.collect
.Sets
;
66 @Category({ MediumTests
.class })
67 public class TestRSGroupsAdmin1
extends TestRSGroupsBase
{
70 public static final HBaseClassTestRule CLASS_RULE
=
71 HBaseClassTestRule
.forClass(TestRSGroupsAdmin1
.class);
73 protected static final Logger LOG
= LoggerFactory
.getLogger(TestRSGroupsAdmin1
.class);
76 public static void setUp() throws Exception
{
77 setUpTestBeforeClass();
81 public static void tearDown() throws Exception
{
86 public void beforeMethod() throws Exception
{
91 public void afterMethod() throws Exception
{
92 tearDownAfterMethod();
96 public void testValidGroupNames() throws IOException
{
97 String
[] badNames
= { "foo*", "foo@", "-" };
98 String
[] goodNames
= { "foo_123" };
100 for (String entry
: badNames
) {
102 rsGroupAdmin
.addRSGroup(entry
);
103 fail("Expected a constraint exception for: " + entry
);
104 } catch (ConstraintException ex
) {
109 for (String entry
: goodNames
) {
110 rsGroupAdmin
.addRSGroup(entry
);
115 public void testBogusArgs() throws Exception
{
116 assertNull(rsGroupAdmin
.getRSGroupInfoOfTable(TableName
.valueOf("nonexistent")));
117 assertNull(rsGroupAdmin
.getRSGroupOfServer(Address
.fromParts("bogus", 123)));
118 assertNull(rsGroupAdmin
.getRSGroupInfo("bogus"));
121 rsGroupAdmin
.removeRSGroup("bogus");
122 fail("Expected removing bogus group to fail");
123 } catch (ConstraintException ex
) {
128 rsGroupAdmin
.moveTables(Sets
.newHashSet(TableName
.valueOf("bogustable")), "bogus");
129 fail("Expected move with bogus group to fail");
130 } catch (ConstraintException
| TableNotFoundException ex
) {
135 rsGroupAdmin
.moveServers(Sets
.newHashSet(Address
.fromParts("bogus", 123)), "bogus");
136 fail("Expected move with bogus group to fail");
137 } catch (ConstraintException ex
) {
142 admin
.balancerSwitch(true, true);
143 rsGroupAdmin
.balanceRSGroup("bogus");
144 admin
.balancerSwitch(false, true);
145 fail("Expected move with bogus group to fail");
146 } catch (ConstraintException ex
) {
152 public void testNamespaceConstraint() throws Exception
{
153 String nsName
= tablePrefix
+ "_foo";
154 String groupName
= tablePrefix
+ "_foo";
155 LOG
.info("testNamespaceConstraint");
156 rsGroupAdmin
.addRSGroup(groupName
);
157 assertTrue(observer
.preAddRSGroupCalled
);
158 assertTrue(observer
.postAddRSGroupCalled
);
160 admin
.createNamespace(NamespaceDescriptor
.create(nsName
)
161 .addConfiguration(RSGroupInfo
.NAMESPACE_DESC_PROP_GROUP
, groupName
).build());
162 // test removing a referenced group
164 rsGroupAdmin
.removeRSGroup(groupName
);
165 fail("Expected a constraint exception");
166 } catch (IOException ex
) {
169 // changing with the same name is fine
170 admin
.modifyNamespace(NamespaceDescriptor
.create(nsName
)
171 .addConfiguration(RSGroupInfo
.NAMESPACE_DESC_PROP_GROUP
, groupName
).build());
172 String anotherGroup
= tablePrefix
+ "_anotherGroup";
173 rsGroupAdmin
.addRSGroup(anotherGroup
);
174 // test add non-existent group
175 admin
.deleteNamespace(nsName
);
176 rsGroupAdmin
.removeRSGroup(groupName
);
177 assertTrue(observer
.preRemoveRSGroupCalled
);
178 assertTrue(observer
.postRemoveRSGroupCalled
);
180 admin
.createNamespace(NamespaceDescriptor
.create(nsName
)
181 .addConfiguration(RSGroupInfo
.NAMESPACE_DESC_PROP_GROUP
, "foo").build());
182 fail("Expected a constraint exception");
183 } catch (IOException ex
) {
188 public void testGroupInfoMultiAccessing() throws Exception
{
189 RSGroupInfoManager manager
= rsGroupAdminEndpoint
.getGroupInfoManager();
190 RSGroupInfo defaultGroup
= manager
.getRSGroup("default");
191 // getRSGroup updates default group's server list
192 // this process must not affect other threads iterating the list
193 Iterator
<Address
> it
= defaultGroup
.getServers().iterator();
194 manager
.getRSGroup("default");
199 public void testGetRSGroupInfoCPHookCalled() throws Exception
{
200 rsGroupAdmin
.getRSGroupInfo(RSGroupInfo
.DEFAULT_GROUP
);
201 assertTrue(observer
.preGetRSGroupInfoCalled
);
202 assertTrue(observer
.postGetRSGroupInfoCalled
);
206 public void testGetRSGroupInfoOfTableCPHookCalled() throws Exception
{
207 rsGroupAdmin
.getRSGroupInfoOfTable(TableName
.META_TABLE_NAME
);
208 assertTrue(observer
.preGetRSGroupInfoOfTableCalled
);
209 assertTrue(observer
.postGetRSGroupInfoOfTableCalled
);
213 public void testListRSGroupsCPHookCalled() throws Exception
{
214 rsGroupAdmin
.listRSGroups();
215 assertTrue(observer
.preListRSGroupsCalled
);
216 assertTrue(observer
.postListRSGroupsCalled
);
220 public void testGetRSGroupInfoOfServerCPHookCalled() throws Exception
{
221 ServerName masterServerName
= ((MiniHBaseCluster
) cluster
).getMaster().getServerName();
222 rsGroupAdmin
.getRSGroupOfServer(masterServerName
.getAddress());
223 assertTrue(observer
.preGetRSGroupInfoOfServerCalled
);
224 assertTrue(observer
.postGetRSGroupInfoOfServerCalled
);
228 public void testFailRemoveGroup() throws IOException
, InterruptedException
{
229 int initNumGroups
= rsGroupAdmin
.listRSGroups().size();
231 TEST_UTIL
.createTable(tableName
, Bytes
.toBytes("f"));
232 rsGroupAdmin
.moveTables(Sets
.newHashSet(tableName
), "bar");
233 RSGroupInfo barGroup
= rsGroupAdmin
.getRSGroupInfo("bar");
234 // group is not empty therefore it should fail
236 rsGroupAdmin
.removeRSGroup(barGroup
.getName());
237 fail("Expected remove group to fail");
238 } catch (IOException e
) {
240 // group cannot lose all it's servers therefore it should fail
242 rsGroupAdmin
.moveServers(barGroup
.getServers(), RSGroupInfo
.DEFAULT_GROUP
);
243 fail("Expected move servers to fail");
244 } catch (IOException e
) {
247 rsGroupAdmin
.moveTables(barGroup
.getTables(), RSGroupInfo
.DEFAULT_GROUP
);
249 rsGroupAdmin
.removeRSGroup(barGroup
.getName());
250 fail("Expected move servers to fail");
251 } catch (IOException e
) {
254 rsGroupAdmin
.moveServers(barGroup
.getServers(), RSGroupInfo
.DEFAULT_GROUP
);
255 rsGroupAdmin
.removeRSGroup(barGroup
.getName());
257 Assert
.assertEquals(initNumGroups
, rsGroupAdmin
.listRSGroups().size());
261 public void testMultiTableMove() throws Exception
{
262 final TableName tableNameA
= TableName
.valueOf(tablePrefix
+ name
.getMethodName() + "A");
263 final TableName tableNameB
= TableName
.valueOf(tablePrefix
+ name
.getMethodName() + "B");
264 final byte[] familyNameBytes
= Bytes
.toBytes("f");
265 String newGroupName
= getGroupName(name
.getMethodName());
266 final RSGroupInfo newGroup
= addGroup(newGroupName
, 1);
268 TEST_UTIL
.createTable(tableNameA
, familyNameBytes
);
269 TEST_UTIL
.createTable(tableNameB
, familyNameBytes
);
270 TEST_UTIL
.waitFor(WAIT_TIMEOUT
, new Waiter
.Predicate
<Exception
>() {
272 public boolean evaluate() throws Exception
{
273 List
<String
> regionsA
= getTableRegionMap().get(tableNameA
);
274 if (regionsA
== null) {
277 List
<String
> regionsB
= getTableRegionMap().get(tableNameB
);
278 if (regionsB
== null) {
281 return getTableRegionMap().get(tableNameA
).size() >= 1 &&
282 getTableRegionMap().get(tableNameB
).size() >= 1;
286 RSGroupInfo tableGrpA
= rsGroupAdmin
.getRSGroupInfoOfTable(tableNameA
);
287 assertTrue(tableGrpA
.getName().equals(RSGroupInfo
.DEFAULT_GROUP
));
289 RSGroupInfo tableGrpB
= rsGroupAdmin
.getRSGroupInfoOfTable(tableNameB
);
290 assertTrue(tableGrpB
.getName().equals(RSGroupInfo
.DEFAULT_GROUP
));
291 // change table's group
292 LOG
.info("Moving table [" + tableNameA
+ "," + tableNameB
+ "] to " + newGroup
.getName());
293 rsGroupAdmin
.moveTables(Sets
.newHashSet(tableNameA
, tableNameB
), newGroup
.getName());
295 // verify group change
296 Assert
.assertEquals(newGroup
.getName(),
297 rsGroupAdmin
.getRSGroupInfoOfTable(tableNameA
).getName());
299 Assert
.assertEquals(newGroup
.getName(),
300 rsGroupAdmin
.getRSGroupInfoOfTable(tableNameB
).getName());
302 // verify tables' not exist in old group
303 Set
<TableName
> DefaultTables
=
304 rsGroupAdmin
.getRSGroupInfo(RSGroupInfo
.DEFAULT_GROUP
).getTables();
305 assertFalse(DefaultTables
.contains(tableNameA
));
306 assertFalse(DefaultTables
.contains(tableNameB
));
308 // verify tables' exist in new group
309 Set
<TableName
> newGroupTables
= rsGroupAdmin
.getRSGroupInfo(newGroupName
).getTables();
310 assertTrue(newGroupTables
.contains(tableNameA
));
311 assertTrue(newGroupTables
.contains(tableNameB
));
315 public void testTableMoveTruncateAndDrop() throws Exception
{
316 final byte[] familyNameBytes
= Bytes
.toBytes("f");
317 String newGroupName
= getGroupName(name
.getMethodName());
318 final RSGroupInfo newGroup
= addGroup(newGroupName
, 2);
320 TEST_UTIL
.createMultiRegionTable(tableName
, familyNameBytes
, 5);
321 TEST_UTIL
.waitFor(WAIT_TIMEOUT
, new Waiter
.Predicate
<Exception
>() {
323 public boolean evaluate() throws Exception
{
324 List
<String
> regions
= getTableRegionMap().get(tableName
);
325 if (regions
== null) {
329 return getTableRegionMap().get(tableName
).size() >= 5;
333 RSGroupInfo tableGrp
= rsGroupAdmin
.getRSGroupInfoOfTable(tableName
);
334 assertTrue(tableGrp
.getName().equals(RSGroupInfo
.DEFAULT_GROUP
));
336 // change table's group
337 LOG
.info("Moving table " + tableName
+ " to " + newGroup
.getName());
338 rsGroupAdmin
.moveTables(Sets
.newHashSet(tableName
), newGroup
.getName());
340 // verify group change
341 Assert
.assertEquals(newGroup
.getName(),
342 rsGroupAdmin
.getRSGroupInfoOfTable(tableName
).getName());
344 TEST_UTIL
.waitFor(WAIT_TIMEOUT
, new Waiter
.Predicate
<Exception
>() {
346 public boolean evaluate() throws Exception
{
347 Map
<ServerName
, List
<String
>> serverMap
= getTableServerRegionMap().get(tableName
);
349 if (serverMap
!= null) {
350 for (ServerName rs
: serverMap
.keySet()) {
351 if (newGroup
.containsServer(rs
.getAddress())) {
352 count
+= serverMap
.get(rs
).size();
361 admin
.disableTable(tableName
);
362 admin
.truncateTable(tableName
, true);
363 Assert
.assertEquals(1, rsGroupAdmin
.getRSGroupInfo(newGroup
.getName()).getTables().size());
364 Assert
.assertEquals(tableName
,
365 rsGroupAdmin
.getRSGroupInfo(newGroup
.getName()).getTables().first());
367 // verify removed table is removed from group
368 TEST_UTIL
.deleteTable(tableName
);
369 Assert
.assertEquals(0, rsGroupAdmin
.getRSGroupInfo(newGroup
.getName()).getTables().size());
371 assertTrue(observer
.preMoveTablesCalled
);
372 assertTrue(observer
.postMoveTablesCalled
);
376 public void testDisabledTableMove() throws Exception
{
377 final byte[] familyNameBytes
= Bytes
.toBytes("f");
378 String newGroupName
= getGroupName(name
.getMethodName());
379 final RSGroupInfo newGroup
= addGroup(newGroupName
, 2);
381 TEST_UTIL
.createMultiRegionTable(tableName
, familyNameBytes
, 5);
382 TEST_UTIL
.waitFor(WAIT_TIMEOUT
, new Waiter
.Predicate
<Exception
>() {
384 public boolean evaluate() throws Exception
{
385 List
<String
> regions
= getTableRegionMap().get(tableName
);
386 if (regions
== null) {
389 return getTableRegionMap().get(tableName
).size() >= 5;
393 RSGroupInfo tableGrp
= rsGroupAdmin
.getRSGroupInfoOfTable(tableName
);
394 assertTrue(tableGrp
.getName().equals(RSGroupInfo
.DEFAULT_GROUP
));
396 // test disable table
397 admin
.disableTable(tableName
);
399 // change table's group
400 LOG
.info("Moving table " + tableName
+ " to " + newGroup
.getName());
401 rsGroupAdmin
.moveTables(Sets
.newHashSet(tableName
), newGroup
.getName());
403 // verify group change
404 Assert
.assertEquals(newGroup
.getName(),
405 rsGroupAdmin
.getRSGroupInfoOfTable(tableName
).getName());
409 public void testNonExistentTableMove() throws Exception
{
410 TableName tableName
= TableName
.valueOf(tablePrefix
+ name
.getMethodName());
412 RSGroupInfo tableGrp
= rsGroupAdmin
.getRSGroupInfoOfTable(tableName
);
413 assertNull(tableGrp
);
415 // test if table exists already.
416 boolean exist
= admin
.tableExists(tableName
);
419 LOG
.info("Moving table " + tableName
+ " to " + RSGroupInfo
.DEFAULT_GROUP
);
421 rsGroupAdmin
.moveTables(Sets
.newHashSet(tableName
), RSGroupInfo
.DEFAULT_GROUP
);
422 fail("Table " + tableName
+ " shouldn't have been successfully moved.");
423 } catch (IOException ex
) {
424 assertTrue(ex
instanceof TableNotFoundException
);
428 rsGroupAdmin
.moveServersAndTables(Sets
.newHashSet(Address
.fromParts("bogus", 123)),
429 Sets
.newHashSet(tableName
), RSGroupInfo
.DEFAULT_GROUP
);
430 fail("Table " + tableName
+ " shouldn't have been successfully moved.");
431 } catch (IOException ex
) {
432 assertTrue(ex
instanceof TableNotFoundException
);
434 // verify group change
435 assertNull(rsGroupAdmin
.getRSGroupInfoOfTable(tableName
));
439 public void testRSGroupListDoesNotContainFailedTableCreation() throws Exception
{
440 toggleQuotaCheckAndRestartMiniCluster(true);
442 NamespaceDescriptor nspDesc
=
443 NamespaceDescriptor
.create(nsp
).addConfiguration(TableNamespaceManager
.KEY_MAX_REGIONS
, "5")
444 .addConfiguration(TableNamespaceManager
.KEY_MAX_TABLES
, "2").build();
445 admin
.createNamespace(nspDesc
);
446 assertEquals(3, admin
.listNamespaceDescriptors().length
);
447 ColumnFamilyDescriptor fam1
= ColumnFamilyDescriptorBuilder
.of("fam1");
448 TableDescriptor tableDescOne
= TableDescriptorBuilder
449 .newBuilder(TableName
.valueOf(nsp
+ TableName
.NAMESPACE_DELIM
+ "table1"))
450 .setColumnFamily(fam1
).build();
451 admin
.createTable(tableDescOne
);
453 TableDescriptor tableDescTwo
= TableDescriptorBuilder
454 .newBuilder(TableName
.valueOf(nsp
+ TableName
.NAMESPACE_DELIM
+ "table2"))
455 .setColumnFamily(fam1
).build();
456 boolean constraintViolated
= false;
459 admin
.createTable(tableDescTwo
, Bytes
.toBytes("AAA"), Bytes
.toBytes("ZZZ"), 6);
460 Assert
.fail("Creation table should fail because of quota violation.");
461 } catch (Exception exp
) {
462 assertTrue(exp
instanceof IOException
);
463 constraintViolated
= true;
465 assertTrue("Constraint not violated for table " + tableDescTwo
.getTableName(),
468 List
<RSGroupInfo
> rsGroupInfoList
= rsGroupAdmin
.listRSGroups();
469 boolean foundTable2
= false;
470 boolean foundTable1
= false;
471 for (int i
= 0; i
< rsGroupInfoList
.size(); i
++) {
472 if (rsGroupInfoList
.get(i
).getTables().contains(tableDescTwo
.getTableName())) {
475 if (rsGroupInfoList
.get(i
).getTables().contains(tableDescOne
.getTableName())) {
479 assertFalse("Found table2 in rsgroup list.", foundTable2
);
480 assertTrue("Did not find table1 in rsgroup list", foundTable1
);
482 TEST_UTIL
.deleteTable(tableDescOne
.getTableName());
483 admin
.deleteNamespace(nspDesc
.getName());
484 toggleQuotaCheckAndRestartMiniCluster(false);
489 public void testNotMoveTableToNullRSGroupWhenCreatingExistingTable()
492 TableName tn1
= TableName
.valueOf("t1");
493 TEST_UTIL
.createTable(tn1
, "cf1");
495 // Create an existing table to trigger HBASE-21866
496 TEST_UTIL
.createTable(tn1
, "cf1");
497 } catch (TableExistsException teex
) {
502 // Could not verify until the rollback of CreateTableProcedure is done
503 // (that is, the coprocessor finishes its work),
504 // or the table is still in the "default" rsgroup even though HBASE-21866
506 TEST_UTIL
.waitFor(5000, new Waiter
.Predicate
<Exception
>() {
508 public boolean evaluate() throws Exception
{
510 (master
.getMasterProcedureExecutor().getActiveExecutorCount() == 0);
513 SortedSet
<TableName
> tables
514 = rsGroupAdmin
.getRSGroupInfo(RSGroupInfo
.DEFAULT_GROUP
).getTables();
515 assertTrue("Table 't1' must be in 'default' rsgroup", tables
.contains(tn1
));
518 TEST_UTIL
.deleteTable(tn1
);
521 private void toggleQuotaCheckAndRestartMiniCluster(boolean enable
) throws Exception
{
522 TEST_UTIL
.shutdownMiniCluster();
523 TEST_UTIL
.getConfiguration().setBoolean(QuotaUtil
.QUOTA_CONF_KEY
, enable
);
524 TEST_UTIL
.startMiniCluster(NUM_SLAVES_BASE
- 1);
525 TEST_UTIL
.getConfiguration().setInt(ServerManager
.WAIT_ON_REGIONSERVERS_MINTOSTART
,
526 NUM_SLAVES_BASE
- 1);
527 TEST_UTIL
.getConfiguration().setBoolean(SnapshotManager
.HBASE_SNAPSHOT_ENABLED
, true);