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