1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.thrift2;
20
21 import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.*;
22 import static org.apache.thrift.TBaseHelper.byteBufferToByteArray;
23
24 import java.io.IOException;
25 import java.lang.reflect.InvocationHandler;
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28 import java.lang.reflect.Proxy;
29 import java.nio.ByteBuffer;
30 import java.util.Collections;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.concurrent.Callable;
34 import java.util.concurrent.ConcurrentHashMap;
35 import java.util.concurrent.ExecutionException;
36 import java.util.concurrent.TimeUnit;
37 import java.util.concurrent.atomic.AtomicInteger;
38
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41 import org.apache.hadoop.hbase.classification.InterfaceAudience;
42 import org.apache.hadoop.conf.Configuration;
43 import org.apache.hadoop.hbase.client.HTableFactory;
44 import org.apache.hadoop.hbase.client.HTableInterface;
45 import org.apache.hadoop.hbase.client.HTablePool;
46 import org.apache.hadoop.hbase.client.ResultScanner;
47 import org.apache.hadoop.hbase.client.Table;
48 import org.apache.hadoop.hbase.security.UserProvider;
49 import org.apache.hadoop.hbase.thrift.ThriftMetrics;
50 import org.apache.hadoop.hbase.thrift2.generated.*;
51 import org.apache.hadoop.hbase.util.Bytes;
52 import org.apache.hadoop.hbase.util.ConnectionCache;
53 import org.apache.thrift.TException;
54
55 import com.google.common.cache.Cache;
56 import com.google.common.cache.CacheBuilder;
57
58
59
60
61
62 @InterfaceAudience.Private
63 @SuppressWarnings("deprecation")
64 public class ThriftHBaseServiceHandler implements THBaseService.Iface {
65
66
67 private final Cache<String, HTablePool> htablePools;
68 private final Callable<? extends HTablePool> htablePoolCreater;
69 private static final Log LOG = LogFactory.getLog(ThriftHBaseServiceHandler.class);
70
71
72
73 private final AtomicInteger nextScannerId = new AtomicInteger(0);
74 private final Map<Integer, ResultScanner> scannerMap =
75 new ConcurrentHashMap<Integer, ResultScanner>();
76
77 private final ConnectionCache connectionCache;
78 private final HTableFactory tableFactory;
79 private final int maxPoolSize;
80
81 static final String CLEANUP_INTERVAL = "hbase.thrift.connection.cleanup-interval";
82 static final String MAX_IDLETIME = "hbase.thrift.connection.max-idletime";
83
84 public static THBaseService.Iface newInstance(
85 THBaseService.Iface handler, ThriftMetrics metrics) {
86 return (THBaseService.Iface) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
87 new Class[] { THBaseService.Iface.class }, new THBaseServiceMetricsProxy(handler, metrics));
88 }
89
90 private static class THBaseServiceMetricsProxy implements InvocationHandler {
91 private final THBaseService.Iface handler;
92 private final ThriftMetrics metrics;
93
94 private THBaseServiceMetricsProxy(THBaseService.Iface handler, ThriftMetrics metrics) {
95 this.handler = handler;
96 this.metrics = metrics;
97 }
98
99 @Override
100 public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
101 Object result;
102 try {
103 long start = now();
104 result = m.invoke(handler, args);
105 int processTime = (int) (now() - start);
106 metrics.incMethodTime(m.getName(), processTime);
107 } catch (InvocationTargetException e) {
108 throw e.getTargetException();
109 } catch (Exception e) {
110 throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
111 }
112 return result;
113 }
114 }
115
116 private static long now() {
117 return System.nanoTime();
118 }
119
120 ThriftHBaseServiceHandler(final Configuration conf,
121 final UserProvider userProvider) throws IOException {
122 int cleanInterval = conf.getInt(CLEANUP_INTERVAL, 10 * 1000);
123 int maxIdleTime = conf.getInt(MAX_IDLETIME, 10 * 60 * 1000);
124 connectionCache = new ConnectionCache(
125 conf, userProvider, cleanInterval, maxIdleTime);
126 tableFactory = new HTableFactory() {
127 @Override
128 public HTableInterface createHTableInterface(Configuration config,
129 byte[] tableName) {
130 try {
131 return connectionCache.getTable(Bytes.toString(tableName));
132 } catch (IOException ioe) {
133 throw new RuntimeException(ioe);
134 }
135 }
136 };
137 htablePools = CacheBuilder.newBuilder().expireAfterAccess(
138 maxIdleTime, TimeUnit.MILLISECONDS).softValues().concurrencyLevel(4).build();
139 maxPoolSize = conf.getInt("hbase.thrift.htablepool.size.max", 1000);
140 htablePoolCreater = new Callable<HTablePool>() {
141 public HTablePool call() {
142 return new HTablePool(conf, maxPoolSize, tableFactory);
143 }
144 };
145 }
146
147 private Table getTable(ByteBuffer tableName) {
148 String currentUser = connectionCache.getEffectiveUser();
149 try {
150 HTablePool htablePool = htablePools.get(currentUser, htablePoolCreater);
151 return htablePool.getTable(byteBufferToByteArray(tableName));
152 } catch (ExecutionException ee) {
153 throw new RuntimeException(ee);
154 }
155 }
156
157 private void closeTable(Table table) throws TIOError {
158 try {
159 table.close();
160 } catch (IOException e) {
161 throw getTIOError(e);
162 }
163 }
164
165 private TIOError getTIOError(IOException e) {
166 TIOError err = new TIOError();
167 err.setMessage(e.getMessage());
168 return err;
169 }
170
171
172
173
174
175
176 private int addScanner(ResultScanner scanner) {
177 int id = nextScannerId.getAndIncrement();
178 scannerMap.put(id, scanner);
179 return id;
180 }
181
182
183
184
185
186
187 private ResultScanner getScanner(int id) {
188 return scannerMap.get(id);
189 }
190
191 void setEffectiveUser(String effectiveUser) {
192 connectionCache.setEffectiveUser(effectiveUser);
193 }
194
195
196
197
198
199
200 protected ResultScanner removeScanner(int id) {
201 return scannerMap.remove(id);
202 }
203
204 @Override
205 public boolean exists(ByteBuffer table, TGet get) throws TIOError, TException {
206 Table htable = getTable(table);
207 try {
208 return htable.exists(getFromThrift(get));
209 } catch (IOException e) {
210 throw getTIOError(e);
211 } finally {
212 closeTable(htable);
213 }
214 }
215
216 @Override
217 public TResult get(ByteBuffer table, TGet get) throws TIOError, TException {
218 Table htable = getTable(table);
219 try {
220 return resultFromHBase(htable.get(getFromThrift(get)));
221 } catch (IOException e) {
222 throw getTIOError(e);
223 } finally {
224 closeTable(htable);
225 }
226 }
227
228 @Override
229 public List<TResult> getMultiple(ByteBuffer table, List<TGet> gets) throws TIOError, TException {
230 Table htable = getTable(table);
231 try {
232 return resultsFromHBase(htable.get(getsFromThrift(gets)));
233 } catch (IOException e) {
234 throw getTIOError(e);
235 } finally {
236 closeTable(htable);
237 }
238 }
239
240 @Override
241 public void put(ByteBuffer table, TPut put) throws TIOError, TException {
242 Table htable = getTable(table);
243 try {
244 htable.put(putFromThrift(put));
245 } catch (IOException e) {
246 throw getTIOError(e);
247 } finally {
248 closeTable(htable);
249 }
250 }
251
252 @Override
253 public boolean checkAndPut(ByteBuffer table, ByteBuffer row, ByteBuffer family,
254 ByteBuffer qualifier, ByteBuffer value, TPut put) throws TIOError, TException {
255 Table htable = getTable(table);
256 try {
257 return htable.checkAndPut(byteBufferToByteArray(row), byteBufferToByteArray(family),
258 byteBufferToByteArray(qualifier), (value == null) ? null : byteBufferToByteArray(value),
259 putFromThrift(put));
260 } catch (IOException e) {
261 throw getTIOError(e);
262 } finally {
263 closeTable(htable);
264 }
265 }
266
267 @Override
268 public void putMultiple(ByteBuffer table, List<TPut> puts) throws TIOError, TException {
269 Table htable = getTable(table);
270 try {
271 htable.put(putsFromThrift(puts));
272 } catch (IOException e) {
273 throw getTIOError(e);
274 } finally {
275 closeTable(htable);
276 }
277 }
278
279 @Override
280 public void deleteSingle(ByteBuffer table, TDelete deleteSingle) throws TIOError, TException {
281 Table htable = getTable(table);
282 try {
283 htable.delete(deleteFromThrift(deleteSingle));
284 } catch (IOException e) {
285 throw getTIOError(e);
286 } finally {
287 closeTable(htable);
288 }
289 }
290
291 @Override
292 public List<TDelete> deleteMultiple(ByteBuffer table, List<TDelete> deletes) throws TIOError,
293 TException {
294 Table htable = getTable(table);
295 try {
296 htable.delete(deletesFromThrift(deletes));
297 } catch (IOException e) {
298 throw getTIOError(e);
299 } finally {
300 closeTable(htable);
301 }
302 return Collections.emptyList();
303 }
304
305 @Override
306 public boolean checkAndDelete(ByteBuffer table, ByteBuffer row, ByteBuffer family,
307 ByteBuffer qualifier, ByteBuffer value, TDelete deleteSingle) throws TIOError, TException {
308 Table htable = getTable(table);
309
310 try {
311 if (value == null) {
312 return htable.checkAndDelete(byteBufferToByteArray(row), byteBufferToByteArray(family),
313 byteBufferToByteArray(qualifier), null, deleteFromThrift(deleteSingle));
314 } else {
315 return htable.checkAndDelete(byteBufferToByteArray(row), byteBufferToByteArray(family),
316 byteBufferToByteArray(qualifier), byteBufferToByteArray(value),
317 deleteFromThrift(deleteSingle));
318 }
319 } catch (IOException e) {
320 throw getTIOError(e);
321 } finally {
322 closeTable(htable);
323 }
324 }
325
326 @Override
327 public TResult increment(ByteBuffer table, TIncrement increment) throws TIOError, TException {
328 Table htable = getTable(table);
329 try {
330 return resultFromHBase(htable.increment(incrementFromThrift(increment)));
331 } catch (IOException e) {
332 throw getTIOError(e);
333 } finally {
334 closeTable(htable);
335 }
336 }
337
338 @Override
339 public TResult append(ByteBuffer table, TAppend append) throws TIOError, TException {
340 Table htable = getTable(table);
341 try {
342 return resultFromHBase(htable.append(appendFromThrift(append)));
343 } catch (IOException e) {
344 throw getTIOError(e);
345 } finally {
346 closeTable(htable);
347 }
348 }
349
350 @Override
351 public int openScanner(ByteBuffer table, TScan scan) throws TIOError, TException {
352 Table htable = getTable(table);
353 ResultScanner resultScanner = null;
354 try {
355 resultScanner = htable.getScanner(scanFromThrift(scan));
356 } catch (IOException e) {
357 throw getTIOError(e);
358 } finally {
359 closeTable(htable);
360 }
361 return addScanner(resultScanner);
362 }
363
364 @Override
365 public List<TResult> getScannerRows(int scannerId, int numRows) throws TIOError,
366 TIllegalArgument, TException {
367 ResultScanner scanner = getScanner(scannerId);
368 if (scanner == null) {
369 TIllegalArgument ex = new TIllegalArgument();
370 ex.setMessage("Invalid scanner Id");
371 throw ex;
372 }
373
374 try {
375 return resultsFromHBase(scanner.next(numRows));
376 } catch (IOException e) {
377 throw getTIOError(e);
378 }
379 }
380
381 @Override
382 public List<TResult> getScannerResults(ByteBuffer table, TScan scan, int numRows)
383 throws TIOError, TException {
384 Table htable = getTable(table);
385 List<TResult> results = null;
386 ResultScanner scanner = null;
387 try {
388 scanner = htable.getScanner(scanFromThrift(scan));
389 results = resultsFromHBase(scanner.next(numRows));
390 } catch (IOException e) {
391 throw getTIOError(e);
392 } finally {
393 if (scanner != null) {
394 scanner.close();
395 }
396 closeTable(htable);
397 }
398 return results;
399 }
400
401 @Override
402 public void closeScanner(int scannerId) throws TIOError, TIllegalArgument, TException {
403 LOG.debug("scannerClose: id=" + scannerId);
404 ResultScanner scanner = getScanner(scannerId);
405 if (scanner == null) {
406 String message = "scanner ID is invalid";
407 LOG.warn(message);
408 TIllegalArgument ex = new TIllegalArgument();
409 ex.setMessage("Invalid scanner Id");
410 throw ex;
411 }
412 scanner.close();
413 removeScanner(scannerId);
414 }
415
416 @Override
417 public void mutateRow(ByteBuffer table, TRowMutations rowMutations) throws TIOError, TException {
418 Table htable = getTable(table);
419 try {
420 htable.mutateRow(rowMutationsFromThrift(rowMutations));
421 } catch (IOException e) {
422 throw getTIOError(e);
423 } finally {
424 closeTable(htable);
425 }
426 }
427
428 }