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 @Override
81 @SuppressWarnings("null")
82 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NP_NULL_ON_SOME_PATH",
83 justification="Preconditions checks insure we are not going to dereference a null value")
84 public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> env,
85 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
86
87
88
89 Integer i;
90 i = null;
91 i = i++;
92 }
93
94 public boolean wasCreateTableCalled() {
95 return preCreateTableCalled && postCreateTableCalled;
96 }
97
98 @Override
99 public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx)
100 throws IOException {
101 postStartMasterCalled = true;
102 }
103
104 public boolean wasStartMasterCalled() {
105 return postStartMasterCalled;
106 }
107
108 @Override
109 public void start(CoprocessorEnvironment env) throws IOException {
110 startCalled = true;
111 }
112
113 public boolean wasStarted() {
114 return startCalled;
115 }
116 }
117
118 private static HBaseTestingUtility UTIL = new HBaseTestingUtility();
119
120 private static byte[] TEST_TABLE1 = Bytes.toBytes("observed_table1");
121 private static byte[] TEST_FAMILY1 = Bytes.toBytes("fam1");
122
123 private static byte[] TEST_TABLE2 = Bytes.toBytes("table2");
124 private static byte[] TEST_FAMILY2 = Bytes.toBytes("fam2");
125
126 @BeforeClass
127 public static void setupBeforeClass() throws Exception {
128 Configuration conf = UTIL.getConfiguration();
129 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
130 BuggyMasterObserver.class.getName());
131 UTIL.getConfiguration().setBoolean(CoprocessorHost.ABORT_ON_ERROR_KEY, false);
132 UTIL.startMiniCluster();
133 }
134
135 @AfterClass
136 public static void teardownAfterClass() throws Exception {
137 UTIL.shutdownMiniCluster();
138 }
139
140 @Test(timeout=30000)
141 public void testExceptionFromCoprocessorWhenCreatingTable()
142 throws IOException {
143 MiniHBaseCluster cluster = UTIL.getHBaseCluster();
144
145 HMaster master = cluster.getMaster();
146 MasterCoprocessorHost host = master.getMasterCoprocessorHost();
147 BuggyMasterObserver cp = (BuggyMasterObserver)host.findCoprocessor(
148 BuggyMasterObserver.class.getName());
149 assertFalse("No table created yet", cp.wasCreateTableCalled());
150
151
152
153
154
155
156
157 ZooKeeperWatcher zkw = new ZooKeeperWatcher(UTIL.getConfiguration(),
158 "unittest", new Abortable() {
159 @Override
160 public void abort(String why, Throwable e) {
161 throw new RuntimeException("Fatal ZK error: " + why, e);
162 }
163 @Override
164 public boolean isAborted() {
165 return false;
166 }
167 });
168
169 MasterTracker masterTracker = new MasterTracker(zkw,"/hbase/master",
170 new Abortable() {
171 @Override
172 public void abort(String why, Throwable e) {
173 throw new RuntimeException("Fatal Zookeeper tracker error, why=", e);
174 }
175 @Override
176 public boolean isAborted() {
177 return false;
178 }
179 });
180
181 masterTracker.start();
182 zkw.registerListener(masterTracker);
183
184
185
186
187 String coprocessorName =
188 BuggyMasterObserver.class.getName();
189 assertTrue(HMaster.getLoadedCoprocessors().contains(coprocessorName));
190
191 HTableDescriptor htd1 = new HTableDescriptor(TableName.valueOf(TEST_TABLE1));
192 htd1.addFamily(new HColumnDescriptor(TEST_FAMILY1));
193
194 boolean threwDNRE = false;
195 try {
196 Admin admin = UTIL.getHBaseAdmin();
197 admin.createTable(htd1);
198 } catch (IOException e) {
199 if (e.getClass().getName().equals("org.apache.hadoop.hbase.DoNotRetryIOException")) {
200 threwDNRE = true;
201 }
202 } finally {
203 assertTrue(threwDNRE);
204 }
205
206
207 try {
208 Thread.sleep(3000);
209 } catch (InterruptedException e) {
210 fail("InterruptedException while sleeping.");
211 }
212
213 assertFalse("Master survived coprocessor NPE, as expected.",
214 masterTracker.masterZKNodeWasDeleted);
215
216 String loadedCoprocessors = HMaster.getLoadedCoprocessors();
217 assertTrue(loadedCoprocessors.contains(coprocessorName));
218
219
220
221 HTableDescriptor htd2 = new HTableDescriptor(TableName.valueOf(TEST_TABLE2));
222 htd2.addFamily(new HColumnDescriptor(TEST_FAMILY2));
223 Admin admin = UTIL.getHBaseAdmin();
224 try {
225 admin.createTable(htd2);
226 } catch (IOException e) {
227 fail("Failed to create table after buggy coprocessor removal: " + e);
228 }
229 }
230
231 }