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 @SuppressWarnings("null")
106 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NP_NULL_ON_SOME_PATH",
107 justification="Preconditions checks insure we are not going to dereference a null value")
108 public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> env,
109 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
110
111
112 Integer i;
113 i = null;
114 i = i++;
115 }
116
117 public boolean wasCreateTableCalled() {
118 return preCreateTableCalled && postCreateTableCalled;
119 }
120
121 @Override
122 public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx)
123 throws IOException {
124 postStartMasterCalled = true;
125 }
126
127 public boolean wasStartMasterCalled() {
128 return postStartMasterCalled;
129 }
130
131 @Override
132 public void start(CoprocessorEnvironment env) throws IOException {
133 startCalled = true;
134 }
135
136 public boolean wasStarted() {
137 return startCalled;
138 }
139 }
140
141 private static HBaseTestingUtility UTIL = new HBaseTestingUtility();
142 private static byte[] TEST_TABLE = Bytes.toBytes("observed_table");
143 private static byte[] TEST_FAMILY = Bytes.toBytes("fam1");
144
145 @BeforeClass
146 public static void setupBeforeClass() throws Exception {
147 Configuration conf = UTIL.getConfiguration();
148 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
149 BuggyMasterObserver.class.getName());
150 conf.setBoolean(CoprocessorHost.ABORT_ON_ERROR_KEY, true);
151 conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 2);
152 UTIL.startMiniCluster();
153 }
154
155 @AfterClass
156 public static void teardownAfterClass() throws Exception {
157 UTIL.shutdownMiniCluster();
158 }
159
160 @Test(timeout=30000)
161 public void testExceptionFromCoprocessorWhenCreatingTable()
162 throws IOException {
163 MiniHBaseCluster cluster = UTIL.getHBaseCluster();
164
165 HMaster master = cluster.getMaster();
166 MasterCoprocessorHost host = master.getMasterCoprocessorHost();
167 BuggyMasterObserver cp = (BuggyMasterObserver)host.findCoprocessor(
168 BuggyMasterObserver.class.getName());
169 assertFalse("No table created yet", cp.wasCreateTableCalled());
170
171
172
173 ZooKeeperWatcher zkw = new ZooKeeperWatcher(UTIL.getConfiguration(),
174 "unittest", new Abortable() {
175 @Override
176 public void abort(String why, Throwable e) {
177 throw new RuntimeException("Fatal ZK error: " + why, e);
178 }
179 @Override
180 public boolean isAborted() {
181 return false;
182 }
183 });
184
185 MasterTracker masterTracker = new MasterTracker(zkw,"/hbase/master",
186 new Abortable() {
187 @Override
188 public void abort(String why, Throwable e) {
189 throw new RuntimeException("Fatal ZK master tracker error, why=", e);
190 }
191 @Override
192 public boolean isAborted() {
193 return false;
194 }
195 });
196
197 masterTracker.start();
198 zkw.registerListener(masterTracker);
199
200
201
202
203 assertTrue(master.getLoadedCoprocessors().
204 contains(TestMasterCoprocessorExceptionWithAbort.BuggyMasterObserver.class.getName()));
205
206 CreateTableThread createTableThread = new CreateTableThread(UTIL);
207
208
209
210 createTableThread.start();
211
212
213 for (int i = 0; i < 30; i++) {
214 if (masterTracker.masterZKNodeWasDeleted == true) {
215 break;
216 }
217 try {
218 Thread.sleep(1000);
219 } catch (InterruptedException e) {
220 fail("InterruptedException while waiting for master zk node to "
221 + "be deleted.");
222 }
223 }
224
225 assertTrue("Master aborted on coprocessor exception, as expected.",
226 masterTracker.masterZKNodeWasDeleted);
227
228 createTableThread.interrupt();
229 try {
230 createTableThread.join(1000);
231 } catch (InterruptedException e) {
232 assertTrue("Ignoring InterruptedException while waiting for " +
233 " createTableThread.join().", true);
234 }
235 }
236
237 }
238