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.assertTrue;
25 import static org.junit.Assert.fail;
26
27 import java.io.IOException;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Set;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.hadoop.hbase.HBaseTestingUtility;
35 import org.apache.hadoop.hbase.HColumnDescriptor;
36 import org.apache.hadoop.hbase.HConstants;
37 import org.apache.hadoop.hbase.HTableDescriptor;
38 import org.apache.hadoop.hbase.MiniHBaseCluster;
39 import org.apache.hadoop.hbase.NamespaceDescriptor;
40 import org.apache.hadoop.hbase.ServerName;
41 import org.apache.hadoop.hbase.TableName;
42 import org.apache.hadoop.hbase.Waiter;
43 import org.apache.hadoop.hbase.Waiter.Predicate;
44 import org.apache.hadoop.hbase.coprocessor.BaseMasterObserver;
45 import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
46 import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
47 import org.apache.hadoop.hbase.coprocessor.MasterObserver;
48 import org.apache.hadoop.hbase.coprocessor.ObserverContext;
49 import org.apache.hadoop.hbase.master.HMaster;
50 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
51 import org.apache.hadoop.hbase.master.ServerManager;
52 import org.apache.hadoop.hbase.master.TableNamespaceManager;
53 import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
54 import org.apache.hadoop.hbase.net.Address;
55 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
56 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos;
57 import org.apache.hadoop.hbase.quotas.QuotaUtil;
58 import org.apache.hadoop.hbase.testclassification.MediumTests;
59 import org.apache.hadoop.hbase.util.Bytes;
60 import org.junit.After;
61 import org.junit.AfterClass;
62 import org.junit.Assert;
63 import org.junit.Before;
64 import org.junit.BeforeClass;
65 import org.junit.Test;
66 import org.junit.experimental.categories.Category;
67
68 import com.google.common.collect.Sets;
69
70 @Category({MediumTests.class})
71 public class TestRSGroups extends TestRSGroupsBase {
72 protected static final Log LOG = LogFactory.getLog(TestRSGroups.class);
73 private static HMaster master;
74 private static boolean init = false;
75 private static RSGroupAdminEndpoint RSGroupAdminEndpoint;
76 private static CPMasterObserver observer;
77
78 @BeforeClass
79 public static void setUp() throws Exception {
80 TEST_UTIL = new HBaseTestingUtility();
81 TEST_UTIL.getConfiguration().setFloat(
82 "hbase.master.balancer.stochastic.tableSkewCost", 6000);
83 TEST_UTIL.getConfiguration().set(
84 HConstants.HBASE_MASTER_LOADBALANCER_CLASS,
85 RSGroupBasedLoadBalancer.class.getName());
86 TEST_UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
87 RSGroupAdminEndpoint.class.getName() + "," + CPMasterObserver.class.getName());
88 TEST_UTIL.getConfiguration().setBoolean(
89 HConstants.ZOOKEEPER_USEMULTI,
90 true);
91 TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE - 1);
92 TEST_UTIL.getConfiguration().setInt(
93 ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
94 NUM_SLAVES_BASE - 1);
95 TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
96 initialize();
97 }
98
99 private static void initialize() throws Exception {
100 admin = TEST_UTIL.getHBaseAdmin();
101 cluster = TEST_UTIL.getHBaseCluster();
102 master = ((MiniHBaseCluster)cluster).getMaster();
103
104
105 TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
106 @Override
107 public boolean evaluate() throws Exception {
108 return master.isInitialized() &&
109 ((RSGroupBasedLoadBalancer) master.getLoadBalancer()).isOnline();
110 }
111 });
112 admin.setBalancerRunning(false,true);
113 rsGroupAdmin = new VerifyingRSGroupAdminClient(new RSGroupAdminClient(TEST_UTIL.getConnection()),
114 TEST_UTIL.getConfiguration());
115 MasterCoprocessorHost host = master.getMasterCoprocessorHost();
116 observer = (CPMasterObserver) host.findCoprocessor(CPMasterObserver.class.getName());
117 RSGroupAdminEndpoint =
118 host.findCoprocessors(RSGroupAdminEndpoint.class).get(0);
119 }
120
121 @AfterClass
122 public static void tearDown() throws Exception {
123 TEST_UTIL.shutdownMiniCluster();
124 }
125
126 @Before
127 public void beforeMethod() throws Exception {
128 if(!init) {
129 init = true;
130 afterMethod();
131 }
132 observer.resetFlags();
133 }
134
135 @After
136 public void afterMethod() throws Exception {
137 deleteTableIfNecessary();
138 deleteNamespaceIfNecessary();
139 deleteGroups();
140
141 int missing = NUM_SLAVES_BASE - getNumServers();
142 LOG.info("Restoring servers: "+missing);
143 for(int i=0; i<missing; i++) {
144 ((MiniHBaseCluster)cluster).startRegionServer();
145 }
146
147 rsGroupAdmin.addRSGroup("master");
148 ServerName masterServerName =
149 ((MiniHBaseCluster)cluster).getMaster().getServerName();
150
151 try {
152 rsGroupAdmin.moveServers(
153 Sets.newHashSet(masterServerName.getAddress()),
154 "master");
155 } catch (Exception ex) {
156
157 }
158
159 TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
160 @Override
161 public boolean evaluate() throws Exception {
162 LOG.info("Waiting for cleanup to finish " + rsGroupAdmin.listRSGroups());
163
164
165
166 return rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size()
167 == NUM_SLAVES_BASE;
168 }
169 });
170 }
171
172 @Test
173 public void testBasicStartUp() throws IOException {
174 RSGroupInfo defaultInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
175 assertEquals(4, defaultInfo.getServers().size());
176
177 int count = master.getAssignmentManager().getRegionStates().getRegionAssignments().size();
178
179 assertEquals(3, count);
180 }
181
182 @Test
183 public void testNamespaceCreateAndAssign() throws Exception {
184 LOG.info("testNamespaceCreateAndAssign");
185 String nsName = tablePrefix+"_foo";
186 final TableName tableName = TableName.valueOf(nsName, tablePrefix + "_testCreateAndAssign");
187 RSGroupInfo appInfo = addGroup(rsGroupAdmin, "appInfo", 1);
188 admin.createNamespace(NamespaceDescriptor.create(nsName)
189 .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "appInfo").build());
190 final HTableDescriptor desc = new HTableDescriptor(tableName);
191 desc.addFamily(new HColumnDescriptor("f"));
192 admin.createTable(desc);
193
194 TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
195 @Override
196 public boolean evaluate() throws Exception {
197 return getTableRegionMap().get(desc.getTableName()) != null;
198 }
199 });
200 ServerName targetServer =
201 ServerName.parseServerName(appInfo.getServers().iterator().next().toString());
202 AdminProtos.AdminService.BlockingInterface rs = admin.getConnection().getAdmin(targetServer);
203
204 Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(rs).size());
205 }
206
207 @Test
208 public void testDefaultNamespaceCreateAndAssign() throws Exception {
209 LOG.info("testDefaultNamespaceCreateAndAssign");
210 final byte[] tableName = Bytes.toBytes(tablePrefix + "_testCreateAndAssign");
211 admin.modifyNamespace(NamespaceDescriptor.create("default")
212 .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "default").build());
213 final HTableDescriptor desc = new HTableDescriptor(tableName);
214 desc.addFamily(new HColumnDescriptor("f"));
215 admin.createTable(desc);
216
217 TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
218 @Override
219 public boolean evaluate() throws Exception {
220 return getTableRegionMap().get(desc.getTableName()) != null;
221 }
222 });
223 }
224
225 @Test
226 public void testNamespaceConstraint() throws Exception {
227 String nsName = tablePrefix+"_foo";
228 String groupName = tablePrefix+"_foo";
229 LOG.info("testNamespaceConstraint");
230 rsGroupAdmin.addRSGroup(groupName);
231 admin.createNamespace(NamespaceDescriptor.create(nsName)
232 .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName)
233 .build());
234
235 try {
236 rsGroupAdmin.removeRSGroup(groupName);
237 fail("Expected a constraint exception");
238 } catch (IOException ex) {
239 }
240
241
242 admin.modifyNamespace(
243 NamespaceDescriptor.create(nsName)
244 .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName)
245 .build());
246 String anotherGroup = tablePrefix+"_anotherGroup";
247 rsGroupAdmin.addRSGroup(anotherGroup);
248
249 admin.deleteNamespace(nsName);
250 rsGroupAdmin.removeRSGroup(groupName);
251 try {
252 admin.createNamespace(NamespaceDescriptor.create(nsName)
253 .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "foo")
254 .build());
255 fail("Expected a constraint exception");
256 } catch (IOException ex) {
257 }
258 }
259
260 @Test
261 public void testGroupInfoMultiAccessing() throws Exception {
262 RSGroupInfoManager manager = RSGroupAdminEndpoint.getGroupInfoManager();
263 final RSGroupInfo defaultGroup = manager.getRSGroup("default");
264
265
266 Iterator<Address> it = defaultGroup.getServers().iterator();
267 manager.getRSGroup("default");
268 it.next();
269 }
270
271 public static class CPMasterObserver extends BaseMasterObserver {
272 boolean preBalanceRSGroupCalled = false;
273 boolean postBalanceRSGroupCalled = false;
274 boolean preMoveServersCalled = false;
275 boolean postMoveServersCalled = false;
276 boolean preMoveTablesCalled = false;
277 boolean postMoveTablesCalled = false;
278 boolean preAddRSGroupCalled = false;
279 boolean postAddRSGroupCalled = false;
280 boolean preRemoveRSGroupCalled = false;
281 boolean postRemoveRSGroupCalled = false;
282 boolean preRemoveServersCalled = false;
283 boolean postRemoveServersCalled = false;
284 boolean preMoveServersAndTables = false;
285 boolean postMoveServersAndTables = false;
286
287 void resetFlags() {
288 preBalanceRSGroupCalled = false;
289 postBalanceRSGroupCalled = false;
290 preMoveServersCalled = false;
291 postMoveServersCalled = false;
292 preMoveTablesCalled = false;
293 postMoveTablesCalled = false;
294 preAddRSGroupCalled = false;
295 postAddRSGroupCalled = false;
296 preRemoveRSGroupCalled = false;
297 postRemoveRSGroupCalled = false;
298 preRemoveServersCalled = false;
299 postRemoveServersCalled = false;
300 preMoveServersAndTables = false;
301 postMoveServersAndTables = false;
302 }
303
304 @Override
305 public void preMoveServersAndTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
306 Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException {
307 preMoveServersAndTables = true;
308 }
309 @Override
310 public void postMoveServersAndTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
311 Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException {
312 postMoveServersAndTables = true;
313 }
314 @Override
315 public void preRemoveServers(
316 final ObserverContext<MasterCoprocessorEnvironment> ctx,
317 Set<Address> servers) throws IOException {
318 preRemoveServersCalled = true;
319 }
320 @Override
321 public void postRemoveServers(
322 final ObserverContext<MasterCoprocessorEnvironment> ctx,
323 Set<Address> servers) throws IOException {
324 postRemoveServersCalled = true;
325 }
326 @Override
327 public void preRemoveRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
328 String name) throws IOException {
329 preRemoveRSGroupCalled = true;
330 }
331 @Override
332 public void postRemoveRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
333 String name) throws IOException {
334 postRemoveRSGroupCalled = true;
335 }
336 @Override
337 public void preAddRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
338 String name) throws IOException {
339 preAddRSGroupCalled = true;
340 }
341 @Override
342 public void postAddRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
343 String name) throws IOException {
344 postAddRSGroupCalled = true;
345 }
346 @Override
347 public void preMoveTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
348 Set<TableName> tables, String targetGroup) throws IOException {
349 preMoveTablesCalled = true;
350 }
351 @Override
352 public void postMoveTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
353 Set<TableName> tables, String targetGroup) throws IOException {
354 postMoveTablesCalled = true;
355 }
356 @Override
357 public void preMoveServers(final ObserverContext<MasterCoprocessorEnvironment> ctx,
358 Set<Address> servers, String targetGroup) throws IOException {
359 preMoveServersCalled = true;
360 }
361
362 @Override
363 public void postMoveServers(final ObserverContext<MasterCoprocessorEnvironment> ctx,
364 Set<Address> servers, String targetGroup) throws IOException {
365 postMoveServersCalled = true;
366 }
367 @Override
368 public void preBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
369 String groupName) throws IOException {
370 preBalanceRSGroupCalled = true;
371 }
372 @Override
373 public void postBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
374 String groupName, boolean balancerRan) throws IOException {
375 postBalanceRSGroupCalled = true;
376 }
377 }
378 @Test
379 public void testMoveServersAndTables() throws Exception {
380 super.testMoveServersAndTables();
381 assertTrue(observer.preMoveServersAndTables);
382 assertTrue(observer.postMoveServersAndTables);
383 }
384 @Test
385 public void testTableMoveTruncateAndDrop() throws Exception {
386 super.testTableMoveTruncateAndDrop();
387 assertTrue(observer.preMoveTablesCalled);
388 assertTrue(observer.postMoveTablesCalled);
389 }
390
391 @Test
392 public void testRemoveServers() throws Exception {
393 super.testRemoveServers();
394 assertTrue(observer.preRemoveServersCalled);
395 }
396
397 @Test
398 public void testGroupBalance() throws Exception {
399 super.testGroupBalance();
400 assertTrue(observer.preBalanceRSGroupCalled);
401 assertTrue(observer.postBalanceRSGroupCalled);
402 }
403
404 @Test
405 public void testMisplacedRegions() throws Exception {
406 final TableName tableName = TableName.valueOf(tablePrefix+"_testMisplacedRegions");
407 LOG.info("testMisplacedRegions");
408
409 final RSGroupInfo RSGroupInfo = addGroup(rsGroupAdmin, "testMisplacedRegions", 1);
410
411 TEST_UTIL.createMultiRegionTable(tableName, new byte[]{'f'}, 15);
412 TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
413
414 RSGroupAdminEndpoint.getGroupInfoManager()
415 .moveTables(Sets.newHashSet(tableName), RSGroupInfo.getName());
416
417 assertTrue(rsGroupAdmin.balanceRSGroup(RSGroupInfo.getName()));
418
419 TEST_UTIL.waitFor(60000, new Predicate<Exception>() {
420 @Override
421 public boolean evaluate() throws Exception {
422 ServerName serverName =
423 ServerName.valueOf(RSGroupInfo.getServers().iterator().next().toString(), 1);
424 return admin.getConnection().getAdmin()
425 .getOnlineRegions(serverName).size() == 15;
426 }
427 });
428 }
429
430 @Test
431 public void testRSGroupBalancerSwitch() throws IOException {
432
433 assertFalse(admin.setBalancerRunning(true, true));
434 assertTrue(admin.isBalancerEnabled());
435
436 assertTrue(admin.setBalancerRunning(false,true));
437 assertFalse(admin.isBalancerEnabled());
438 }
439
440 @Test
441 public void testCloneSnapshot() throws Exception {
442 final TableName tableName = TableName.valueOf(tablePrefix+"_testCloneSnapshot");
443 LOG.info("testCloneSnapshot");
444
445 byte[] FAMILY = Bytes.toBytes("test");
446 String snapshotName = tableName.getNameAsString() + "_snap";
447 TableName clonedTableName = TableName.valueOf(tableName.getNameAsString() + "_clone");
448
449
450 TEST_UTIL.createTable(tableName, FAMILY);
451
452
453 admin.snapshot(snapshotName, tableName);
454
455
456 admin.cloneSnapshot(snapshotName, clonedTableName);
457 }
458
459 @Test
460 public void testRSGroupListDoesNotContainFailedTableCreation() throws Exception {
461 toggleQuotaCheckAndRestartMiniCluster(true);
462 String nsp = "np1";
463 NamespaceDescriptor nspDesc =
464 NamespaceDescriptor.create(nsp).addConfiguration(TableNamespaceManager.KEY_MAX_REGIONS, "5")
465 .addConfiguration(TableNamespaceManager.KEY_MAX_TABLES, "2").build();
466 admin.createNamespace(nspDesc);
467 assertEquals(3, admin.listNamespaceDescriptors().length);
468 HColumnDescriptor fam1 = new HColumnDescriptor("fam1");
469 HTableDescriptor tableDescOne =
470 new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table1"));
471 tableDescOne.addFamily(fam1);
472 admin.createTable(tableDescOne);
473
474 HTableDescriptor tableDescTwo =
475 new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table2"));
476 tableDescTwo.addFamily(fam1);
477 boolean constraintViolated = false;
478
479 try {
480 admin.createTable(tableDescTwo, Bytes.toBytes("AAA"), Bytes.toBytes("ZZZ"),
481 6);
482 Assert.fail("Creation table should fail because of quota violation.");
483 } catch (Exception exp) {
484 assertTrue(exp instanceof IOException);
485 constraintViolated = true;
486 } finally {
487 assertTrue("Constraint not violated for table " + tableDescTwo.getTableName(),
488 constraintViolated);
489 }
490 List<RSGroupInfo> rsGroupInfoList = rsGroupAdmin.listRSGroups();
491 boolean foundTable2 = false;
492 boolean foundTable1 = false;
493 for (int i = 0; i < rsGroupInfoList.size(); i++){
494 if(rsGroupInfoList.get(i).getTables().contains(tableDescTwo.getTableName())){
495 foundTable2 = true;
496 }
497 if(rsGroupInfoList.get(i).getTables().contains(tableDescOne.getTableName())){
498 foundTable1 = true;
499 }
500 }
501 assertFalse("Found table2 in rsgroup list.", foundTable2);
502 assertTrue("Did not find table1 in rsgroup list", foundTable1);
503
504 TEST_UTIL.deleteTable(tableDescOne.getTableName());
505 admin.deleteNamespace(nspDesc.getName());
506 toggleQuotaCheckAndRestartMiniCluster(false);
507
508 }
509
510 private void toggleQuotaCheckAndRestartMiniCluster(boolean enable) throws Exception {
511 TEST_UTIL.shutdownMiniCluster();
512 TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, enable);
513 TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE - 1);
514 TEST_UTIL.getConfiguration().setInt(
515 ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
516 NUM_SLAVES_BASE - 1);
517 TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
518 initialize();
519 }
520
521 }