1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.thrift;
20
21 import java.io.IOException;
22 import java.net.InetAddress;
23 import java.net.InetSocketAddress;
24 import java.net.UnknownHostException;
25 import java.nio.ByteBuffer;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.TreeMap;
32
33 import org.apache.commons.cli.CommandLine;
34 import org.apache.commons.cli.CommandLineParser;
35 import org.apache.commons.cli.HelpFormatter;
36 import org.apache.commons.cli.Option;
37 import org.apache.commons.cli.OptionGroup;
38 import org.apache.commons.cli.Options;
39 import org.apache.commons.cli.PosixParser;
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42 import org.apache.hadoop.conf.Configuration;
43 import org.apache.hadoop.hbase.HBaseConfiguration;
44 import org.apache.hadoop.hbase.HColumnDescriptor;
45 import org.apache.hadoop.hbase.HConstants;
46 import org.apache.hadoop.hbase.HRegionInfo;
47 import org.apache.hadoop.hbase.HTableDescriptor;
48 import org.apache.hadoop.hbase.KeyValue;
49 import org.apache.hadoop.hbase.client.Delete;
50 import org.apache.hadoop.hbase.client.Get;
51 import org.apache.hadoop.hbase.client.HBaseAdmin;
52 import org.apache.hadoop.hbase.client.HTable;
53 import org.apache.hadoop.hbase.client.Put;
54 import org.apache.hadoop.hbase.client.Result;
55 import org.apache.hadoop.hbase.client.ResultScanner;
56 import org.apache.hadoop.hbase.client.Scan;
57 import org.apache.hadoop.hbase.filter.Filter;
58 import org.apache.hadoop.hbase.filter.PrefixFilter;
59 import org.apache.hadoop.hbase.filter.WhileMatchFilter;
60 import org.apache.hadoop.hbase.filter.ParseFilter;
61 import org.apache.hadoop.hbase.thrift.generated.AlreadyExists;
62 import org.apache.hadoop.hbase.thrift.generated.BatchMutation;
63 import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor;
64 import org.apache.hadoop.hbase.thrift.generated.Hbase;
65 import org.apache.hadoop.hbase.thrift.generated.IOError;
66 import org.apache.hadoop.hbase.thrift.generated.IllegalArgument;
67 import org.apache.hadoop.hbase.thrift.generated.Mutation;
68 import org.apache.hadoop.hbase.thrift.generated.TCell;
69 import org.apache.hadoop.hbase.thrift.generated.TRegionInfo;
70 import org.apache.hadoop.hbase.thrift.generated.TRowResult;
71 import org.apache.hadoop.hbase.thrift.generated.TScan;
72 import org.apache.hadoop.hbase.util.Bytes;
73 import org.apache.hadoop.hbase.util.VersionInfo;
74 import org.apache.thrift.TException;
75 import org.apache.thrift.protocol.TBinaryProtocol;
76 import org.apache.thrift.protocol.TCompactProtocol;
77 import org.apache.thrift.protocol.TProtocolFactory;
78 import org.apache.thrift.server.THsHaServer;
79 import org.apache.thrift.server.TNonblockingServer;
80 import org.apache.thrift.server.TServer;
81 import org.apache.thrift.server.TThreadPoolServer;
82 import org.apache.thrift.transport.TFramedTransport;
83 import org.apache.thrift.transport.TNonblockingServerSocket;
84 import org.apache.thrift.transport.TNonblockingServerTransport;
85 import org.apache.thrift.transport.TServerSocket;
86 import org.apache.thrift.transport.TServerTransport;
87 import org.apache.thrift.transport.TTransportFactory;
88
89 import static org.apache.hadoop.hbase.util.Bytes.getBytes;
90
91
92
93
94
95 public class ThriftServer {
96
97
98
99
100
101 public static class HBaseHandler implements Hbase.Iface {
102 protected Configuration conf;
103 protected HBaseAdmin admin = null;
104 protected final Log LOG = LogFactory.getLog(this.getClass().getName());
105
106
107 protected int nextScannerId = 0;
108 protected HashMap<Integer, ResultScanner> scannerMap = null;
109
110 private static ThreadLocal<Map<String, HTable>> threadLocalTables = new ThreadLocal<Map<String, HTable>>() {
111 @Override
112 protected Map<String, HTable> initialValue() {
113 return new TreeMap<String, HTable>();
114 }
115 };
116
117
118
119
120
121
122
123
124 byte[][] getAllColumns(HTable table) throws IOException {
125 HColumnDescriptor[] cds = table.getTableDescriptor().getColumnFamilies();
126 byte[][] columns = new byte[cds.length][];
127 for (int i = 0; i < cds.length; i++) {
128 columns[i] = Bytes.add(cds[i].getName(),
129 KeyValue.COLUMN_FAMILY_DELIM_ARRAY);
130 }
131 return columns;
132 }
133
134
135
136
137
138
139
140
141
142
143 protected HTable getTable(final byte[] tableName) throws
144 IOException {
145 String table = new String(tableName);
146 Map<String, HTable> tables = threadLocalTables.get();
147 if (!tables.containsKey(table)) {
148 tables.put(table, new HTable(conf, tableName));
149 }
150 return tables.get(table);
151 }
152
153 protected HTable getTable(final ByteBuffer tableName) throws IOException {
154 return getTable(getBytes(tableName));
155 }
156
157
158
159
160
161
162
163
164 protected synchronized int addScanner(ResultScanner scanner) {
165 int id = nextScannerId++;
166 scannerMap.put(id, scanner);
167 return id;
168 }
169
170
171
172
173
174
175
176 protected synchronized ResultScanner getScanner(int id) {
177 return scannerMap.get(id);
178 }
179
180
181
182
183
184
185
186
187 protected synchronized ResultScanner removeScanner(int id) {
188 return scannerMap.remove(id);
189 }
190
191
192
193
194
195 HBaseHandler()
196 throws IOException {
197 this(HBaseConfiguration.create());
198 }
199
200 HBaseHandler(final Configuration c)
201 throws IOException {
202 this.conf = c;
203 admin = new HBaseAdmin(conf);
204 scannerMap = new HashMap<Integer, ResultScanner>();
205 }
206
207 @Override
208 public void enableTable(ByteBuffer tableName) throws IOError {
209 try{
210 admin.enableTable(getBytes(tableName));
211 } catch (IOException e) {
212 throw new IOError(e.getMessage());
213 }
214 }
215
216 @Override
217 public void disableTable(ByteBuffer tableName) throws IOError{
218 try{
219 admin.disableTable(getBytes(tableName));
220 } catch (IOException e) {
221 throw new IOError(e.getMessage());
222 }
223 }
224
225 @Override
226 public boolean isTableEnabled(ByteBuffer tableName) throws IOError {
227 try {
228 return HTable.isTableEnabled(this.conf, getBytes(tableName));
229 } catch (IOException e) {
230 throw new IOError(e.getMessage());
231 }
232 }
233
234 @Override
235 public void compact(ByteBuffer tableNameOrRegionName) throws IOError {
236 try{
237 admin.compact(getBytes(tableNameOrRegionName));
238 } catch (InterruptedException e) {
239 throw new IOError(e.getMessage());
240 } catch (IOException e) {
241 throw new IOError(e.getMessage());
242 }
243 }
244
245 @Override
246 public void majorCompact(ByteBuffer tableNameOrRegionName) throws IOError {
247 try{
248 admin.majorCompact(getBytes(tableNameOrRegionName));
249 } catch (InterruptedException e) {
250 throw new IOError(e.getMessage());
251 } catch (IOException e) {
252 throw new IOError(e.getMessage());
253 }
254 }
255
256 @Override
257 public List<ByteBuffer> getTableNames() throws IOError {
258 try {
259 HTableDescriptor[] tables = this.admin.listTables();
260 ArrayList<ByteBuffer> list = new ArrayList<ByteBuffer>(tables.length);
261 for (int i = 0; i < tables.length; i++) {
262 list.add(ByteBuffer.wrap(tables[i].getName()));
263 }
264 return list;
265 } catch (IOException e) {
266 throw new IOError(e.getMessage());
267 }
268 }
269
270 @Override
271 public List<TRegionInfo> getTableRegions(ByteBuffer tableName)
272 throws IOError {
273 try{
274 List<HRegionInfo> hris = this.admin.getTableRegions(tableName.array());
275 List<TRegionInfo> regions = new ArrayList<TRegionInfo>();
276
277 if (hris != null) {
278 for (HRegionInfo regionInfo : hris){
279 TRegionInfo region = new TRegionInfo();
280 region.startKey = ByteBuffer.wrap(regionInfo.getStartKey());
281 region.endKey = ByteBuffer.wrap(regionInfo.getEndKey());
282 region.id = regionInfo.getRegionId();
283 region.name = ByteBuffer.wrap(regionInfo.getRegionName());
284 region.version = regionInfo.getVersion();
285 regions.add(region);
286 }
287 }
288 return regions;
289 } catch (IOException e){
290 throw new IOError(e.getMessage());
291 }
292 }
293
294 @Deprecated
295 @Override
296 public List<TCell> get(ByteBuffer tableName, ByteBuffer row, ByteBuffer column)
297 throws IOError {
298 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
299 if(famAndQf.length == 1) {
300 return get(tableName, row, famAndQf[0], new byte[0]);
301 }
302 return get(tableName, row, famAndQf[0], famAndQf[1]);
303 }
304
305 protected List<TCell> get(ByteBuffer tableName,
306 ByteBuffer row,
307 byte[] family,
308 byte[] qualifier) throws IOError {
309 try {
310 HTable table = getTable(tableName);
311 Get get = new Get(getBytes(row));
312 if (qualifier == null || qualifier.length == 0) {
313 get.addFamily(family);
314 } else {
315 get.addColumn(family, qualifier);
316 }
317 Result result = table.get(get);
318 return ThriftUtilities.cellFromHBase(result.raw());
319 } catch (IOException e) {
320 throw new IOError(e.getMessage());
321 }
322 }
323
324 @Deprecated
325 @Override
326 public List<TCell> getVer(ByteBuffer tableName, ByteBuffer row,
327 ByteBuffer column, int numVersions) throws IOError {
328 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
329 if(famAndQf.length == 1) {
330 return getVer(tableName, row, famAndQf[0],
331 new byte[0], numVersions);
332 }
333 return getVer(tableName, row,
334 famAndQf[0], famAndQf[1], numVersions);
335 }
336
337 public List<TCell> getVer(ByteBuffer tableName, ByteBuffer row,
338 byte[] family,
339 byte[] qualifier, int numVersions) throws IOError {
340 try {
341 HTable table = getTable(tableName);
342 Get get = new Get(getBytes(row));
343 get.addColumn(family, qualifier);
344 get.setMaxVersions(numVersions);
345 Result result = table.get(get);
346 return ThriftUtilities.cellFromHBase(result.raw());
347 } catch (IOException e) {
348 throw new IOError(e.getMessage());
349 }
350 }
351
352 @Deprecated
353 @Override
354 public List<TCell> getVerTs(ByteBuffer tableName,
355 ByteBuffer row,
356 ByteBuffer column,
357 long timestamp,
358 int numVersions) throws IOError {
359 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
360 if(famAndQf.length == 1) {
361 return getVerTs(tableName, row, famAndQf[0], new byte[0], timestamp,
362 numVersions);
363 }
364 return getVerTs(tableName, row, famAndQf[0], famAndQf[1], timestamp,
365 numVersions);
366 }
367
368 protected List<TCell> getVerTs(ByteBuffer tableName,
369 ByteBuffer row, byte [] family,
370 byte [] qualifier, long timestamp, int numVersions) throws IOError {
371 try {
372 HTable table = getTable(tableName);
373 Get get = new Get(getBytes(row));
374 get.addColumn(family, qualifier);
375 get.setTimeRange(Long.MIN_VALUE, timestamp);
376 get.setMaxVersions(numVersions);
377 Result result = table.get(get);
378 return ThriftUtilities.cellFromHBase(result.raw());
379 } catch (IOException e) {
380 throw new IOError(e.getMessage());
381 }
382 }
383
384 @Override
385 public List<TRowResult> getRow(ByteBuffer tableName, ByteBuffer row)
386 throws IOError {
387 return getRowWithColumnsTs(tableName, row, null,
388 HConstants.LATEST_TIMESTAMP);
389 }
390
391 @Override
392 public List<TRowResult> getRowWithColumns(ByteBuffer tableName,
393 ByteBuffer row,
394 List<ByteBuffer> columns) throws IOError {
395 return getRowWithColumnsTs(tableName, row, columns,
396 HConstants.LATEST_TIMESTAMP);
397 }
398
399 @Override
400 public List<TRowResult> getRowTs(ByteBuffer tableName, ByteBuffer row,
401 long timestamp) throws IOError {
402 return getRowWithColumnsTs(tableName, row, null,
403 timestamp);
404 }
405
406 @Override
407 public List<TRowResult> getRowWithColumnsTs(ByteBuffer tableName, ByteBuffer row,
408 List<ByteBuffer> columns, long timestamp) throws IOError {
409 try {
410 HTable table = getTable(tableName);
411 if (columns == null) {
412 Get get = new Get(getBytes(row));
413 get.setTimeRange(Long.MIN_VALUE, timestamp);
414 Result result = table.get(get);
415 return ThriftUtilities.rowResultFromHBase(result);
416 }
417 Get get = new Get(getBytes(row));
418 for(ByteBuffer column : columns) {
419 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
420 if (famAndQf.length == 1) {
421 get.addFamily(famAndQf[0]);
422 } else {
423 get.addColumn(famAndQf[0], famAndQf[1]);
424 }
425 }
426 get.setTimeRange(Long.MIN_VALUE, timestamp);
427 Result result = table.get(get);
428 return ThriftUtilities.rowResultFromHBase(result);
429 } catch (IOException e) {
430 throw new IOError(e.getMessage());
431 }
432 }
433
434 @Override
435 public List<TRowResult> getRows(ByteBuffer tableName,
436 List<ByteBuffer> rows)
437 throws IOError {
438 return getRowsWithColumnsTs(tableName, rows, null,
439 HConstants.LATEST_TIMESTAMP);
440 }
441
442 @Override
443 public List<TRowResult> getRowsWithColumns(ByteBuffer tableName,
444 List<ByteBuffer> rows,
445 List<ByteBuffer> columns) throws IOError {
446 return getRowsWithColumnsTs(tableName, rows, columns,
447 HConstants.LATEST_TIMESTAMP);
448 }
449
450 @Override
451 public List<TRowResult> getRowsTs(ByteBuffer tableName,
452 List<ByteBuffer> rows,
453 long timestamp) throws IOError {
454 return getRowsWithColumnsTs(tableName, rows, null,
455 timestamp);
456 }
457
458 @Override
459 public List<TRowResult> getRowsWithColumnsTs(ByteBuffer tableName,
460 List<ByteBuffer> rows,
461 List<ByteBuffer> columns, long timestamp) throws IOError {
462 try {
463 List<Get> gets = new ArrayList<Get>(rows.size());
464 HTable table = getTable(tableName);
465 for (ByteBuffer row : rows) {
466 Get get = new Get(getBytes(row));
467 if (columns != null) {
468
469 for(ByteBuffer column : columns) {
470 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
471 if (famAndQf.length == 1) {
472 get.addFamily(famAndQf[0]);
473 } else {
474 get.addColumn(famAndQf[0], famAndQf[1]);
475 }
476 }
477 get.setTimeRange(Long.MIN_VALUE, timestamp);
478 }
479 gets.add(get);
480 }
481 Result[] result = table.get(gets);
482 return ThriftUtilities.rowResultFromHBase(result);
483 } catch (IOException e) {
484 throw new IOError(e.getMessage());
485 }
486 }
487
488 @Override
489 public void deleteAll(ByteBuffer tableName, ByteBuffer row, ByteBuffer column)
490 throws IOError {
491 deleteAllTs(tableName, row, column, HConstants.LATEST_TIMESTAMP);
492 }
493
494 @Override
495 public void deleteAllTs(ByteBuffer tableName,
496 ByteBuffer row,
497 ByteBuffer column,
498 long timestamp) throws IOError {
499 try {
500 HTable table = getTable(tableName);
501 Delete delete = new Delete(getBytes(row));
502 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
503 if (famAndQf.length == 1) {
504 delete.deleteFamily(famAndQf[0], timestamp);
505 } else {
506 delete.deleteColumns(famAndQf[0], famAndQf[1], timestamp);
507 }
508 table.delete(delete);
509
510 } catch (IOException e) {
511 throw new IOError(e.getMessage());
512 }
513 }
514
515 @Override
516 public void deleteAllRow(ByteBuffer tableName, ByteBuffer row) throws IOError {
517 deleteAllRowTs(tableName, row, HConstants.LATEST_TIMESTAMP);
518 }
519
520 @Override
521 public void deleteAllRowTs(ByteBuffer tableName, ByteBuffer row, long timestamp)
522 throws IOError {
523 try {
524 HTable table = getTable(tableName);
525 Delete delete = new Delete(getBytes(row), timestamp, null);
526 table.delete(delete);
527 } catch (IOException e) {
528 throw new IOError(e.getMessage());
529 }
530 }
531
532 @Override
533 public void createTable(ByteBuffer in_tableName,
534 List<ColumnDescriptor> columnFamilies) throws IOError,
535 IllegalArgument, AlreadyExists {
536 byte [] tableName = getBytes(in_tableName);
537 try {
538 if (admin.tableExists(tableName)) {
539 throw new AlreadyExists("table name already in use");
540 }
541 HTableDescriptor desc = new HTableDescriptor(tableName);
542 for (ColumnDescriptor col : columnFamilies) {
543 HColumnDescriptor colDesc = ThriftUtilities.colDescFromThrift(col);
544 desc.addFamily(colDesc);
545 }
546 admin.createTable(desc);
547 } catch (IOException e) {
548 throw new IOError(e.getMessage());
549 } catch (IllegalArgumentException e) {
550 throw new IllegalArgument(e.getMessage());
551 }
552 }
553
554 @Override
555 public void deleteTable(ByteBuffer in_tableName) throws IOError {
556 byte [] tableName = getBytes(in_tableName);
557 if (LOG.isDebugEnabled()) {
558 LOG.debug("deleteTable: table=" + Bytes.toString(tableName));
559 }
560 try {
561 if (!admin.tableExists(tableName)) {
562 throw new IOError("table does not exist");
563 }
564 admin.deleteTable(tableName);
565 } catch (IOException e) {
566 throw new IOError(e.getMessage());
567 }
568 }
569
570 @Override
571 public void mutateRow(ByteBuffer tableName, ByteBuffer row,
572 List<Mutation> mutations) throws IOError, IllegalArgument {
573 mutateRowTs(tableName, row, mutations, HConstants.LATEST_TIMESTAMP);
574 }
575
576 @Override
577 public void mutateRowTs(ByteBuffer tableName, ByteBuffer row,
578 List<Mutation> mutations, long timestamp) throws IOError, IllegalArgument {
579 HTable table = null;
580 try {
581 table = getTable(tableName);
582 Put put = new Put(getBytes(row), timestamp, null);
583
584 Delete delete = new Delete(getBytes(row));
585
586
587 for (Mutation m : mutations) {
588 byte[][] famAndQf = KeyValue.parseColumn(getBytes(m.column));
589 if (m.isDelete) {
590 if (famAndQf.length == 1) {
591 delete.deleteFamily(famAndQf[0], timestamp);
592 } else {
593 delete.deleteColumns(famAndQf[0], famAndQf[1], timestamp);
594 }
595 } else {
596 if(famAndQf.length == 1) {
597 put.add(famAndQf[0], HConstants.EMPTY_BYTE_ARRAY,
598 m.value != null ? m.value.array()
599 : HConstants.EMPTY_BYTE_ARRAY);
600 } else {
601 put.add(famAndQf[0], famAndQf[1],
602 m.value != null ? m.value.array()
603 : HConstants.EMPTY_BYTE_ARRAY);
604 }
605 }
606 }
607 if (!delete.isEmpty())
608 table.delete(delete);
609 if (!put.isEmpty())
610 table.put(put);
611 } catch (IOException e) {
612 throw new IOError(e.getMessage());
613 } catch (IllegalArgumentException e) {
614 throw new IllegalArgument(e.getMessage());
615 }
616 }
617
618 @Override
619 public void mutateRows(ByteBuffer tableName, List<BatchMutation> rowBatches)
620 throws IOError, IllegalArgument, TException {
621 mutateRowsTs(tableName, rowBatches, HConstants.LATEST_TIMESTAMP);
622 }
623
624 @Override
625 public void mutateRowsTs(ByteBuffer tableName, List<BatchMutation> rowBatches, long timestamp)
626 throws IOError, IllegalArgument, TException {
627 List<Put> puts = new ArrayList<Put>();
628 List<Delete> deletes = new ArrayList<Delete>();
629
630 for (BatchMutation batch : rowBatches) {
631 byte[] row = getBytes(batch.row);
632 List<Mutation> mutations = batch.mutations;
633 Delete delete = new Delete(row);
634 Put put = new Put(row, timestamp, null);
635 for (Mutation m : mutations) {
636 byte[][] famAndQf = KeyValue.parseColumn(getBytes(m.column));
637 if (m.isDelete) {
638
639 if (famAndQf.length == 1) {
640 delete.deleteFamily(famAndQf[0], timestamp);
641 } else {
642 delete.deleteColumns(famAndQf[0], famAndQf[1], timestamp);
643 }
644 } else {
645 if(famAndQf.length == 1) {
646 put.add(famAndQf[0], HConstants.EMPTY_BYTE_ARRAY,
647 m.value != null ? m.value.array()
648 : HConstants.EMPTY_BYTE_ARRAY);
649 } else {
650 put.add(famAndQf[0], famAndQf[1],
651 m.value != null ? m.value.array()
652 : HConstants.EMPTY_BYTE_ARRAY);
653 }
654 }
655 }
656 if (!delete.isEmpty())
657 deletes.add(delete);
658 if (!put.isEmpty())
659 puts.add(put);
660 }
661
662 HTable table = null;
663 try {
664 table = getTable(tableName);
665 if (!puts.isEmpty())
666 table.put(puts);
667 for (Delete del : deletes) {
668 table.delete(del);
669 }
670 } catch (IOException e) {
671 throw new IOError(e.getMessage());
672 } catch (IllegalArgumentException e) {
673 throw new IllegalArgument(e.getMessage());
674 }
675 }
676
677 @Deprecated
678 @Override
679 public long atomicIncrement(ByteBuffer tableName, ByteBuffer row, ByteBuffer column,
680 long amount) throws IOError, IllegalArgument, TException {
681 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
682 if(famAndQf.length == 1) {
683 return atomicIncrement(tableName, row, famAndQf[0], new byte[0],
684 amount);
685 }
686 return atomicIncrement(tableName, row, famAndQf[0], famAndQf[1], amount);
687 }
688
689 protected long atomicIncrement(ByteBuffer tableName, ByteBuffer row, byte [] family,
690 byte [] qualifier, long amount)
691 throws IOError, IllegalArgument, TException {
692 HTable table;
693 try {
694 table = getTable(tableName);
695 return table.incrementColumnValue(getBytes(row), family, qualifier, amount);
696 } catch (IOException e) {
697 throw new IOError(e.getMessage());
698 }
699 }
700
701 public void scannerClose(int id) throws IOError, IllegalArgument {
702 LOG.debug("scannerClose: id=" + id);
703 ResultScanner scanner = getScanner(id);
704 if (scanner == null) {
705 throw new IllegalArgument("scanner ID is invalid");
706 }
707 scanner.close();
708 removeScanner(id);
709 }
710
711 @Override
712 public List<TRowResult> scannerGetList(int id,int nbRows) throws IllegalArgument, IOError {
713 LOG.debug("scannerGetList: id=" + id);
714 ResultScanner scanner = getScanner(id);
715 if (null == scanner) {
716 throw new IllegalArgument("scanner ID is invalid");
717 }
718
719 Result [] results = null;
720 try {
721 results = scanner.next(nbRows);
722 if (null == results) {
723 return new ArrayList<TRowResult>();
724 }
725 } catch (IOException e) {
726 throw new IOError(e.getMessage());
727 }
728 return ThriftUtilities.rowResultFromHBase(results);
729 }
730 @Override
731 public List<TRowResult> scannerGet(int id) throws IllegalArgument, IOError {
732 return scannerGetList(id,1);
733 }
734
735 public int scannerOpenWithScan(ByteBuffer tableName, TScan tScan) throws IOError {
736 try {
737 HTable table = getTable(tableName);
738 Scan scan = new Scan();
739 if (tScan.isSetStartRow()) {
740 scan.setStartRow(tScan.getStartRow());
741 }
742 if (tScan.isSetStopRow()) {
743 scan.setStopRow(tScan.getStopRow());
744 }
745 if (tScan.isSetTimestamp()) {
746 scan.setTimeRange(Long.MIN_VALUE, tScan.getTimestamp());
747 }
748 if (tScan.isSetCaching()) {
749 scan.setCaching(tScan.getCaching());
750 }
751 if(tScan.isSetColumns() && tScan.getColumns().size() != 0) {
752 for(ByteBuffer column : tScan.getColumns()) {
753 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
754 if(famQf.length == 1) {
755 scan.addFamily(famQf[0]);
756 } else {
757 scan.addColumn(famQf[0], famQf[1]);
758 }
759 }
760 }
761 if (tScan.isSetFilterString()) {
762 ParseFilter parseFilter = new ParseFilter();
763 scan.setFilter(parseFilter.parseFilterString(tScan.getFilterString()));
764 }
765 return addScanner(table.getScanner(scan));
766 } catch (IOException e) {
767 throw new IOError(e.getMessage());
768 }
769 }
770
771 @Override
772 public int scannerOpen(ByteBuffer tableName, ByteBuffer startRow,
773 List<ByteBuffer> columns) throws IOError {
774 try {
775 HTable table = getTable(tableName);
776 Scan scan = new Scan(getBytes(startRow));
777 if(columns != null && columns.size() != 0) {
778 for(ByteBuffer column : columns) {
779 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
780 if(famQf.length == 1) {
781 scan.addFamily(famQf[0]);
782 } else {
783 scan.addColumn(famQf[0], famQf[1]);
784 }
785 }
786 }
787 return addScanner(table.getScanner(scan));
788 } catch (IOException e) {
789 throw new IOError(e.getMessage());
790 }
791 }
792
793 @Override
794 public int scannerOpenWithStop(ByteBuffer tableName, ByteBuffer startRow,
795 ByteBuffer stopRow, List<ByteBuffer> columns) throws IOError, TException {
796 try {
797 HTable table = getTable(tableName);
798 Scan scan = new Scan(getBytes(startRow), getBytes(stopRow));
799 if(columns != null && columns.size() != 0) {
800 for(ByteBuffer column : columns) {
801 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
802 if(famQf.length == 1) {
803 scan.addFamily(famQf[0]);
804 } else {
805 scan.addColumn(famQf[0], famQf[1]);
806 }
807 }
808 }
809 return addScanner(table.getScanner(scan));
810 } catch (IOException e) {
811 throw new IOError(e.getMessage());
812 }
813 }
814
815 @Override
816 public int scannerOpenWithPrefix(ByteBuffer tableName,
817 ByteBuffer startAndPrefix,
818 List<ByteBuffer> columns)
819 throws IOError, TException {
820 try {
821 HTable table = getTable(tableName);
822 Scan scan = new Scan(getBytes(startAndPrefix));
823 Filter f = new WhileMatchFilter(
824 new PrefixFilter(getBytes(startAndPrefix)));
825 scan.setFilter(f);
826 if(columns != null && columns.size() != 0) {
827 for(ByteBuffer column : columns) {
828 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
829 if(famQf.length == 1) {
830 scan.addFamily(famQf[0]);
831 } else {
832 scan.addColumn(famQf[0], famQf[1]);
833 }
834 }
835 }
836 return addScanner(table.getScanner(scan));
837 } catch (IOException e) {
838 throw new IOError(e.getMessage());
839 }
840 }
841
842 @Override
843 public int scannerOpenTs(ByteBuffer tableName, ByteBuffer startRow,
844 List<ByteBuffer> columns, long timestamp) throws IOError, TException {
845 try {
846 HTable table = getTable(tableName);
847 Scan scan = new Scan(getBytes(startRow));
848 scan.setTimeRange(Long.MIN_VALUE, timestamp);
849 if(columns != null && columns.size() != 0) {
850 for(ByteBuffer column : columns) {
851 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
852 if(famQf.length == 1) {
853 scan.addFamily(famQf[0]);
854 } else {
855 scan.addColumn(famQf[0], famQf[1]);
856 }
857 }
858 }
859 return addScanner(table.getScanner(scan));
860 } catch (IOException e) {
861 throw new IOError(e.getMessage());
862 }
863 }
864
865 @Override
866 public int scannerOpenWithStopTs(ByteBuffer tableName, ByteBuffer startRow,
867 ByteBuffer stopRow, List<ByteBuffer> columns, long timestamp)
868 throws IOError, TException {
869 try {
870 HTable table = getTable(tableName);
871 Scan scan = new Scan(getBytes(startRow), getBytes(stopRow));
872 scan.setTimeRange(Long.MIN_VALUE, timestamp);
873 if(columns != null && columns.size() != 0) {
874 for(ByteBuffer column : columns) {
875 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
876 if(famQf.length == 1) {
877 scan.addFamily(famQf[0]);
878 } else {
879 scan.addColumn(famQf[0], famQf[1]);
880 }
881 }
882 }
883 scan.setTimeRange(Long.MIN_VALUE, timestamp);
884 return addScanner(table.getScanner(scan));
885 } catch (IOException e) {
886 throw new IOError(e.getMessage());
887 }
888 }
889
890 @Override
891 public Map<ByteBuffer, ColumnDescriptor> getColumnDescriptors(
892 ByteBuffer tableName) throws IOError, TException {
893 try {
894 TreeMap<ByteBuffer, ColumnDescriptor> columns =
895 new TreeMap<ByteBuffer, ColumnDescriptor>();
896
897 HTable table = getTable(tableName);
898 HTableDescriptor desc = table.getTableDescriptor();
899
900 for (HColumnDescriptor e : desc.getFamilies()) {
901 ColumnDescriptor col = ThriftUtilities.colDescFromHbase(e);
902 columns.put(col.name, col);
903 }
904 return columns;
905 } catch (IOException e) {
906 throw new IOError(e.getMessage());
907 }
908 }
909 }
910
911
912
913
914
915 private static void printUsageAndExit(Options options, int exitCode) {
916 HelpFormatter formatter = new HelpFormatter();
917 formatter.printHelp("Thrift", null, options,
918 "To start the Thrift server run 'bin/hbase-daemon.sh start thrift'\n" +
919 "To shutdown the thrift server run 'bin/hbase-daemon.sh stop thrift' or" +
920 " send a kill signal to the thrift server pid",
921 true);
922 System.exit(exitCode);
923 }
924
925 private static final String DEFAULT_LISTEN_PORT = "9090";
926
927
928
929
930
931 static private void doMain(final String[] args) throws Exception {
932 Log LOG = LogFactory.getLog("ThriftServer");
933
934 Options options = new Options();
935 options.addOption("b", "bind", true, "Address to bind the Thrift server to. Not supported by the Nonblocking and HsHa server [default: 0.0.0.0]");
936 options.addOption("p", "port", true, "Port to bind to [default: 9090]");
937 options.addOption("f", "framed", false, "Use framed transport");
938 options.addOption("c", "compact", false, "Use the compact protocol");
939 options.addOption("h", "help", false, "Print help information");
940
941 OptionGroup servers = new OptionGroup();
942 servers.addOption(new Option("nonblocking", false, "Use the TNonblockingServer. This implies the framed transport."));
943 servers.addOption(new Option("hsha", false, "Use the THsHaServer. This implies the framed transport."));
944 servers.addOption(new Option("threadpool", false, "Use the TThreadPoolServer. This is the default."));
945 options.addOptionGroup(servers);
946
947 CommandLineParser parser = new PosixParser();
948 CommandLine cmd = parser.parse(options, args);
949
950
951
952
953
954
955 List<String> commandLine = Arrays.asList(args);
956 boolean stop = commandLine.contains("stop");
957 boolean start = commandLine.contains("start");
958 if (cmd.hasOption("help") || !start || stop) {
959 printUsageAndExit(options, 1);
960 }
961
962
963 int listenPort = 0;
964 try {
965 listenPort = Integer.parseInt(cmd.getOptionValue("port", DEFAULT_LISTEN_PORT));
966 } catch (NumberFormatException e) {
967 LOG.error("Could not parse the value provided for the port option", e);
968 printUsageAndExit(options, -1);
969 }
970
971
972 TProtocolFactory protocolFactory;
973 if (cmd.hasOption("compact")) {
974 LOG.debug("Using compact protocol");
975 protocolFactory = new TCompactProtocol.Factory();
976 } else {
977 LOG.debug("Using binary protocol");
978 protocolFactory = new TBinaryProtocol.Factory();
979 }
980
981 HBaseHandler handler = new HBaseHandler();
982 Hbase.Processor processor = new Hbase.Processor(handler);
983
984 TServer server;
985 if (cmd.hasOption("nonblocking") || cmd.hasOption("hsha")) {
986 if (cmd.hasOption("bind")) {
987 LOG.error("The Nonblocking and HsHa servers don't support IP address binding at the moment." +
988 " See https://issues.apache.org/jira/browse/HBASE-2155 for details.");
989 printUsageAndExit(options, -1);
990 }
991
992 TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(listenPort);
993 TFramedTransport.Factory transportFactory = new TFramedTransport.Factory();
994
995 if (cmd.hasOption("nonblocking")) {
996 TNonblockingServer.Args serverArgs = new TNonblockingServer.Args(serverTransport);
997 serverArgs.processor(processor);
998 serverArgs.transportFactory(transportFactory);
999 serverArgs.protocolFactory(protocolFactory);
1000
1001 LOG.info("starting HBase Nonblocking Thrift server on " + Integer.toString(listenPort));
1002 server = new TNonblockingServer(serverArgs);
1003 } else {
1004 THsHaServer.Args serverArgs = new THsHaServer.Args(serverTransport);
1005 serverArgs.processor(processor);
1006 serverArgs.transportFactory(transportFactory);
1007 serverArgs.protocolFactory(protocolFactory);
1008
1009 LOG.info("starting HBase HsHA Thrift server on " + Integer.toString(listenPort));
1010 server = new THsHaServer(serverArgs);
1011 }
1012 } else {
1013
1014 InetAddress listenAddress = null;
1015 if (cmd.hasOption("bind")) {
1016 try {
1017 listenAddress = InetAddress.getByName(cmd.getOptionValue("bind"));
1018 } catch (UnknownHostException e) {
1019 LOG.error("Could not bind to provided ip address", e);
1020 printUsageAndExit(options, -1);
1021 }
1022 } else {
1023 listenAddress = InetAddress.getByName("0.0.0.0");
1024 }
1025 TServerTransport serverTransport = new TServerSocket(new InetSocketAddress(listenAddress, listenPort));
1026
1027
1028 TTransportFactory transportFactory;
1029 if (cmd.hasOption("framed")) {
1030 transportFactory = new TFramedTransport.Factory();
1031 LOG.debug("Using framed transport");
1032 } else {
1033 transportFactory = new TTransportFactory();
1034 }
1035
1036 TThreadPoolServer.Args serverArgs = new TThreadPoolServer.Args(serverTransport);
1037 serverArgs.processor(processor);
1038 serverArgs.protocolFactory(protocolFactory);
1039 serverArgs.transportFactory(transportFactory);
1040 LOG.info("starting HBase ThreadPool Thrift server on " + listenAddress + ":" + Integer.toString(listenPort));
1041 server = new TThreadPoolServer(serverArgs);
1042 }
1043
1044 server.serve();
1045 }
1046
1047
1048
1049
1050
1051 public static void main(String [] args) throws Exception {
1052 VersionInfo.logVersion();
1053 doMain(args);
1054 }
1055 }