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
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.conf.Configuration;
28 import org.apache.hadoop.hbase.*;
29 import org.apache.hadoop.hbase.client.HTable;
30 import org.apache.hadoop.hbase.client.Put;
31 import org.apache.hadoop.hbase.regionserver.HRegionServer;
32 import org.apache.hadoop.hbase.util.Bytes;
33 import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
34 import org.apache.hadoop.hbase.zookeeper.ZooKeeperListener;
35 import org.apache.hadoop.hbase.zookeeper.ZooKeeperNodeTracker;
36 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
37 import org.junit.AfterClass;
38 import org.junit.BeforeClass;
39 import org.junit.Test;
40 import org.junit.experimental.categories.Category;
41
42 import static org.junit.Assert.*;
43
44
45
46
47
48
49
50 @Category(MediumTests.class)
51 public class TestRegionServerCoprocessorExceptionWithAbort {
52 static final Log LOG = LogFactory.getLog(TestRegionObserverInterface.class);
53
54 private class zkwAbortable implements Abortable {
55 @Override
56 public void abort(String why, Throwable e) {
57 throw new RuntimeException("Fatal ZK rs tracker error, why=", e);
58 }
59 @Override
60 public boolean isAborted() {
61 return false;
62 }
63 };
64
65 private class RSTracker extends ZooKeeperNodeTracker {
66 public boolean regionZKNodeWasDeleted = false;
67 public String rsNode;
68 private Thread mainThread;
69
70 public RSTracker(ZooKeeperWatcher zkw, String rsNode, Thread mainThread) {
71 super(zkw, rsNode, new zkwAbortable());
72 this.rsNode = rsNode;
73 this.mainThread = mainThread;
74 }
75
76 @Override
77 public synchronized void nodeDeleted(String path) {
78 if (path.equals(rsNode)) {
79 regionZKNodeWasDeleted = true;
80 mainThread.interrupt();
81 }
82 }
83 }
84 private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
85 static final int timeout = 30000;
86
87 @BeforeClass
88 public static void setupBeforeClass() throws Exception {
89
90 Configuration conf = TEST_UTIL.getConfiguration();
91 conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
92 BuggyRegionObserver.class.getName());
93 conf.set("hbase.coprocessor.abortonerror", "true");
94 TEST_UTIL.startMiniCluster(2);
95 }
96
97 @AfterClass
98 public static void teardownAfterClass() throws Exception {
99 TEST_UTIL.shutdownMiniCluster();
100 }
101
102 @Test
103 public void testExceptionFromCoprocessorDuringPut()
104 throws IOException {
105
106
107
108 byte[] TEST_TABLE = Bytes.toBytes("observed_table");
109 byte[] TEST_FAMILY = Bytes.toBytes("aaa");
110
111 HTable table = TEST_UTIL.createTable(TEST_TABLE, TEST_FAMILY);
112 TEST_UTIL.createMultiRegions(table, TEST_FAMILY);
113 TEST_UTIL.waitUntilAllRegionsAssigned(TEST_TABLE);
114
115
116 final HRegionServer regionServer =
117 TEST_UTIL.getRSForFirstRegionInTable(TEST_TABLE);
118
119
120 ZooKeeperWatcher zkw = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
121 "unittest", new zkwAbortable());
122
123 RSTracker rsTracker = new RSTracker(zkw,
124 "/hbase/rs/"+regionServer.getServerName(), Thread.currentThread());
125 rsTracker.start();
126 zkw.registerListener(rsTracker);
127
128 boolean caughtInterruption = false;
129 try {
130 final byte[] ROW = Bytes.toBytes("aaa");
131 Put put = new Put(ROW);
132 put.add(TEST_FAMILY, ROW, ROW);
133 table.put(put);
134 } catch (IOException e) {
135
136
137 if (e.getCause().getClass().equals(InterruptedException.class)) {
138 LOG.debug("caught interruption here (during put()).");
139 caughtInterruption = true;
140 } else {
141 fail("put() failed: " + e);
142 }
143 }
144 if (caughtInterruption == false) {
145 try {
146 Thread.sleep(timeout);
147 fail("RegionServer did not abort within 30 seconds.");
148 } catch (InterruptedException e) {
149
150 LOG.debug("caught interruption here (during sleep()).");
151 caughtInterruption = true;
152 }
153 }
154 assertTrue("Main thread caught interruption.",caughtInterruption);
155 assertTrue("RegionServer aborted on coprocessor exception, as expected.",
156 rsTracker.regionZKNodeWasDeleted);
157 table.close();
158 }
159
160 public static class BuggyRegionObserver extends SimpleRegionObserver {
161 @Override
162 public void prePut(final ObserverContext<RegionCoprocessorEnvironment> c,
163 final Put put, final WALEdit edit,
164 final boolean writeToWAL) {
165 String tableName =
166 c.getEnvironment().getRegion().getRegionInfo().getTableNameAsString();
167 if (tableName.equals("observed_table")) {
168 Integer i = null;
169 i = i + 1;
170 }
171 }
172 }
173
174 @org.junit.Rule
175 public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
176 new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
177 }
178