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