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.util.ArrayList;
25 import java.util.List;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.fs.Path;
31 import org.apache.hadoop.hbase.HBaseTestCase;
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.CoprocessorEnvironment;
36 import org.apache.hadoop.hbase.Coprocessor;
37 import org.apache.hadoop.hbase.KeyValue;
38 import org.apache.hadoop.hbase.client.Scan;
39 import org.apache.hadoop.hbase.regionserver.InternalScanner;
40 import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
41 import org.apache.hadoop.hbase.regionserver.HRegion;
42 import org.apache.hadoop.hbase.regionserver.RegionScanner;
43 import org.apache.hadoop.hbase.regionserver.SplitTransaction;
44 import org.apache.hadoop.hbase.regionserver.Store;
45 import org.apache.hadoop.hbase.regionserver.StoreFile;
46 import org.apache.hadoop.hbase.util.Bytes;
47 import org.apache.hadoop.hbase.util.PairOfSameType;
48 import org.apache.hadoop.hbase.Server;
49 import org.mockito.Mockito;
50 import org.apache.hadoop.hbase.HBaseTestingUtility;
51 import static org.mockito.Mockito.when;
52
53 public class TestCoprocessorInterface extends HBaseTestCase {
54 static final Log LOG = LogFactory.getLog(TestCoprocessorInterface.class);
55 static final String DIR = "test/build/data/TestCoprocessorInterface/";
56 private static final HBaseTestingUtility TEST_UTIL =
57 new HBaseTestingUtility();
58
59 private static class CustomScanner implements RegionScanner {
60
61 private RegionScanner delegate;
62
63 public CustomScanner(RegionScanner delegate) {
64 this.delegate = delegate;
65 }
66
67 @Override
68 public boolean next(List<KeyValue> results) throws IOException {
69 return delegate.next(results);
70 }
71
72 @Override
73 public boolean next(List<KeyValue> result, int limit) throws IOException {
74 return delegate.next(result, limit);
75 }
76
77 @Override
78 public void close() throws IOException {
79 delegate.close();
80 }
81
82 @Override
83 public HRegionInfo getRegionInfo() {
84 return delegate.getRegionInfo();
85 }
86
87 @Override
88 public boolean isFilterDone() {
89 return delegate.isFilterDone();
90 }
91
92 }
93
94 public static class CoprocessorImpl extends BaseRegionObserver {
95
96 private boolean startCalled;
97 private boolean stopCalled;
98 private boolean preOpenCalled;
99 private boolean postOpenCalled;
100 private boolean preCloseCalled;
101 private boolean postCloseCalled;
102 private boolean preCompactCalled;
103 private boolean postCompactCalled;
104 private boolean preFlushCalled;
105 private boolean postFlushCalled;
106 private boolean preSplitCalled;
107 private boolean postSplitCalled;
108
109 @Override
110 public void start(CoprocessorEnvironment e) {
111 startCalled = true;
112 }
113
114 @Override
115 public void stop(CoprocessorEnvironment e) {
116 stopCalled = true;
117 }
118
119 @Override
120 public void preOpen(ObserverContext<RegionCoprocessorEnvironment> e) {
121 preOpenCalled = true;
122 }
123 @Override
124 public void postOpen(ObserverContext<RegionCoprocessorEnvironment> e) {
125 postOpenCalled = true;
126 }
127 @Override
128 public void preClose(ObserverContext<RegionCoprocessorEnvironment> e, boolean abortRequested) {
129 preCloseCalled = true;
130 }
131 @Override
132 public void postClose(ObserverContext<RegionCoprocessorEnvironment> e, boolean abortRequested) {
133 postCloseCalled = true;
134 }
135 @Override
136 public InternalScanner preCompact(ObserverContext<RegionCoprocessorEnvironment> e,
137 Store store, InternalScanner scanner) {
138 preCompactCalled = true;
139 return scanner;
140 }
141 @Override
142 public void postCompact(ObserverContext<RegionCoprocessorEnvironment> e,
143 Store store, StoreFile resultFile) {
144 postCompactCalled = true;
145 }
146 @Override
147 public void preFlush(ObserverContext<RegionCoprocessorEnvironment> e) {
148 preFlushCalled = true;
149 }
150 @Override
151 public void postFlush(ObserverContext<RegionCoprocessorEnvironment> e) {
152 postFlushCalled = true;
153 }
154 @Override
155 public void preSplit(ObserverContext<RegionCoprocessorEnvironment> e) {
156 preSplitCalled = true;
157 }
158 @Override
159 public void postSplit(ObserverContext<RegionCoprocessorEnvironment> e, HRegion l, HRegion r) {
160 postSplitCalled = true;
161 }
162
163 @Override
164 public RegionScanner postScannerOpen(final ObserverContext<RegionCoprocessorEnvironment> e,
165 final Scan scan, final RegionScanner s) throws IOException {
166 return new CustomScanner(s);
167 }
168
169 boolean wasStarted() {
170 return startCalled;
171 }
172 boolean wasStopped() {
173 return stopCalled;
174 }
175 boolean wasOpened() {
176 return (preOpenCalled && postOpenCalled);
177 }
178 boolean wasClosed() {
179 return (preCloseCalled && postCloseCalled);
180 }
181 boolean wasFlushed() {
182 return (preFlushCalled && postFlushCalled);
183 }
184 boolean wasCompacted() {
185 return (preCompactCalled && postCompactCalled);
186 }
187 boolean wasSplit() {
188 return (preSplitCalled && postSplitCalled);
189 }
190 }
191
192 public void testCoprocessorInterface() throws IOException {
193 byte [] tableName = Bytes.toBytes("testtable");
194 byte [][] families = { fam1, fam2, fam3 };
195
196 Configuration hc = initSplit();
197 HRegion region = initHRegion(tableName, getName(), hc,
198 CoprocessorImpl.class, families);
199 for (int i = 0; i < 3; i++) {
200 addContent(region, fam3);
201 region.flushcache();
202 }
203
204 region.compactStores();
205
206 byte [] splitRow = region.checkSplit();
207
208 assertNotNull(splitRow);
209 HRegion [] regions = split(region, splitRow);
210 for (int i = 0; i < regions.length; i++) {
211 regions[i] = reopenRegion(regions[i], CoprocessorImpl.class);
212 }
213 region.close();
214 region.getLog().closeAndDelete();
215 Coprocessor c = region.getCoprocessorHost().
216 findCoprocessor(CoprocessorImpl.class.getName());
217
218
219 Scan s = new Scan();
220 RegionScanner scanner = regions[0].getCoprocessorHost().postScannerOpen(s, regions[0].getScanner(s));
221 assertTrue(scanner instanceof CustomScanner);
222
223 scanner.next(new ArrayList<KeyValue>());
224
225 assertTrue("Coprocessor not started", ((CoprocessorImpl)c).wasStarted());
226 assertTrue("Coprocessor not stopped", ((CoprocessorImpl)c).wasStopped());
227 assertTrue(((CoprocessorImpl)c).wasOpened());
228 assertTrue(((CoprocessorImpl)c).wasClosed());
229 assertTrue(((CoprocessorImpl)c).wasFlushed());
230 assertTrue(((CoprocessorImpl)c).wasCompacted());
231 assertTrue(((CoprocessorImpl)c).wasSplit());
232
233 for (int i = 0; i < regions.length; i++) {
234 regions[i].close();
235 regions[i].getLog().closeAndDelete();
236 c = region.getCoprocessorHost()
237 .findCoprocessor(CoprocessorImpl.class.getName());
238 assertTrue("Coprocessor not started", ((CoprocessorImpl)c).wasStarted());
239 assertTrue("Coprocessor not stopped", ((CoprocessorImpl)c).wasStopped());
240 assertTrue(((CoprocessorImpl)c).wasOpened());
241 assertTrue(((CoprocessorImpl)c).wasClosed());
242 assertTrue(((CoprocessorImpl)c).wasCompacted());
243 }
244 }
245
246 HRegion reopenRegion(final HRegion closedRegion, Class<?> implClass)
247 throws IOException {
248
249 HRegion r = new HRegion(closedRegion.getTableDir(), closedRegion.getLog(),
250 closedRegion.getFilesystem(), closedRegion.getConf(),
251 closedRegion.getRegionInfo(), closedRegion.getTableDesc(), null);
252 r.initialize();
253
254
255
256
257
258 RegionCoprocessorHost host = new RegionCoprocessorHost(r, null, conf);
259 r.setCoprocessorHost(host);
260
261 host.load(implClass, Coprocessor.PRIORITY_USER, conf);
262
263
264
265
266
267
268 host.preOpen();
269 host.postOpen();
270 return r;
271 }
272
273 HRegion initHRegion (byte [] tableName, String callingMethod,
274 Configuration conf, Class<?> implClass, byte [] ... families)
275 throws IOException {
276 HTableDescriptor htd = new HTableDescriptor(tableName);
277 for(byte [] family : families) {
278 htd.addFamily(new HColumnDescriptor(family));
279 }
280 HRegionInfo info = new HRegionInfo(tableName, null, null, false);
281 Path path = new Path(DIR + callingMethod);
282 HRegion r = HRegion.createHRegion(info, path, conf, htd);
283
284
285 RegionCoprocessorHost host = new RegionCoprocessorHost(r, null, conf);
286 r.setCoprocessorHost(host);
287
288 host.load(implClass, Coprocessor.PRIORITY_USER, conf);
289
290 Coprocessor c = host.findCoprocessor(implClass.getName());
291 assertNotNull(c);
292
293
294 host.preOpen();
295 host.postOpen();
296 return r;
297 }
298
299 Configuration initSplit() {
300
301 TEST_UTIL.getConfiguration().setInt("hbase.hstore.compactionThreshold", 2);
302
303 TEST_UTIL.getConfiguration().setInt(
304 "hbase.master.lease.thread.wakefrequency", 5 * 1000);
305 TEST_UTIL.getConfiguration().setInt(
306 "hbase.regionserver.lease.period", 10 * 1000);
307
308 TEST_UTIL.getConfiguration().setLong("hbase.client.pause", 15 * 1000);
309
310
311 TEST_UTIL.getConfiguration().setLong("hbase.hregion.max.filesize",
312 1024 * 128);
313 TEST_UTIL.getConfiguration().setBoolean("hbase.testing.nocluster",
314 true);
315
316 return TEST_UTIL.getConfiguration();
317 }
318
319 private HRegion [] split(final HRegion r, final byte [] splitRow)
320 throws IOException {
321
322 HRegion[] regions = new HRegion[2];
323
324 SplitTransaction st = new SplitTransaction(r, splitRow);
325 int i = 0;
326
327 if (!st.prepare()) {
328
329 assertTrue(false);
330 }
331 try {
332 Server mockServer = Mockito.mock(Server.class);
333 when(mockServer.getConfiguration()).thenReturn(
334 TEST_UTIL.getConfiguration());
335 PairOfSameType<HRegion> daughters = st.execute(mockServer, null);
336 for (HRegion each_daughter: daughters) {
337 regions[i] = each_daughter;
338 i++;
339 }
340 } catch (IOException ioe) {
341 LOG.info("Split transaction of " + r.getRegionNameAsString() +
342 " failed:" + ioe.getMessage());
343 assertTrue(false);
344 } catch (RuntimeException e) {
345 LOG.info("Failed rollback of failed split of " +
346 r.getRegionNameAsString() + e.getMessage());
347 }
348
349 assertTrue(i == 2);
350 return regions;
351 }
352 }
353
354