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