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