1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.coprocessor;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22
23 import java.io.IOException;
24 import java.util.Collections;
25 import java.util.concurrent.ExecutorService;
26 import java.util.concurrent.SynchronousQueue;
27 import java.util.concurrent.ThreadPoolExecutor;
28 import java.util.concurrent.TimeUnit;
29
30 import org.apache.hadoop.hbase.HBaseTestingUtility;
31 import org.apache.hadoop.hbase.HColumnDescriptor;
32 import org.apache.hadoop.hbase.HTableDescriptor;
33 import org.apache.hadoop.hbase.MediumTests;
34 import org.apache.hadoop.hbase.client.HBaseAdmin;
35 import org.apache.hadoop.hbase.client.HTable;
36 import org.apache.hadoop.hbase.client.HTableInterface;
37 import org.apache.hadoop.hbase.client.Put;
38 import org.apache.hadoop.hbase.client.Result;
39 import org.apache.hadoop.hbase.client.ResultScanner;
40 import org.apache.hadoop.hbase.client.Scan;
41 import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
42 import org.apache.hadoop.hbase.util.Bytes;
43 import org.apache.hadoop.hbase.util.Threads;
44 import org.junit.After;
45 import org.junit.AfterClass;
46 import org.junit.BeforeClass;
47 import org.junit.Test;
48 import org.junit.experimental.categories.Category;
49
50
51
52
53 @Category(MediumTests.class)
54 public class TestOpenTableInCoprocessor {
55
56 private static final byte[] otherTable = Bytes.toBytes("otherTable");
57 private static final byte[] primaryTable = Bytes.toBytes("primary");
58 private static final byte[] family = new byte[] { 'f' };
59
60 private static boolean [] completed = new boolean[1];
61
62
63
64
65 public static class SendToOtherTableCoprocessor extends BaseRegionObserver {
66
67 @Override
68 public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit,
69 boolean writeToWAL) throws IOException {
70 HTableInterface table = e.getEnvironment().getTable(otherTable);
71 table.put(put);
72 table.flushCommits();
73 completed[0] = true;
74 table.close();
75 }
76
77 }
78
79 private static boolean [] completedWithPool = new boolean [1] ;
80
81 public static class CustomThreadPoolCoprocessor extends BaseRegionObserver {
82
83
84
85
86
87
88 private ExecutorService getPool() {
89 int maxThreads = 1;
90 long keepAliveTime = 60;
91 ThreadPoolExecutor pool = new ThreadPoolExecutor(1, maxThreads, keepAliveTime,
92 TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
93 Threads.newDaemonThreadFactory("hbase-table"));
94 pool.allowCoreThreadTimeOut(true);
95 return pool;
96 }
97
98 @Override
99 public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit,
100 boolean writeToWAL) throws IOException {
101 HTableInterface table = e.getEnvironment().getTable(otherTable, getPool());
102 Put p = new Put(new byte[] { 'a' });
103 p.add(family, null, new byte[] { 'a' });
104 try {
105 table.batch(Collections.singletonList(put));
106 } catch (InterruptedException e1) {
107 throw new IOException(e1);
108 }
109 completedWithPool[0] = true;
110 table.close();
111 }
112 }
113
114 private static HBaseTestingUtility UTIL = new HBaseTestingUtility();
115
116 @BeforeClass
117 public static void setupCluster() throws Exception {
118 UTIL.startMiniCluster();
119 }
120
121 @After
122 public void cleanupTestTable() throws Exception {
123 UTIL.getHBaseAdmin().disableTable(primaryTable);
124 UTIL.getHBaseAdmin().deleteTable(primaryTable);
125
126 UTIL.getHBaseAdmin().disableTable(otherTable);
127 UTIL.getHBaseAdmin().deleteTable(otherTable);
128
129 }
130
131 @AfterClass
132 public static void teardownCluster() throws Exception{
133 UTIL.shutdownMiniCluster();
134 }
135
136 @Test
137 public void testCoprocessorCanCreateConnectionToRemoteTable() throws Throwable {
138 runCoprocessorConnectionToRemoteTable(SendToOtherTableCoprocessor.class, completed);
139 }
140
141 @Test
142 public void testCoprocessorCanCreateConnectionToRemoteTableWithCustomPool() throws Throwable {
143 runCoprocessorConnectionToRemoteTable(CustomThreadPoolCoprocessor.class, completedWithPool);
144 }
145
146 private void runCoprocessorConnectionToRemoteTable(Class<? extends BaseRegionObserver> clazz,
147 boolean[] completeCheck) throws Throwable {
148 HTableDescriptor primary = new HTableDescriptor(primaryTable);
149 primary.addFamily(new HColumnDescriptor(family));
150
151 primary.addCoprocessor(clazz.getName());
152
153 HTableDescriptor other = new HTableDescriptor(otherTable);
154 other.addFamily(new HColumnDescriptor(family));
155
156
157 HBaseAdmin admin = UTIL.getHBaseAdmin();
158 admin.createTable(primary);
159 admin.createTable(other);
160
161 HTable table = new HTable(UTIL.getConfiguration(), "primary");
162 Put p = new Put(new byte[] { 'a' });
163 p.add(family, null, new byte[] { 'a' });
164 table.put(p);
165 table.flushCommits();
166 table.close();
167
168 HTable target = new HTable(UTIL.getConfiguration(), otherTable);
169 assertTrue("Didn't complete update to target table!", completeCheck[0]);
170 assertEquals("Didn't find inserted row", 1, getKeyValueCount(target));
171 target.close();
172
173 }
174
175
176
177
178
179
180
181 private int getKeyValueCount(HTable table) throws IOException {
182 Scan scan = new Scan();
183 scan.setMaxVersions(Integer.MAX_VALUE - 1);
184
185 ResultScanner results = table.getScanner(scan);
186 int count = 0;
187 for (Result res : results) {
188 count += res.list().size();
189 System.out.println(count + ") " + res);
190 }
191 results.close();
192
193 return count;
194 }
195 }