1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.rsgroup;
21
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertNotNull;
25 import static org.junit.Assert.assertNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28
29 import java.io.IOException;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.SortedSet;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.apache.hadoop.hbase.HColumnDescriptor;
39 import org.apache.hadoop.hbase.HTableDescriptor;
40 import org.apache.hadoop.hbase.NamespaceDescriptor;
41 import org.apache.hadoop.hbase.ServerName;
42 import org.apache.hadoop.hbase.TableExistsException;
43 import org.apache.hadoop.hbase.TableName;
44 import org.apache.hadoop.hbase.TableNotFoundException;
45 import org.apache.hadoop.hbase.Waiter;
46 import org.apache.hadoop.hbase.constraint.ConstraintException;
47 import org.apache.hadoop.hbase.master.ServerManager;
48 import org.apache.hadoop.hbase.master.TableNamespaceManager;
49 import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
50 import org.apache.hadoop.hbase.net.Address;
51 import org.apache.hadoop.hbase.quotas.QuotaUtil;
52 import org.apache.hadoop.hbase.testclassification.MediumTests;
53 import org.apache.hadoop.hbase.util.Bytes;
54 import org.junit.After;
55 import org.junit.AfterClass;
56 import org.junit.Assert;
57 import org.junit.Before;
58 import org.junit.BeforeClass;
59 import org.junit.Test;
60 import org.junit.experimental.categories.Category;
61
62 import com.google.common.collect.Sets;
63
64 @Category({MediumTests.class})
65 public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
66 protected static final Log LOG = LogFactory.getLog(TestRSGroupsAdmin1.class);
67
68 @BeforeClass
69 public static void setUp() throws Exception {
70 setUpTestBeforeClass();
71 }
72
73 @AfterClass
74 public static void tearDown() throws Exception {
75 tearDownAfterClass();
76 }
77
78 @Before
79 public void beforeMethod() throws Exception {
80 setUpBeforeMethod();
81 }
82
83 @After
84 public void afterMethod() throws Exception {
85 tearDownAfterMethod();
86 }
87
88 @Test
89 public void testValidGroupNames() throws IOException {
90 String[] badNames = {"foo*","foo@","-"};
91 String[] goodNames = {"foo_123"};
92
93 for(String entry: badNames) {
94 try {
95 rsGroupAdmin.addRSGroup(entry);
96 fail("Expected a constraint exception for: "+entry);
97 } catch(ConstraintException ex) {
98
99 }
100 }
101
102 for(String entry: goodNames) {
103 rsGroupAdmin.addRSGroup(entry);
104 }
105 }
106
107 @Test
108 public void testBogusArgs() throws Exception {
109 assertNull(rsGroupAdmin.getRSGroupInfoOfTable(TableName.valueOf("nonexistent")));
110 assertNull(rsGroupAdmin.getRSGroupOfServer(Address.fromParts("bogus",123)));
111 assertNull(rsGroupAdmin.getRSGroupInfo("bogus"));
112
113 try {
114 rsGroupAdmin.removeRSGroup("bogus");
115 fail("Expected removing bogus group to fail");
116 } catch(ConstraintException ex) {
117
118 }
119
120 try {
121 rsGroupAdmin.moveTables(Sets.newHashSet(TableName.valueOf("bogustable")), "bogus");
122 fail("Expected move with bogus group to fail");
123 } catch(ConstraintException | TableNotFoundException ex) {
124
125 }
126
127 try {
128 rsGroupAdmin.moveServers(Sets.newHashSet(Address.fromParts("bogus",123)), "bogus");
129 fail("Expected move with bogus group to fail");
130 } catch(ConstraintException ex) {
131
132 }
133
134 try {
135 rsGroupAdmin.balanceRSGroup("bogus");
136 fail("Expected move with bogus group to fail");
137 } catch(ConstraintException ex) {
138
139 }
140 }
141
142 @Test
143 public void testNamespaceConstraint() throws Exception {
144 String nsName = tablePrefix+"_foo";
145 String groupName = tablePrefix+"_foo";
146 LOG.info("testNamespaceConstraint");
147 rsGroupAdmin.addRSGroup(groupName);
148 assertTrue(observer.preAddRSGroupCalled);
149 assertTrue(observer.postAddRSGroupCalled);
150 admin.createNamespace(NamespaceDescriptor.create(nsName)
151 .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName)
152 .build());
153
154 try {
155 rsGroupAdmin.removeRSGroup(groupName);
156 fail("Expected a constraint exception");
157 } catch (IOException ex) {
158 }
159
160
161 admin.modifyNamespace(
162 NamespaceDescriptor.create(nsName)
163 .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName)
164 .build());
165 String anotherGroup = tablePrefix+"_anotherGroup";
166 rsGroupAdmin.addRSGroup(anotherGroup);
167
168 admin.deleteNamespace(nsName);
169 rsGroupAdmin.removeRSGroup(groupName);
170 assertTrue(observer.preRemoveRSGroupCalled);
171 assertTrue(observer.postRemoveRSGroupCalled);
172 try {
173 admin.createNamespace(NamespaceDescriptor.create(nsName)
174 .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "foo")
175 .build());
176 fail("Expected a constraint exception");
177 } catch (IOException ex) {
178 }
179 }
180
181 @Test
182 public void testGroupInfoMultiAccessing() throws Exception {
183 RSGroupInfoManager manager = RSGroupAdminEndpoint.getGroupInfoManager();
184 final RSGroupInfo defaultGroup = manager.getRSGroup("default");
185
186
187 Iterator<Address> it = defaultGroup.getServers().iterator();
188 manager.getRSGroup("default");
189 it.next();
190 }
191
192 @Test
193 public void testFailRemoveGroup() throws IOException, InterruptedException {
194 LOG.info("testFailRemoveGroup");
195
196 int initNumGroups = rsGroupAdmin.listRSGroups().size();
197 addGroup(rsGroupAdmin, "bar", 3);
198 TableName tableName = TableName.valueOf(tablePrefix+"_my_table");
199 TEST_UTIL.createTable(tableName, Bytes.toBytes("f"));
200 rsGroupAdmin.moveTables(Sets.newHashSet(tableName), "bar");
201 RSGroupInfo barGroup = rsGroupAdmin.getRSGroupInfo("bar");
202
203 try {
204 rsGroupAdmin.removeRSGroup(barGroup.getName());
205 fail("Expected remove group to fail");
206 } catch(IOException e) {
207 }
208
209 try {
210 rsGroupAdmin.moveServers(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
211 fail("Expected move servers to fail");
212 } catch(IOException e) {
213 }
214
215 rsGroupAdmin.moveTables(barGroup.getTables(), RSGroupInfo.DEFAULT_GROUP);
216 try {
217 rsGroupAdmin.removeRSGroup(barGroup.getName());
218 fail("Expected move servers to fail");
219 } catch(IOException e) {
220 }
221
222 rsGroupAdmin.moveServers(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
223 rsGroupAdmin.removeRSGroup(barGroup.getName());
224
225 Assert.assertEquals(initNumGroups, rsGroupAdmin.listRSGroups().size());
226 }
227
228 @Test
229 public void testMultiTableMove() throws Exception {
230 LOG.info("testMultiTableMove");
231
232 final TableName tableNameA = TableName.valueOf(tablePrefix + "_testMultiTableMoveA");
233 final TableName tableNameB = TableName.valueOf(tablePrefix + "_testMultiTableMoveB");
234 final byte[] familyNameBytes = Bytes.toBytes("f");
235 String newGroupName = getGroupName("testMultiTableMove");
236 final RSGroupInfo newGroup = addGroup(rsGroupAdmin, newGroupName, 1);
237
238 TEST_UTIL.createTable(tableNameA, familyNameBytes);
239 TEST_UTIL.createTable(tableNameB, familyNameBytes);
240 TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
241 @Override
242 public boolean evaluate() throws Exception {
243 List<String> regionsA = getTableRegionMap().get(tableNameA);
244 if (regionsA == null) {
245 return false;
246 }
247 List<String> regionsB = getTableRegionMap().get(tableNameB);
248 if (regionsB == null) {
249 return false;
250 }
251 return getTableRegionMap().get(tableNameA).size() >= 1
252 && getTableRegionMap().get(tableNameB).size() >= 1;
253 }
254 });
255
256 RSGroupInfo tableGrpA = rsGroupAdmin.getRSGroupInfoOfTable(tableNameA);
257 assertTrue(tableGrpA.getName().equals(RSGroupInfo.DEFAULT_GROUP));
258
259 RSGroupInfo tableGrpB = rsGroupAdmin.getRSGroupInfoOfTable(tableNameB);
260 assertTrue(tableGrpB.getName().equals(RSGroupInfo.DEFAULT_GROUP));
261
262 LOG.info("Moving table [" + tableNameA + "," + tableNameB + "] to " + newGroup.getName());
263 rsGroupAdmin.moveTables(Sets.newHashSet(tableNameA, tableNameB), newGroup.getName());
264
265
266 Assert.assertEquals(newGroup.getName(),
267 rsGroupAdmin.getRSGroupInfoOfTable(tableNameA).getName());
268
269 Assert.assertEquals(newGroup.getName(),
270 rsGroupAdmin.getRSGroupInfoOfTable(tableNameB).getName());
271
272
273 Set<TableName> DefaultTables =
274 rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables();
275 assertFalse(DefaultTables.contains(tableNameA));
276 assertFalse(DefaultTables.contains(tableNameB));
277
278
279 Set<TableName> newGroupTables = rsGroupAdmin.getRSGroupInfo(newGroupName).getTables();
280 assertTrue(newGroupTables.contains(tableNameA));
281 assertTrue(newGroupTables.contains(tableNameB));
282 }
283
284 @Test
285 public void testTableMoveTruncateAndDrop() throws Exception {
286 LOG.info("testTableMove");
287
288 final TableName tableName = TableName.valueOf(tablePrefix + "_testTableMoveAndDrop");
289 final byte[] familyNameBytes = Bytes.toBytes("f");
290 String newGroupName = getGroupName("testTableMove");
291 final RSGroupInfo newGroup = addGroup(rsGroupAdmin, newGroupName, 2);
292
293 TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
294 TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
295 @Override
296 public boolean evaluate() throws Exception {
297 List<String> regions = getTableRegionMap().get(tableName);
298 if (regions == null)
299 return false;
300 return getTableRegionMap().get(tableName).size() >= 5;
301 }
302 });
303
304 RSGroupInfo tableGrp = rsGroupAdmin.getRSGroupInfoOfTable(tableName);
305 assertTrue(tableGrp.getName().equals(RSGroupInfo.DEFAULT_GROUP));
306
307
308 LOG.info("Moving table "+tableName+" to "+newGroup.getName());
309 rsGroupAdmin.moveTables(Sets.newHashSet(tableName), newGroup.getName());
310
311
312 Assert.assertEquals(newGroup.getName(),
313 rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
314
315 TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
316 @Override
317 public boolean evaluate() throws Exception {
318 Map<ServerName, List<String>> serverMap = getTableServerRegionMap().get(tableName);
319 int count = 0;
320 if (serverMap != null) {
321 for (ServerName rs : serverMap.keySet()) {
322 if (newGroup.containsServer(rs.getAddress())) {
323 count += serverMap.get(rs).size();
324 }
325 }
326 }
327 return count == 5;
328 }
329 });
330
331
332 admin.disableTable(tableName);
333 admin.truncateTable(tableName, true);
334 Assert.assertEquals(1, rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
335 Assert.assertEquals(tableName, rsGroupAdmin.getRSGroupInfo(
336 newGroup.getName()).getTables().first());
337
338
339 TEST_UTIL.deleteTable(tableName);
340 Assert.assertEquals(0, rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
341
342 assertTrue(observer.preMoveTablesCalled);
343 assertTrue(observer.postMoveTablesCalled);
344 }
345
346 @Test
347 public void testDisabledTableMove() throws Exception {
348 final TableName tableName = TableName.valueOf(tablePrefix + "_testDisabledTableMove");
349 final byte[] familyNameBytes = Bytes.toBytes("f");
350 String newGroupName = getGroupName("testDisabledTableMove");
351 final RSGroupInfo newGroup = addGroup(rsGroupAdmin, newGroupName, 2);
352
353 TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
354 TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
355 @Override
356 public boolean evaluate() throws Exception {
357 List<String> regions = getTableRegionMap().get(tableName);
358 if (regions == null) {
359 return false;
360 }
361 return getTableRegionMap().get(tableName).size() >= 5;
362 }
363 });
364
365 RSGroupInfo tableGrp = rsGroupAdmin.getRSGroupInfoOfTable(tableName);
366 assertTrue(tableGrp.getName().equals(RSGroupInfo.DEFAULT_GROUP));
367
368
369 admin.disableTable(tableName);
370
371
372 LOG.info("Moving table "+ tableName + " to " + newGroup.getName());
373 rsGroupAdmin.moveTables(Sets.newHashSet(tableName), newGroup.getName());
374
375
376 Assert.assertEquals(newGroup.getName(),
377 rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
378 }
379
380 @Test
381 public void testRSGroupListDoesNotContainFailedTableCreation() throws Exception {
382 toggleQuotaCheckAndRestartMiniCluster(true);
383 String nsp = "np1";
384 NamespaceDescriptor nspDesc =
385 NamespaceDescriptor.create(nsp).addConfiguration(TableNamespaceManager.KEY_MAX_REGIONS, "5")
386 .addConfiguration(TableNamespaceManager.KEY_MAX_TABLES, "2").build();
387 admin.createNamespace(nspDesc);
388 assertEquals(3, admin.listNamespaceDescriptors().length);
389 HColumnDescriptor fam1 = new HColumnDescriptor("fam1");
390 HTableDescriptor tableDescOne =
391 new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table1"));
392 tableDescOne.addFamily(fam1);
393 admin.createTable(tableDescOne);
394
395 HTableDescriptor tableDescTwo =
396 new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table2"));
397 tableDescTwo.addFamily(fam1);
398 boolean constraintViolated = false;
399
400 try {
401 admin.createTable(tableDescTwo, Bytes.toBytes("AAA"), Bytes.toBytes("ZZZ"),
402 6);
403 Assert.fail("Creation table should fail because of quota violation.");
404 } catch (Exception exp) {
405 assertTrue(exp instanceof IOException);
406 constraintViolated = true;
407 } finally {
408 assertTrue("Constraint not violated for table " + tableDescTwo.getTableName(),
409 constraintViolated);
410 }
411 List<RSGroupInfo> rsGroupInfoList = rsGroupAdmin.listRSGroups();
412 boolean foundTable2 = false;
413 boolean foundTable1 = false;
414 for (int i = 0; i < rsGroupInfoList.size(); i++){
415 if(rsGroupInfoList.get(i).getTables().contains(tableDescTwo.getTableName())){
416 foundTable2 = true;
417 }
418 if(rsGroupInfoList.get(i).getTables().contains(tableDescOne.getTableName())){
419 foundTable1 = true;
420 }
421 }
422 assertFalse("Found table2 in rsgroup list.", foundTable2);
423 assertTrue("Did not find table1 in rsgroup list", foundTable1);
424
425 TEST_UTIL.deleteTable(tableDescOne.getTableName());
426 admin.deleteNamespace(nspDesc.getName());
427 toggleQuotaCheckAndRestartMiniCluster(false);
428
429 }
430
431 @Test
432 public void testNotMoveTableToNullRSGroupWhenCreatingExistingTable()
433 throws Exception {
434
435 TableName tn1 = TableName.valueOf("t1");
436 TEST_UTIL.createTable(tn1, "cf1");
437 try {
438
439 TEST_UTIL.createTable(tn1, "cf1");
440 } catch (TableExistsException teex) {
441
442 }
443
444
445
446
447
448
449 TEST_UTIL.waitFor(5000, new Waiter.Predicate<Exception>() {
450 @Override
451 public boolean evaluate() throws Exception {
452 return
453 (master.getMasterProcedureExecutor().getActiveExecutorCount() == 0);
454 }
455 });
456 SortedSet<TableName> tables
457 = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables();
458 assertTrue("Table 't1' must be in 'default' rsgroup", tables.contains(tn1));
459
460
461 TEST_UTIL.deleteTable(tn1);
462 }
463
464 private void toggleQuotaCheckAndRestartMiniCluster(boolean enable) throws Exception {
465 TEST_UTIL.shutdownMiniCluster();
466 TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, enable);
467 TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE - 1);
468 TEST_UTIL.getConfiguration().setInt(
469 ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
470 NUM_SLAVES_BASE - 1);
471 TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
472 initialize();
473 }
474
475 @Test
476 public void testRenameRSGroup() throws Exception {
477
478 RSGroupInfo oldgroup = addGroup(rsGroupAdmin, "oldgroup", 2);
479 final TableName tb1 = TableName.valueOf("testRename");
480 TEST_UTIL.createTable(tb1, "tr");
481 rsGroupAdmin.moveTables(Sets.newHashSet(tb1), oldgroup.getName());
482 TEST_UTIL.waitFor(1000, new Waiter.Predicate<Exception>() {
483 @Override
484 public boolean evaluate() throws Exception {
485 return rsGroupAdmin.getRSGroupInfoOfTable(tb1).getServers().size() == 2;
486 }
487 });
488 oldgroup = rsGroupAdmin.getRSGroupInfo(oldgroup.getName());
489 assertEquals(2, oldgroup.getServers().size());
490 assertEquals(oldgroup.getName(), rsGroupAdmin.getRSGroupInfoOfTable(tb1).getName());
491 assertTrue(oldgroup.getTables().contains(tb1));
492
493
494
495 RSGroupInfo normal = addGroup(rsGroupAdmin, "normal", 1);
496 final TableName tb2 = TableName.valueOf("unmovedTable");
497 TEST_UTIL.createTable(tb2, "ut");
498 rsGroupAdmin.moveTables(Sets.newHashSet(tb2), normal.getName());
499 TEST_UTIL.waitFor(1000, new Waiter.Predicate<Exception>() {
500 @Override
501 public boolean evaluate() throws Exception {
502 return rsGroupAdmin.getRSGroupInfoOfTable(tb2).getServers().size() == 1;
503 }
504 });
505 normal = rsGroupAdmin.getRSGroupInfo(normal.getName());
506 assertEquals(1, normal.getServers().size());
507 assertEquals(normal.getName(), rsGroupAdmin.getRSGroupInfoOfTable(tb2).getName());
508 assertTrue(normal.containsTable(tb2));
509
510
511
512 rsGroupAdmin.renameRSGroup(oldgroup.getName(), "newgroup");
513 Set<Address> servers = oldgroup.getServers();
514 RSGroupInfo newgroup = rsGroupAdmin.getRSGroupInfo("newgroup");
515 assertEquals(servers.size(), newgroup.getServers().size());
516 for (Address server : servers) {
517 assertTrue(newgroup.containsServer(server));
518 }
519 assertEquals(newgroup.getName(), rsGroupAdmin.getRSGroupInfoOfTable(tb1).getName());
520 assertTrue(newgroup.containsTable(tb1));
521 assertEquals(normal.getName(), rsGroupAdmin.getRSGroupInfoOfTable(tb2).getName());
522 }
523
524 @Test
525 public void testRenameRSGroupConstraints() throws Exception {
526
527 String oldGroupName = "oldGroup";
528 RSGroupInfo oldGroup = addGroup(rsGroupAdmin, oldGroupName, 2);
529 oldGroup = rsGroupAdmin.getRSGroupInfo(oldGroup.getName());
530 assertNotNull(oldGroup);
531 assertEquals(2, oldGroup.getServers().size());
532
533
534 String anotherRSGroupName = "anotherRSGroup";
535 RSGroupInfo anotherGroup = addGroup(rsGroupAdmin, anotherRSGroupName, 1);
536 anotherGroup = rsGroupAdmin.getRSGroupInfo(anotherGroup.getName());
537 assertNotNull(anotherGroup);
538 assertEquals(1, anotherGroup.getServers().size());
539
540
541 try {
542 rsGroupAdmin.renameRSGroup(oldGroup.getName(), anotherRSGroupName);
543 fail("ConstraintException was expected.");
544 } catch (ConstraintException e) {
545 assertTrue(e.getMessage().contains("Group already exists"));
546 }
547
548
549 try {
550 rsGroupAdmin.renameRSGroup(RSGroupInfo.DEFAULT_GROUP, "newRSGroup2");
551 fail("ConstraintException was expected.");
552 } catch (ConstraintException e) {
553
554 }
555
556
557 try {
558 rsGroupAdmin.renameRSGroup(oldGroup.getName(), RSGroupInfo.DEFAULT_GROUP);
559 fail("ConstraintException was expected.");
560 } catch (ConstraintException e) {
561 assertTrue(e.getMessage().contains("Group already exists"));
562 }
563 }
564 }