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.coprocessor;
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
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.hbase.Abortable;
31 import org.apache.hadoop.hbase.CoprocessorEnvironment;
32 import org.apache.hadoop.hbase.HBaseTestingUtility;
33 import org.apache.hadoop.hbase.HColumnDescriptor;
34 import org.apache.hadoop.hbase.HConstants;
35 import org.apache.hadoop.hbase.HRegionInfo;
36 import org.apache.hadoop.hbase.HTableDescriptor;
37 import org.apache.hadoop.hbase.testclassification.MediumTests;
38 import org.apache.hadoop.hbase.MiniHBaseCluster;
39 import org.apache.hadoop.hbase.TableName;
40 import org.apache.hadoop.hbase.client.Admin;
41 import org.apache.hadoop.hbase.master.HMaster;
42 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
43 import org.apache.hadoop.hbase.util.Bytes;
44 import org.apache.hadoop.hbase.zookeeper.ZooKeeperNodeTracker;
45 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
46 import org.junit.AfterClass;
47 import org.junit.BeforeClass;
48 import org.junit.Test;
49 import org.junit.experimental.categories.Category;
50
51
52
53
54
55
56
57 @Category(MediumTests.class)
58 public class TestMasterCoprocessorExceptionWithAbort {
59
60 public static class MasterTracker extends ZooKeeperNodeTracker {
61 public boolean masterZKNodeWasDeleted = false;
62
63 public MasterTracker(ZooKeeperWatcher zkw, String masterNode, Abortable abortable) {
64 super(zkw, masterNode, abortable);
65 }
66
67 @Override
68 public synchronized void nodeDeleted(String path) {
69 if (path.equals("/hbase/master")) {
70 masterZKNodeWasDeleted = true;
71 }
72 }
73 }
74
75 public static class CreateTableThread extends Thread {
76 HBaseTestingUtility UTIL;
77 public CreateTableThread(HBaseTestingUtility UTIL) {
78 this.UTIL = UTIL;
79 }
80
81 @Override
82 public void run() {
83
84
85 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(TEST_TABLE));
86 htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
87 try {
88 Admin admin = UTIL.getHBaseAdmin();
89 admin.createTable(htd);
90 fail("BuggyMasterObserver failed to throw an exception.");
91 } catch (IOException e) {
92 assertEquals("HBaseAdmin threw an interrupted IOException as expected.",
93 e.getClass().getName(), "java.io.InterruptedIOException");
94 }
95 }
96 }
97
98 public static class BuggyMasterObserver extends BaseMasterObserver {
99 private boolean preCreateTableCalled;
100 private boolean postCreateTableCalled;
101 private boolean startCalled;
102 private boolean postStartMasterCalled;
103
104 @Override
105 public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> env,
106 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
107
108
109 Integer i;
110 i = null;
111 i = i++;
112 }
113
114 public boolean wasCreateTableCalled() {
115 return preCreateTableCalled && postCreateTableCalled;
116 }
117
118 @Override
119 public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx)
120 throws IOException {
121 postStartMasterCalled = true;
122 }
123
124 public boolean wasStartMasterCalled() {
125 return postStartMasterCalled;
126 }
127
128 @Override
129 public void start(CoprocessorEnvironment env) throws IOException {
130 startCalled = true;
131 }
132
133 public boolean wasStarted() {
134 return startCalled;
135 }
136 }
137
138 private static HBaseTestingUtility UTIL = new HBaseTestingUtility();
139 private static byte[] TEST_TABLE = Bytes.toBytes("observed_table");
140 private static byte[] TEST_FAMILY = Bytes.toBytes("fam1");
141
142 @BeforeClass
143 public static void setupBeforeClass() throws Exception {
144 Configuration conf = UTIL.getConfiguration();
145 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
146 BuggyMasterObserver.class.getName());
147 conf.setBoolean(CoprocessorHost.ABORT_ON_ERROR_KEY, true);
148 conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 2);
149 UTIL.startMiniCluster();
150 }
151
152 @AfterClass
153 public static void teardownAfterClass() throws Exception {
154 UTIL.shutdownMiniCluster();
155 }
156
157 @Test(timeout=30000)
158 public void testExceptionFromCoprocessorWhenCreatingTable()
159 throws IOException {
160 MiniHBaseCluster cluster = UTIL.getHBaseCluster();
161
162 HMaster master = cluster.getMaster();
163 MasterCoprocessorHost host = master.getMasterCoprocessorHost();
164 BuggyMasterObserver cp = (BuggyMasterObserver)host.findCoprocessor(
165 BuggyMasterObserver.class.getName());
166 assertFalse("No table created yet", cp.wasCreateTableCalled());
167
168
169
170 ZooKeeperWatcher zkw = new ZooKeeperWatcher(UTIL.getConfiguration(),
171 "unittest", new Abortable() {
172 @Override
173 public void abort(String why, Throwable e) {
174 throw new RuntimeException("Fatal ZK error: " + why, e);
175 }
176 @Override
177 public boolean isAborted() {
178 return false;
179 }
180 });
181
182 MasterTracker masterTracker = new MasterTracker(zkw,"/hbase/master",
183 new Abortable() {
184 @Override
185 public void abort(String why, Throwable e) {
186 throw new RuntimeException("Fatal ZK master tracker error, why=", e);
187 }
188 @Override
189 public boolean isAborted() {
190 return false;
191 }
192 });
193
194 masterTracker.start();
195 zkw.registerListener(masterTracker);
196
197
198
199
200 assertTrue(master.getLoadedCoprocessors().
201 contains(TestMasterCoprocessorExceptionWithAbort.BuggyMasterObserver.class.getName()));
202
203 CreateTableThread createTableThread = new CreateTableThread(UTIL);
204
205
206
207 createTableThread.start();
208
209
210 for (int i = 0; i < 30; i++) {
211 if (masterTracker.masterZKNodeWasDeleted == true) {
212 break;
213 }
214 try {
215 Thread.sleep(1000);
216 } catch (InterruptedException e) {
217 fail("InterruptedException while waiting for master zk node to "
218 + "be deleted.");
219 }
220 }
221
222 assertTrue("Master aborted on coprocessor exception, as expected.",
223 masterTracker.masterZKNodeWasDeleted);
224
225 createTableThread.interrupt();
226 try {
227 createTableThread.join(1000);
228 } catch (InterruptedException e) {
229 assertTrue("Ignoring InterruptedException while waiting for " +
230 " createTableThread.join().", true);
231 }
232 }
233
234 }
235