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