1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.coprocessor;
22
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
28 import java.io.IOException;
29 import java.util.Collection;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.NavigableMap;
33
34 import junit.framework.Assert;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.apache.hadoop.conf.Configuration;
39 import org.apache.hadoop.hbase.*;
40 import org.apache.hadoop.hbase.client.HBaseAdmin;
41 import org.apache.hadoop.hbase.client.HTable;
42 import org.apache.hadoop.hbase.master.AssignmentManager;
43 import org.apache.hadoop.hbase.master.HMaster;
44 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
45 import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
46 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
47 import org.apache.hadoop.hbase.regionserver.HRegionServer;
48 import org.apache.hadoop.hbase.util.Bytes;
49 import org.apache.hadoop.hbase.util.Threads;
50 import org.junit.AfterClass;
51 import org.junit.BeforeClass;
52 import org.junit.Test;
53 import org.junit.experimental.categories.Category;
54
55
56
57
58
59 @Category(MediumTests.class)
60 public class TestMasterObserver {
61 private static final Log LOG = LogFactory.getLog(TestMasterObserver.class);
62
63 public static class CPMasterObserver implements MasterObserver {
64
65 private boolean bypass = false;
66 private boolean preCreateTableCalled;
67 private boolean postCreateTableCalled;
68 private boolean preDeleteTableCalled;
69 private boolean postDeleteTableCalled;
70 private boolean preModifyTableCalled;
71 private boolean postModifyTableCalled;
72 private boolean preAddColumnCalled;
73 private boolean postAddColumnCalled;
74 private boolean preModifyColumnCalled;
75 private boolean postModifyColumnCalled;
76 private boolean preDeleteColumnCalled;
77 private boolean postDeleteColumnCalled;
78 private boolean preEnableTableCalled;
79 private boolean postEnableTableCalled;
80 private boolean preDisableTableCalled;
81 private boolean postDisableTableCalled;
82 private boolean preMoveCalled;
83 private boolean postMoveCalled;
84 private boolean preAssignCalled;
85 private boolean postAssignCalled;
86 private boolean preUnassignCalled;
87 private boolean postUnassignCalled;
88 private boolean preBalanceCalled;
89 private boolean postBalanceCalled;
90 private boolean preBalanceSwitchCalled;
91 private boolean postBalanceSwitchCalled;
92 private boolean preShutdownCalled;
93 private boolean preStopMasterCalled;
94 private boolean postStartMasterCalled;
95 private boolean startCalled;
96 private boolean stopCalled;
97 private boolean preSnapshotCalled;
98 private boolean postSnapshotCalled;
99 private boolean preCloneSnapshotCalled;
100 private boolean postCloneSnapshotCalled;
101 private boolean preRestoreSnapshotCalled;
102 private boolean postRestoreSnapshotCalled;
103 private boolean preDeleteSnapshotCalled;
104 private boolean postDeleteSnapshotCalled;
105
106 public void enableBypass(boolean bypass) {
107 this.bypass = bypass;
108 }
109
110 public void resetStates() {
111 preCreateTableCalled = false;
112 postCreateTableCalled = false;
113 preDeleteTableCalled = false;
114 postDeleteTableCalled = false;
115 preModifyTableCalled = false;
116 postModifyTableCalled = false;
117 preAddColumnCalled = false;
118 postAddColumnCalled = false;
119 preModifyColumnCalled = false;
120 postModifyColumnCalled = false;
121 preDeleteColumnCalled = false;
122 postDeleteColumnCalled = false;
123 preEnableTableCalled = false;
124 postEnableTableCalled = false;
125 preDisableTableCalled = false;
126 postDisableTableCalled = false;
127 preMoveCalled= false;
128 postMoveCalled = false;
129 preAssignCalled = false;
130 postAssignCalled = false;
131 preUnassignCalled = false;
132 postUnassignCalled = false;
133 preBalanceCalled = false;
134 postBalanceCalled = false;
135 preBalanceSwitchCalled = false;
136 postBalanceSwitchCalled = false;
137 preSnapshotCalled = false;
138 postSnapshotCalled = false;
139 preCloneSnapshotCalled = false;
140 postCloneSnapshotCalled = false;
141 preRestoreSnapshotCalled = false;
142 postRestoreSnapshotCalled = false;
143 preDeleteSnapshotCalled = false;
144 postDeleteSnapshotCalled = false;
145 }
146
147 @Override
148 public void preCreateTable(ObserverContext<MasterCoprocessorEnvironment> env,
149 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
150 if (bypass) {
151 env.bypass();
152 }
153 preCreateTableCalled = true;
154 }
155
156 @Override
157 public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> env,
158 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
159 postCreateTableCalled = true;
160 }
161
162 public boolean wasCreateTableCalled() {
163 return preCreateTableCalled && postCreateTableCalled;
164 }
165
166 public boolean preCreateTableCalledOnly() {
167 return preCreateTableCalled && !postCreateTableCalled;
168 }
169
170 @Override
171 public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> env,
172 byte[] tableName) throws IOException {
173 if (bypass) {
174 env.bypass();
175 }
176 preDeleteTableCalled = true;
177 }
178
179 @Override
180 public void postDeleteTable(ObserverContext<MasterCoprocessorEnvironment> env,
181 byte[] tableName) throws IOException {
182 postDeleteTableCalled = true;
183 }
184
185 public boolean wasDeleteTableCalled() {
186 return preDeleteTableCalled && postDeleteTableCalled;
187 }
188
189 public boolean preDeleteTableCalledOnly() {
190 return preDeleteTableCalled && !postDeleteTableCalled;
191 }
192
193 @Override
194 public void preModifyTable(ObserverContext<MasterCoprocessorEnvironment> env,
195 byte[] tableName, HTableDescriptor htd) throws IOException {
196 if (bypass) {
197 env.bypass();
198 }
199 preModifyTableCalled = true;
200 }
201
202 @Override
203 public void postModifyTable(ObserverContext<MasterCoprocessorEnvironment> env,
204 byte[] tableName, HTableDescriptor htd) throws IOException {
205 postModifyTableCalled = true;
206 }
207
208 public boolean wasModifyTableCalled() {
209 return preModifyTableCalled && postModifyTableCalled;
210 }
211
212 public boolean preModifyTableCalledOnly() {
213 return preModifyTableCalled && !postModifyTableCalled;
214 }
215
216 @Override
217 public void preAddColumn(ObserverContext<MasterCoprocessorEnvironment> env,
218 byte[] tableName, HColumnDescriptor column) throws IOException {
219 if (bypass) {
220 env.bypass();
221 }
222 preAddColumnCalled = true;
223 }
224
225 @Override
226 public void postAddColumn(ObserverContext<MasterCoprocessorEnvironment> env,
227 byte[] tableName, HColumnDescriptor column) throws IOException {
228 postAddColumnCalled = true;
229 }
230
231 public boolean wasAddColumnCalled() {
232 return preAddColumnCalled && postAddColumnCalled;
233 }
234
235 public boolean preAddColumnCalledOnly() {
236 return preAddColumnCalled && !postAddColumnCalled;
237 }
238
239 @Override
240 public void preModifyColumn(ObserverContext<MasterCoprocessorEnvironment> env,
241 byte[] tableName, HColumnDescriptor descriptor) throws IOException {
242 if (bypass) {
243 env.bypass();
244 }
245 preModifyColumnCalled = true;
246 }
247
248 @Override
249 public void postModifyColumn(ObserverContext<MasterCoprocessorEnvironment> env,
250 byte[] tableName, HColumnDescriptor descriptor) throws IOException {
251 postModifyColumnCalled = true;
252 }
253
254 public boolean wasModifyColumnCalled() {
255 return preModifyColumnCalled && postModifyColumnCalled;
256 }
257
258 public boolean preModifyColumnCalledOnly() {
259 return preModifyColumnCalled && !postModifyColumnCalled;
260 }
261
262 @Override
263 public void preDeleteColumn(ObserverContext<MasterCoprocessorEnvironment> env,
264 byte[] tableName, byte[] c) throws IOException {
265 if (bypass) {
266 env.bypass();
267 }
268 preDeleteColumnCalled = true;
269 }
270
271 @Override
272 public void postDeleteColumn(ObserverContext<MasterCoprocessorEnvironment> env,
273 byte[] tableName, byte[] c) throws IOException {
274 postDeleteColumnCalled = true;
275 }
276
277 public boolean wasDeleteColumnCalled() {
278 return preDeleteColumnCalled && postDeleteColumnCalled;
279 }
280
281 public boolean preDeleteColumnCalledOnly() {
282 return preDeleteColumnCalled && !postDeleteColumnCalled;
283 }
284
285 @Override
286 public void preEnableTable(ObserverContext<MasterCoprocessorEnvironment> env,
287 byte[] tableName) throws IOException {
288 if (bypass) {
289 env.bypass();
290 }
291 preEnableTableCalled = true;
292 }
293
294 @Override
295 public void postEnableTable(ObserverContext<MasterCoprocessorEnvironment> env,
296 byte[] tableName) throws IOException {
297 postEnableTableCalled = true;
298 }
299
300 public boolean wasEnableTableCalled() {
301 return preEnableTableCalled && postEnableTableCalled;
302 }
303
304 public boolean preEnableTableCalledOnly() {
305 return preEnableTableCalled && !postEnableTableCalled;
306 }
307
308 @Override
309 public void preDisableTable(ObserverContext<MasterCoprocessorEnvironment> env,
310 byte[] tableName) throws IOException {
311 if (bypass) {
312 env.bypass();
313 }
314 preDisableTableCalled = true;
315 }
316
317 @Override
318 public void postDisableTable(ObserverContext<MasterCoprocessorEnvironment> env,
319 byte[] tableName) throws IOException {
320 postDisableTableCalled = true;
321 }
322
323 public boolean wasDisableTableCalled() {
324 return preDisableTableCalled && postDisableTableCalled;
325 }
326
327 public boolean preDisableTableCalledOnly() {
328 return preDisableTableCalled && !postDisableTableCalled;
329 }
330
331 @Override
332 public void preMove(ObserverContext<MasterCoprocessorEnvironment> env,
333 HRegionInfo region, ServerName srcServer, ServerName destServer)
334 throws IOException {
335 if (bypass) {
336 env.bypass();
337 }
338 preMoveCalled = true;
339 }
340
341 @Override
342 public void postMove(ObserverContext<MasterCoprocessorEnvironment> env, HRegionInfo region,
343 ServerName srcServer, ServerName destServer)
344 throws IOException {
345 postMoveCalled = true;
346 }
347
348 public boolean wasMoveCalled() {
349 return preMoveCalled && postMoveCalled;
350 }
351
352 public boolean preMoveCalledOnly() {
353 return preMoveCalled && !postMoveCalled;
354 }
355
356 @Override
357 public void preAssign(ObserverContext<MasterCoprocessorEnvironment> env,
358 final HRegionInfo regionInfo) throws IOException {
359 if (bypass) {
360 env.bypass();
361 }
362 preAssignCalled = true;
363 }
364
365 @Override
366 public void postAssign(ObserverContext<MasterCoprocessorEnvironment> env,
367 final HRegionInfo regionInfo) throws IOException {
368 postAssignCalled = true;
369 }
370
371 public boolean wasAssignCalled() {
372 return preAssignCalled && postAssignCalled;
373 }
374
375 public boolean preAssignCalledOnly() {
376 return preAssignCalled && !postAssignCalled;
377 }
378
379 @Override
380 public void preUnassign(ObserverContext<MasterCoprocessorEnvironment> env,
381 final HRegionInfo regionInfo, final boolean force) throws IOException {
382 if (bypass) {
383 env.bypass();
384 }
385 preUnassignCalled = true;
386 }
387
388 @Override
389 public void postUnassign(ObserverContext<MasterCoprocessorEnvironment> env,
390 final HRegionInfo regionInfo, final boolean force) throws IOException {
391 postUnassignCalled = true;
392 }
393
394 public boolean wasUnassignCalled() {
395 return preUnassignCalled && postUnassignCalled;
396 }
397
398 public boolean preUnassignCalledOnly() {
399 return preUnassignCalled && !postUnassignCalled;
400 }
401
402 @Override
403 public void preBalance(ObserverContext<MasterCoprocessorEnvironment> env)
404 throws IOException {
405 if (bypass) {
406 env.bypass();
407 }
408 preBalanceCalled = true;
409 }
410
411 @Override
412 public void postBalance(ObserverContext<MasterCoprocessorEnvironment> env)
413 throws IOException {
414 postBalanceCalled = true;
415 }
416
417 public boolean wasBalanceCalled() {
418 return preBalanceCalled && postBalanceCalled;
419 }
420
421 public boolean preBalanceCalledOnly() {
422 return preBalanceCalled && !postBalanceCalled;
423 }
424
425 @Override
426 public boolean preBalanceSwitch(ObserverContext<MasterCoprocessorEnvironment> env, boolean b)
427 throws IOException {
428 if (bypass) {
429 env.bypass();
430 }
431 preBalanceSwitchCalled = true;
432 return b;
433 }
434
435 @Override
436 public void postBalanceSwitch(ObserverContext<MasterCoprocessorEnvironment> env,
437 boolean oldValue, boolean newValue) throws IOException {
438 postBalanceSwitchCalled = true;
439 }
440
441 public boolean wasBalanceSwitchCalled() {
442 return preBalanceSwitchCalled && postBalanceSwitchCalled;
443 }
444
445 public boolean preBalanceSwitchCalledOnly() {
446 return preBalanceSwitchCalled && !postBalanceSwitchCalled;
447 }
448
449 @Override
450 public void preShutdown(ObserverContext<MasterCoprocessorEnvironment> env)
451 throws IOException {
452 preShutdownCalled = true;
453 }
454
455 @Override
456 public void preStopMaster(ObserverContext<MasterCoprocessorEnvironment> env)
457 throws IOException {
458 preStopMasterCalled = true;
459 }
460
461 @Override
462 public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx)
463 throws IOException {
464 postStartMasterCalled = true;
465 }
466
467 public boolean wasStartMasterCalled() {
468 return postStartMasterCalled;
469 }
470
471 @Override
472 public void start(CoprocessorEnvironment env) throws IOException {
473 startCalled = true;
474 }
475
476 @Override
477 public void stop(CoprocessorEnvironment env) throws IOException {
478 stopCalled = true;
479 }
480
481 public boolean wasStarted() { return startCalled; }
482
483 public boolean wasStopped() { return stopCalled; }
484
485 @Override
486 public void preSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
487 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
488 throws IOException {
489 preSnapshotCalled = true;
490 }
491
492 @Override
493 public void postSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
494 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
495 throws IOException {
496 postSnapshotCalled = true;
497 }
498
499 public boolean wasSnapshotCalled() {
500 return preSnapshotCalled && postSnapshotCalled;
501 }
502
503 @Override
504 public void preCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
505 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
506 throws IOException {
507 preCloneSnapshotCalled = true;
508 }
509
510 @Override
511 public void postCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
512 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
513 throws IOException {
514 postCloneSnapshotCalled = true;
515 }
516
517 public boolean wasCloneSnapshotCalled() {
518 return preCloneSnapshotCalled && postCloneSnapshotCalled;
519 }
520
521 @Override
522 public void preRestoreSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
523 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
524 throws IOException {
525 preRestoreSnapshotCalled = true;
526 }
527
528 @Override
529 public void postRestoreSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
530 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
531 throws IOException {
532 postRestoreSnapshotCalled = true;
533 }
534
535 public boolean wasRestoreSnapshotCalled() {
536 return preRestoreSnapshotCalled && postRestoreSnapshotCalled;
537 }
538
539 @Override
540 public void preDeleteSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
541 final SnapshotDescription snapshot) throws IOException {
542 preDeleteSnapshotCalled = true;
543 }
544
545 @Override
546 public void postDeleteSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
547 final SnapshotDescription snapshot) throws IOException {
548 postDeleteSnapshotCalled = true;
549 }
550
551 public boolean wasDeleteSnapshotCalled() {
552 return preDeleteSnapshotCalled && postDeleteSnapshotCalled;
553 }
554 }
555
556 private static HBaseTestingUtility UTIL = new HBaseTestingUtility();
557 private static byte[] TEST_SNAPSHOT = Bytes.toBytes("observed_snapshot");
558 private static byte[] TEST_TABLE = Bytes.toBytes("observed_table");
559 private static byte[] TEST_CLONE = Bytes.toBytes("observed_clone");
560 private static byte[] TEST_FAMILY = Bytes.toBytes("fam1");
561 private static byte[] TEST_FAMILY2 = Bytes.toBytes("fam2");
562
563 @BeforeClass
564 public static void setupBeforeClass() throws Exception {
565 Configuration conf = UTIL.getConfiguration();
566 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
567 CPMasterObserver.class.getName());
568
569 conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
570
571 UTIL.startMiniCluster(2);
572 }
573
574 @AfterClass
575 public static void tearDownAfterClass() throws Exception {
576 UTIL.shutdownMiniCluster();
577 }
578
579 @Test
580 public void testStarted() throws Exception {
581 MiniHBaseCluster cluster = UTIL.getHBaseCluster();
582
583 HMaster master = cluster.getMaster();
584 assertTrue("Master should be active", master.isActiveMaster());
585 MasterCoprocessorHost host = master.getCoprocessorHost();
586 assertNotNull("CoprocessorHost should not be null", host);
587 CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
588 CPMasterObserver.class.getName());
589 assertNotNull("CPMasterObserver coprocessor not found or not installed!", cp);
590
591
592 assertTrue("MasterObserver should have been started", cp.wasStarted());
593 assertTrue("postStartMaster() hook should have been called",
594 cp.wasStartMasterCalled());
595 }
596
597 @Test
598 public void testTableOperations() throws Exception {
599 MiniHBaseCluster cluster = UTIL.getHBaseCluster();
600
601 HMaster master = cluster.getMaster();
602 MasterCoprocessorHost host = master.getCoprocessorHost();
603 CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
604 CPMasterObserver.class.getName());
605 cp.enableBypass(true);
606 cp.resetStates();
607 assertFalse("No table created yet", cp.wasCreateTableCalled());
608
609
610 HTableDescriptor htd = new HTableDescriptor(TEST_TABLE);
611 htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
612 HBaseAdmin admin = UTIL.getHBaseAdmin();
613
614 admin.createTable(htd);
615
616 assertTrue("Test table should be created", cp.wasCreateTableCalled());
617
618 admin.disableTable(TEST_TABLE);
619 assertTrue(admin.isTableDisabled(TEST_TABLE));
620
621 assertTrue("Coprocessor should have been called on table disable",
622 cp.wasDisableTableCalled());
623
624
625 assertFalse(cp.wasEnableTableCalled());
626 admin.enableTable(TEST_TABLE);
627 assertTrue(admin.isTableEnabled(TEST_TABLE));
628
629 assertTrue("Coprocessor should have been called on table enable",
630 cp.wasEnableTableCalled());
631
632 admin.disableTable(TEST_TABLE);
633 assertTrue(admin.isTableDisabled(TEST_TABLE));
634
635
636 htd.setMaxFileSize(512 * 1024 * 1024);
637 modifyTableSync(admin, TEST_TABLE, htd);
638
639 assertTrue("Test table should have been modified",
640 cp.wasModifyTableCalled());
641
642
643 admin.addColumn(TEST_TABLE, new HColumnDescriptor(TEST_FAMILY2));
644 assertTrue("New column family shouldn't have been added to test table",
645 cp.preAddColumnCalledOnly());
646
647
648 HColumnDescriptor hcd1 = new HColumnDescriptor(TEST_FAMILY2);
649 hcd1.setMaxVersions(25);
650 admin.modifyColumn(TEST_TABLE, hcd1);
651 assertTrue("Second column family should be modified",
652 cp.preModifyColumnCalledOnly());
653
654
655 admin.deleteTable(TEST_TABLE);
656 assertFalse("Test table should have been deleted",
657 admin.tableExists(TEST_TABLE));
658
659 assertTrue("Coprocessor should have been called on table delete",
660 cp.wasDeleteTableCalled());
661
662
663
664 cp.enableBypass(false);
665 cp.resetStates();
666
667 admin.createTable(htd);
668 assertTrue("Test table should be created", cp.wasCreateTableCalled());
669
670
671 assertFalse(cp.wasDisableTableCalled());
672
673 admin.disableTable(TEST_TABLE);
674 assertTrue(admin.isTableDisabled(TEST_TABLE));
675 assertTrue("Coprocessor should have been called on table disable",
676 cp.wasDisableTableCalled());
677
678
679 htd.setMaxFileSize(512 * 1024 * 1024);
680 modifyTableSync(admin, TEST_TABLE, htd);
681 assertTrue("Test table should have been modified",
682 cp.wasModifyTableCalled());
683
684
685 admin.addColumn(TEST_TABLE, new HColumnDescriptor(TEST_FAMILY2));
686 assertTrue("New column family should have been added to test table",
687 cp.wasAddColumnCalled());
688
689
690 HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY2);
691 hcd.setMaxVersions(25);
692 admin.modifyColumn(TEST_TABLE, hcd);
693 assertTrue("Second column family should be modified",
694 cp.wasModifyColumnCalled());
695
696
697 assertFalse(cp.wasEnableTableCalled());
698 admin.enableTable(TEST_TABLE);
699 assertTrue(admin.isTableEnabled(TEST_TABLE));
700 assertTrue("Coprocessor should have been called on table enable",
701 cp.wasEnableTableCalled());
702
703
704 admin.disableTable(TEST_TABLE);
705 assertTrue(admin.isTableDisabled(TEST_TABLE));
706
707
708 assertFalse("No column family deleted yet", cp.wasDeleteColumnCalled());
709 admin.deleteColumn(TEST_TABLE, TEST_FAMILY2);
710 HTableDescriptor tableDesc = admin.getTableDescriptor(TEST_TABLE);
711 assertNull("'"+Bytes.toString(TEST_FAMILY2)+"' should have been removed",
712 tableDesc.getFamily(TEST_FAMILY2));
713 assertTrue("Coprocessor should have been called on column delete",
714 cp.wasDeleteColumnCalled());
715
716
717 assertFalse("No table deleted yet", cp.wasDeleteTableCalled());
718 admin.deleteTable(TEST_TABLE);
719 assertFalse("Test table should have been deleted",
720 admin.tableExists(TEST_TABLE));
721 assertTrue("Coprocessor should have been called on table delete",
722 cp.wasDeleteTableCalled());
723 }
724
725 private void modifyTableSync(HBaseAdmin admin, byte[] tableName, HTableDescriptor htd)
726 throws IOException {
727 admin.modifyTable(tableName, htd);
728
729 for (int t = 0; t < 100; t++) {
730 HTableDescriptor td = admin.getTableDescriptor(htd.getName());
731 if (td.equals(htd)) {
732 break;
733 }
734 Threads.sleep(100);
735 }
736 }
737
738 @Test
739 public void testRegionTransitionOperations() throws Exception {
740 MiniHBaseCluster cluster = UTIL.getHBaseCluster();
741
742 HMaster master = cluster.getMaster();
743 MasterCoprocessorHost host = master.getCoprocessorHost();
744 CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
745 CPMasterObserver.class.getName());
746 cp.enableBypass(false);
747 cp.resetStates();
748
749 HTable table = UTIL.createTable(TEST_TABLE, TEST_FAMILY);
750 UTIL.createMultiRegions(table, TEST_FAMILY);
751 UTIL.waitUntilAllRegionsAssigned(TEST_TABLE);
752
753 NavigableMap<HRegionInfo, ServerName> regions = table.getRegionLocations();
754 Map.Entry<HRegionInfo, ServerName> firstGoodPair = null;
755 for (Map.Entry<HRegionInfo, ServerName> e: regions.entrySet()) {
756 if (e.getValue() != null) {
757 firstGoodPair = e;
758 break;
759 }
760 }
761 assertNotNull("Found a non-null entry", firstGoodPair);
762 LOG.info("Found " + firstGoodPair.toString());
763
764 Collection<ServerName> servers = master.getClusterStatus().getServers();
765 String destName = null;
766 String firstRegionHostnamePortStr = firstGoodPair.getValue().toString();
767 LOG.info("firstRegionHostnamePortStr=" + firstRegionHostnamePortStr);
768 boolean found = false;
769
770 for (ServerName info : servers) {
771 LOG.info("ServerName=" + info);
772 if (!firstRegionHostnamePortStr.equals(info.getHostAndPort())) {
773 destName = info.toString();
774 found = true;
775 break;
776 }
777 }
778 assertTrue("Found server", found);
779 LOG.info("Found " + destName);
780 master.move(firstGoodPair.getKey().getEncodedNameAsBytes(),
781 Bytes.toBytes(destName));
782 assertTrue("Coprocessor should have been called on region move",
783 cp.wasMoveCalled());
784
785
786 master.balanceSwitch(true);
787 assertTrue("Coprocessor should have been called on balance switch",
788 cp.wasBalanceSwitchCalled());
789
790
791 master.balanceSwitch(false);
792
793 HRegionServer rs = cluster.getRegionServer(0);
794 byte[] destRS = Bytes.toBytes(cluster.getRegionServer(1).getServerName().toString());
795
796 waitForRITtoBeZero(master);
797 List<HRegionInfo> openRegions = rs.getOnlineRegions();
798 int moveCnt = openRegions.size()/2;
799 for (int i=0; i<moveCnt; i++) {
800 HRegionInfo info = openRegions.get(i);
801 if (!info.isMetaTable()) {
802 master.move(openRegions.get(i).getEncodedNameAsBytes(), destRS);
803 }
804 }
805
806 waitForRITtoBeZero(master);
807
808 master.balanceSwitch(true);
809 boolean balanceRun = master.balance();
810 assertTrue("Coprocessor should be called on region rebalancing",
811 cp.wasBalanceCalled());
812 }
813
814 @Test
815 public void testSnapshotOperations() throws Exception {
816 MiniHBaseCluster cluster = UTIL.getHBaseCluster();
817 HMaster master = cluster.getMaster();
818 MasterCoprocessorHost host = master.getCoprocessorHost();
819 CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
820 CPMasterObserver.class.getName());
821 cp.resetStates();
822
823
824 HTableDescriptor htd = new HTableDescriptor(TEST_TABLE);
825 htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
826 HBaseAdmin admin = UTIL.getHBaseAdmin();
827
828
829 if (admin.tableExists(TEST_TABLE)) {
830 UTIL.deleteTable(TEST_TABLE);
831 }
832
833 admin.createTable(htd);
834 admin.disableTable(TEST_TABLE);
835 assertTrue(admin.isTableDisabled(TEST_TABLE));
836
837 try {
838
839 assertFalse("Coprocessor should not have been called yet",
840 cp.wasSnapshotCalled());
841 admin.snapshot(TEST_SNAPSHOT, TEST_TABLE);
842 assertTrue("Coprocessor should have been called on snapshot",
843 cp.wasSnapshotCalled());
844
845
846 admin.cloneSnapshot(TEST_SNAPSHOT, TEST_CLONE);
847 assertTrue("Coprocessor should have been called on snapshot clone",
848 cp.wasCloneSnapshotCalled());
849 assertFalse("Coprocessor restore should not have been called on snapshot clone",
850 cp.wasRestoreSnapshotCalled());
851 admin.disableTable(TEST_CLONE);
852 assertTrue(admin.isTableDisabled(TEST_TABLE));
853 admin.deleteTable(TEST_CLONE);
854
855
856 cp.resetStates();
857 admin.restoreSnapshot(TEST_SNAPSHOT);
858 assertTrue("Coprocessor should have been called on snapshot restore",
859 cp.wasRestoreSnapshotCalled());
860 assertFalse("Coprocessor clone should not have been called on snapshot restore",
861 cp.wasCloneSnapshotCalled());
862
863 admin.deleteSnapshot(TEST_SNAPSHOT);
864 assertTrue("Coprocessor should have been called on snapshot delete",
865 cp.wasDeleteSnapshotCalled());
866 } finally {
867 admin.deleteTable(TEST_TABLE);
868 }
869 }
870
871 private void waitForRITtoBeZero(HMaster master) throws IOException {
872
873 AssignmentManager mgr = master.getAssignmentManager();
874 Collection<AssignmentManager.RegionState> transRegions =
875 mgr.getRegionsInTransition().values();
876 for (AssignmentManager.RegionState state : transRegions) {
877 mgr.waitOnRegionToClearRegionsInTransition(state.getRegion());
878 }
879 }
880
881 @org.junit.Rule
882 public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
883 new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
884 }
885