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 static org.apache.hadoop.hbase.util.Bytes.getBytes;
22
23 import java.io.IOException;
24 import java.net.InetAddress;
25 import java.net.InetSocketAddress;
26 import java.net.UnknownHostException;
27 import java.nio.ByteBuffer;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.TreeMap;
35 import java.util.concurrent.BlockingQueue;
36 import java.util.concurrent.ExecutorService;
37 import java.util.concurrent.LinkedBlockingQueue;
38 import java.util.concurrent.ThreadPoolExecutor;
39 import java.util.concurrent.TimeUnit;
40
41 import org.apache.commons.cli.CommandLine;
42 import org.apache.commons.cli.Option;
43 import org.apache.commons.cli.OptionGroup;
44 import org.apache.commons.logging.Log;
45 import org.apache.commons.logging.LogFactory;
46 import org.apache.hadoop.classification.InterfaceAudience;
47 import org.apache.hadoop.conf.Configuration;
48 import org.apache.hadoop.hbase.HBaseConfiguration;
49 import org.apache.hadoop.hbase.HColumnDescriptor;
50 import org.apache.hadoop.hbase.HConstants;
51 import org.apache.hadoop.hbase.HRegionInfo;
52 import org.apache.hadoop.hbase.HTableDescriptor;
53 import org.apache.hadoop.hbase.KeyValue;
54 import org.apache.hadoop.hbase.ServerName;
55 import org.apache.hadoop.hbase.TableName;
56 import org.apache.hadoop.hbase.TableNotFoundException;
57 import org.apache.hadoop.hbase.client.Delete;
58 import org.apache.hadoop.hbase.client.Get;
59 import org.apache.hadoop.hbase.client.HBaseAdmin;
60 import org.apache.hadoop.hbase.client.HTable;
61 import org.apache.hadoop.hbase.client.Increment;
62 import org.apache.hadoop.hbase.client.OperationWithAttributes;
63 import org.apache.hadoop.hbase.client.Put;
64 import org.apache.hadoop.hbase.client.Result;
65 import org.apache.hadoop.hbase.client.ResultScanner;
66 import org.apache.hadoop.hbase.client.Scan;
67 import org.apache.hadoop.hbase.client.Durability;
68 import org.apache.hadoop.hbase.filter.Filter;
69 import org.apache.hadoop.hbase.filter.ParseFilter;
70 import org.apache.hadoop.hbase.filter.PrefixFilter;
71 import org.apache.hadoop.hbase.filter.WhileMatchFilter;
72 import org.apache.hadoop.hbase.thrift.CallQueue.Call;
73 import org.apache.hadoop.hbase.thrift.generated.AlreadyExists;
74 import org.apache.hadoop.hbase.thrift.generated.BatchMutation;
75 import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor;
76 import org.apache.hadoop.hbase.thrift.generated.Hbase;
77 import org.apache.hadoop.hbase.thrift.generated.IOError;
78 import org.apache.hadoop.hbase.thrift.generated.IllegalArgument;
79 import org.apache.hadoop.hbase.thrift.generated.Mutation;
80 import org.apache.hadoop.hbase.thrift.generated.TCell;
81 import org.apache.hadoop.hbase.thrift.generated.TIncrement;
82 import org.apache.hadoop.hbase.thrift.generated.TRegionInfo;
83 import org.apache.hadoop.hbase.thrift.generated.TRowResult;
84 import org.apache.hadoop.hbase.thrift.generated.TScan;
85 import org.apache.hadoop.hbase.util.Bytes;
86 import org.apache.thrift.TException;
87 import org.apache.thrift.protocol.TBinaryProtocol;
88 import org.apache.thrift.protocol.TCompactProtocol;
89 import org.apache.thrift.protocol.TProtocolFactory;
90 import org.apache.thrift.server.THsHaServer;
91 import org.apache.thrift.server.TNonblockingServer;
92 import org.apache.thrift.server.TServer;
93 import org.apache.thrift.server.TThreadedSelectorServer;
94 import org.apache.thrift.transport.TFramedTransport;
95 import org.apache.thrift.transport.TNonblockingServerSocket;
96 import org.apache.thrift.transport.TNonblockingServerTransport;
97 import org.apache.thrift.transport.TServerSocket;
98 import org.apache.thrift.transport.TServerTransport;
99 import org.apache.thrift.transport.TTransportFactory;
100
101 import com.google.common.base.Joiner;
102 import com.google.common.util.concurrent.ThreadFactoryBuilder;
103
104
105
106
107
108 @InterfaceAudience.Private
109 public class ThriftServerRunner implements Runnable {
110
111 private static final Log LOG = LogFactory.getLog(ThriftServerRunner.class);
112
113 static final String SERVER_TYPE_CONF_KEY =
114 "hbase.regionserver.thrift.server.type";
115
116 static final String BIND_CONF_KEY = "hbase.regionserver.thrift.ipaddress";
117 static final String COMPACT_CONF_KEY = "hbase.regionserver.thrift.compact";
118 static final String FRAMED_CONF_KEY = "hbase.regionserver.thrift.framed";
119 static final String PORT_CONF_KEY = "hbase.regionserver.thrift.port";
120 static final String COALESCE_INC_KEY = "hbase.regionserver.thrift.coalesceIncrement";
121
122 private static final String DEFAULT_BIND_ADDR = "0.0.0.0";
123 public static final int DEFAULT_LISTEN_PORT = 9090;
124 private final int listenPort;
125
126 private Configuration conf;
127 volatile TServer tserver;
128 private final Hbase.Iface handler;
129 private final ThriftMetrics metrics;
130
131
132 enum ImplType {
133 HS_HA("hsha", true, THsHaServer.class, true),
134 NONBLOCKING("nonblocking", true, TNonblockingServer.class, true),
135 THREAD_POOL("threadpool", false, TBoundedThreadPoolServer.class, true),
136 THREADED_SELECTOR(
137 "threadedselector", true, TThreadedSelectorServer.class, true);
138
139 public static final ImplType DEFAULT = THREAD_POOL;
140
141 final String option;
142 final boolean isAlwaysFramed;
143 final Class<? extends TServer> serverClass;
144 final boolean canSpecifyBindIP;
145
146 ImplType(String option, boolean isAlwaysFramed,
147 Class<? extends TServer> serverClass, boolean canSpecifyBindIP) {
148 this.option = option;
149 this.isAlwaysFramed = isAlwaysFramed;
150 this.serverClass = serverClass;
151 this.canSpecifyBindIP = canSpecifyBindIP;
152 }
153
154
155
156
157
158 @Override
159 public String toString() {
160 return "-" + option;
161 }
162
163 String getDescription() {
164 StringBuilder sb = new StringBuilder("Use the " +
165 serverClass.getSimpleName());
166 if (isAlwaysFramed) {
167 sb.append(" This implies the framed transport.");
168 }
169 if (this == DEFAULT) {
170 sb.append("This is the default.");
171 }
172 return sb.toString();
173 }
174
175 static OptionGroup createOptionGroup() {
176 OptionGroup group = new OptionGroup();
177 for (ImplType t : values()) {
178 group.addOption(new Option(t.option, t.getDescription()));
179 }
180 return group;
181 }
182
183 static ImplType getServerImpl(Configuration conf) {
184 String confType = conf.get(SERVER_TYPE_CONF_KEY, THREAD_POOL.option);
185 for (ImplType t : values()) {
186 if (confType.equals(t.option)) {
187 return t;
188 }
189 }
190 throw new AssertionError("Unknown server ImplType.option:" + confType);
191 }
192
193 static void setServerImpl(CommandLine cmd, Configuration conf) {
194 ImplType chosenType = null;
195 int numChosen = 0;
196 for (ImplType t : values()) {
197 if (cmd.hasOption(t.option)) {
198 chosenType = t;
199 ++numChosen;
200 }
201 }
202 if (numChosen < 1) {
203 LOG.info("Using default thrift server type");
204 chosenType = DEFAULT;
205 } else if (numChosen > 1) {
206 throw new AssertionError("Exactly one option out of " +
207 Arrays.toString(values()) + " has to be specified");
208 }
209 LOG.info("Using thrift server type " + chosenType.option);
210 conf.set(SERVER_TYPE_CONF_KEY, chosenType.option);
211 }
212
213 public String simpleClassName() {
214 return serverClass.getSimpleName();
215 }
216
217 public static List<String> serversThatCannotSpecifyBindIP() {
218 List<String> l = new ArrayList<String>();
219 for (ImplType t : values()) {
220 if (!t.canSpecifyBindIP) {
221 l.add(t.simpleClassName());
222 }
223 }
224 return l;
225 }
226
227 }
228
229 public ThriftServerRunner(Configuration conf) throws IOException {
230 this(conf, new ThriftServerRunner.HBaseHandler(conf));
231 }
232
233 public ThriftServerRunner(Configuration conf, HBaseHandler handler) {
234 this.conf = HBaseConfiguration.create(conf);
235 this.listenPort = conf.getInt(PORT_CONF_KEY, DEFAULT_LISTEN_PORT);
236 this.metrics = new ThriftMetrics(conf, ThriftMetrics.ThriftServerType.ONE);
237 handler.initMetrics(metrics);
238 this.handler = HbaseHandlerMetricsProxy.newInstance(handler, metrics, conf);
239 }
240
241
242
243
244 @Override
245 public void run() {
246 try {
247 setupServer();
248 tserver.serve();
249 } catch (Exception e) {
250 LOG.fatal("Cannot run ThriftServer", e);
251
252 System.exit(-1);
253 }
254 }
255
256 public void shutdown() {
257 if (tserver != null) {
258 tserver.stop();
259 tserver = null;
260 }
261 }
262
263
264
265
266 private void setupServer() throws Exception {
267
268 TProtocolFactory protocolFactory;
269 if (conf.getBoolean(COMPACT_CONF_KEY, false)) {
270 LOG.debug("Using compact protocol");
271 protocolFactory = new TCompactProtocol.Factory();
272 } else {
273 LOG.debug("Using binary protocol");
274 protocolFactory = new TBinaryProtocol.Factory();
275 }
276
277 Hbase.Processor<Hbase.Iface> processor =
278 new Hbase.Processor<Hbase.Iface>(handler);
279 ImplType implType = ImplType.getServerImpl(conf);
280
281
282 TTransportFactory transportFactory;
283 if (conf.getBoolean(FRAMED_CONF_KEY, false) || implType.isAlwaysFramed) {
284 transportFactory = new TFramedTransport.Factory();
285 LOG.debug("Using framed transport");
286 } else {
287 transportFactory = new TTransportFactory();
288 }
289
290 if (conf.get(BIND_CONF_KEY) != null && !implType.canSpecifyBindIP) {
291 LOG.error("Server types " + Joiner.on(", ").join(
292 ImplType.serversThatCannotSpecifyBindIP()) + " don't support IP " +
293 "address binding at the moment. See " +
294 "https://issues.apache.org/jira/browse/HBASE-2155 for details.");
295 throw new RuntimeException(
296 "-" + BIND_CONF_KEY + " not supported with " + implType);
297 }
298
299 if (implType == ImplType.HS_HA || implType == ImplType.NONBLOCKING ||
300 implType == ImplType.THREADED_SELECTOR) {
301
302 InetAddress listenAddress = getBindAddress(conf);
303 TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(
304 new InetSocketAddress(listenAddress, listenPort));
305
306 if (implType == ImplType.NONBLOCKING) {
307 TNonblockingServer.Args serverArgs =
308 new TNonblockingServer.Args(serverTransport);
309 serverArgs.processor(processor)
310 .transportFactory(transportFactory)
311 .protocolFactory(protocolFactory);
312 tserver = new TNonblockingServer(serverArgs);
313 } else if (implType == ImplType.HS_HA) {
314 THsHaServer.Args serverArgs = new THsHaServer.Args(serverTransport);
315 CallQueue callQueue =
316 new CallQueue(new LinkedBlockingQueue<Call>(), metrics);
317 ExecutorService executorService = createExecutor(
318 callQueue, serverArgs.getWorkerThreads());
319 serverArgs.executorService(executorService)
320 .processor(processor)
321 .transportFactory(transportFactory)
322 .protocolFactory(protocolFactory);
323 tserver = new THsHaServer(serverArgs);
324 } else {
325 TThreadedSelectorServer.Args serverArgs =
326 new HThreadedSelectorServerArgs(serverTransport, conf);
327 CallQueue callQueue =
328 new CallQueue(new LinkedBlockingQueue<Call>(), metrics);
329 ExecutorService executorService = createExecutor(
330 callQueue, serverArgs.getWorkerThreads());
331 serverArgs.executorService(executorService)
332 .processor(processor)
333 .transportFactory(transportFactory)
334 .protocolFactory(protocolFactory);
335 tserver = new TThreadedSelectorServer(serverArgs);
336 }
337 LOG.info("starting HBase " + implType.simpleClassName() +
338 " server on " + Integer.toString(listenPort));
339 } else if (implType == ImplType.THREAD_POOL) {
340
341 InetAddress listenAddress = getBindAddress(conf);
342
343 TServerTransport serverTransport = new TServerSocket(
344 new InetSocketAddress(listenAddress, listenPort));
345
346 TBoundedThreadPoolServer.Args serverArgs =
347 new TBoundedThreadPoolServer.Args(serverTransport, conf);
348 serverArgs.processor(processor)
349 .transportFactory(transportFactory)
350 .protocolFactory(protocolFactory);
351 LOG.info("starting " + ImplType.THREAD_POOL.simpleClassName() + " on "
352 + listenAddress + ":" + Integer.toString(listenPort)
353 + "; " + serverArgs);
354 TBoundedThreadPoolServer tserver =
355 new TBoundedThreadPoolServer(serverArgs, metrics);
356 this.tserver = tserver;
357 } else {
358 throw new AssertionError("Unsupported Thrift server implementation: " +
359 implType.simpleClassName());
360 }
361
362
363 if (tserver.getClass() != implType.serverClass) {
364 throw new AssertionError("Expected to create Thrift server class " +
365 implType.serverClass.getName() + " but got " +
366 tserver.getClass().getName());
367 }
368
369
370
371 registerFilters(conf);
372 }
373
374 ExecutorService createExecutor(BlockingQueue<Runnable> callQueue,
375 int workerThreads) {
376 ThreadFactoryBuilder tfb = new ThreadFactoryBuilder();
377 tfb.setDaemon(true);
378 tfb.setNameFormat("thrift-worker-%d");
379 return new ThreadPoolExecutor(workerThreads, workerThreads,
380 Long.MAX_VALUE, TimeUnit.SECONDS, callQueue, tfb.build());
381 }
382
383 private InetAddress getBindAddress(Configuration conf)
384 throws UnknownHostException {
385 String bindAddressStr = conf.get(BIND_CONF_KEY, DEFAULT_BIND_ADDR);
386 return InetAddress.getByName(bindAddressStr);
387 }
388
389 protected static class ResultScannerWrapper {
390
391 private final ResultScanner scanner;
392 private final boolean sortColumns;
393 public ResultScannerWrapper(ResultScanner resultScanner,
394 boolean sortResultColumns) {
395 scanner = resultScanner;
396 sortColumns = sortResultColumns;
397 }
398
399 public ResultScanner getScanner() {
400 return scanner;
401 }
402
403 public boolean isColumnSorted() {
404 return sortColumns;
405 }
406 }
407
408
409
410
411
412 public static class HBaseHandler implements Hbase.Iface {
413 protected Configuration conf;
414 protected volatile HBaseAdmin admin = null;
415 protected final Log LOG = LogFactory.getLog(this.getClass().getName());
416
417
418 protected int nextScannerId = 0;
419 protected HashMap<Integer, ResultScannerWrapper> scannerMap = null;
420 private ThriftMetrics metrics = null;
421
422 private static ThreadLocal<Map<String, HTable>> threadLocalTables =
423 new ThreadLocal<Map<String, HTable>>() {
424 @Override
425 protected Map<String, HTable> initialValue() {
426 return new TreeMap<String, HTable>();
427 }
428 };
429
430 IncrementCoalescer coalescer = null;
431
432
433
434
435
436
437
438
439 byte[][] getAllColumns(HTable table) throws IOException {
440 HColumnDescriptor[] cds = table.getTableDescriptor().getColumnFamilies();
441 byte[][] columns = new byte[cds.length][];
442 for (int i = 0; i < cds.length; i++) {
443 columns[i] = Bytes.add(cds[i].getName(),
444 KeyValue.COLUMN_FAMILY_DELIM_ARRAY);
445 }
446 return columns;
447 }
448
449
450
451
452
453
454
455
456
457
458 public HTable getTable(final byte[] tableName) throws
459 IOException {
460 String table = new String(tableName);
461 Map<String, HTable> tables = threadLocalTables.get();
462 if (!tables.containsKey(table)) {
463 tables.put(table, new HTable(conf, tableName));
464 }
465 return tables.get(table);
466 }
467
468 public HTable getTable(final ByteBuffer tableName) throws IOException {
469 return getTable(getBytes(tableName));
470 }
471
472
473
474
475
476
477
478
479 protected synchronized int addScanner(ResultScanner scanner,boolean sortColumns) {
480 int id = nextScannerId++;
481 ResultScannerWrapper resultScannerWrapper = new ResultScannerWrapper(scanner, sortColumns);
482 scannerMap.put(id, resultScannerWrapper);
483 return id;
484 }
485
486
487
488
489
490
491
492 protected synchronized ResultScannerWrapper getScanner(int id) {
493 return scannerMap.get(id);
494 }
495
496
497
498
499
500
501
502
503 protected synchronized ResultScannerWrapper removeScanner(int id) {
504 return scannerMap.remove(id);
505 }
506
507
508
509
510
511 protected HBaseHandler()
512 throws IOException {
513 this(HBaseConfiguration.create());
514 }
515
516 protected HBaseHandler(final Configuration c) throws IOException {
517 this.conf = c;
518 scannerMap = new HashMap<Integer, ResultScannerWrapper>();
519 this.coalescer = new IncrementCoalescer(this);
520 }
521
522
523
524
525 private HBaseAdmin getHBaseAdmin() throws IOException {
526 if (admin == null) {
527 synchronized (this) {
528 if (admin == null) {
529 admin = new HBaseAdmin(conf);
530 }
531 }
532 }
533 return admin;
534 }
535
536 @Override
537 public void enableTable(ByteBuffer tableName) throws IOError {
538 try{
539 getHBaseAdmin().enableTable(getBytes(tableName));
540 } catch (IOException e) {
541 LOG.warn(e.getMessage(), e);
542 throw new IOError(e.getMessage());
543 }
544 }
545
546 @Override
547 public void disableTable(ByteBuffer tableName) throws IOError{
548 try{
549 getHBaseAdmin().disableTable(getBytes(tableName));
550 } catch (IOException e) {
551 LOG.warn(e.getMessage(), e);
552 throw new IOError(e.getMessage());
553 }
554 }
555
556 @Override
557 public boolean isTableEnabled(ByteBuffer tableName) throws IOError {
558 try {
559 return HTable.isTableEnabled(this.conf, getBytes(tableName));
560 } catch (IOException e) {
561 LOG.warn(e.getMessage(), e);
562 throw new IOError(e.getMessage());
563 }
564 }
565
566 @Override
567 public void compact(ByteBuffer tableNameOrRegionName) throws IOError {
568 try{
569 getHBaseAdmin().compact(getBytes(tableNameOrRegionName));
570 } catch (InterruptedException e) {
571 throw new IOError(e.getMessage());
572 } catch (IOException e) {
573 LOG.warn(e.getMessage(), e);
574 throw new IOError(e.getMessage());
575 }
576 }
577
578 @Override
579 public void majorCompact(ByteBuffer tableNameOrRegionName) throws IOError {
580 try{
581 getHBaseAdmin().majorCompact(getBytes(tableNameOrRegionName));
582 } catch (InterruptedException e) {
583 LOG.warn(e.getMessage(), e);
584 throw new IOError(e.getMessage());
585 } catch (IOException e) {
586 LOG.warn(e.getMessage(), e);
587 throw new IOError(e.getMessage());
588 }
589 }
590
591 @Override
592 public List<ByteBuffer> getTableNames() throws IOError {
593 try {
594 HTableDescriptor[] tables = this.getHBaseAdmin().listTables();
595 ArrayList<ByteBuffer> list = new ArrayList<ByteBuffer>(tables.length);
596 for (int i = 0; i < tables.length; i++) {
597 list.add(ByteBuffer.wrap(tables[i].getTableName().getName()));
598 }
599 return list;
600 } catch (IOException e) {
601 LOG.warn(e.getMessage(), e);
602 throw new IOError(e.getMessage());
603 }
604 }
605
606
607
608
609 @Override
610 public List<TRegionInfo> getTableRegions(ByteBuffer tableName)
611 throws IOError {
612 try {
613 HTable table;
614 try {
615 table = getTable(tableName);
616 } catch (TableNotFoundException ex) {
617 return new ArrayList<TRegionInfo>();
618 }
619 Map<HRegionInfo, ServerName> regionLocations =
620 table.getRegionLocations();
621 List<TRegionInfo> results = new ArrayList<TRegionInfo>();
622 for (Map.Entry<HRegionInfo, ServerName> entry :
623 regionLocations.entrySet()) {
624 HRegionInfo info = entry.getKey();
625 ServerName serverName = entry.getValue();
626 TRegionInfo region = new TRegionInfo();
627 region.serverName = ByteBuffer.wrap(
628 Bytes.toBytes(serverName.getHostname()));
629 region.port = serverName.getPort();
630 region.startKey = ByteBuffer.wrap(info.getStartKey());
631 region.endKey = ByteBuffer.wrap(info.getEndKey());
632 region.id = info.getRegionId();
633 region.name = ByteBuffer.wrap(info.getRegionName());
634 region.version = info.getVersion();
635 results.add(region);
636 }
637 return results;
638 } catch (TableNotFoundException e) {
639
640 return Collections.emptyList();
641 } catch (IOException e){
642 LOG.warn(e.getMessage(), e);
643 throw new IOError(e.getMessage());
644 }
645 }
646
647 @Deprecated
648 @Override
649 public List<TCell> get(
650 ByteBuffer tableName, ByteBuffer row, ByteBuffer column,
651 Map<ByteBuffer, ByteBuffer> attributes)
652 throws IOError {
653 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
654 if(famAndQf.length == 1) {
655 return get(tableName, row, famAndQf[0], new byte[0], attributes);
656 }
657 return get(tableName, row, famAndQf[0], famAndQf[1], attributes);
658 }
659
660 protected List<TCell> get(ByteBuffer tableName,
661 ByteBuffer row,
662 byte[] family,
663 byte[] qualifier,
664 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
665 try {
666 HTable table = getTable(tableName);
667 Get get = new Get(getBytes(row));
668 addAttributes(get, attributes);
669 if (qualifier == null || qualifier.length == 0) {
670 get.addFamily(family);
671 } else {
672 get.addColumn(family, qualifier);
673 }
674 Result result = table.get(get);
675 return ThriftUtilities.cellFromHBase(result.raw());
676 } catch (IOException e) {
677 LOG.warn(e.getMessage(), e);
678 throw new IOError(e.getMessage());
679 }
680 }
681
682 @Deprecated
683 @Override
684 public List<TCell> getVer(ByteBuffer tableName, ByteBuffer row,
685 ByteBuffer column, int numVersions,
686 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
687 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
688 if(famAndQf.length == 1) {
689 return getVer(tableName, row, famAndQf[0],
690 new byte[0], numVersions, attributes);
691 }
692 return getVer(tableName, row,
693 famAndQf[0], famAndQf[1], numVersions, attributes);
694 }
695
696 public List<TCell> getVer(ByteBuffer tableName, ByteBuffer row,
697 byte[] family,
698 byte[] qualifier, int numVersions,
699 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
700 try {
701 HTable table = getTable(tableName);
702 Get get = new Get(getBytes(row));
703 addAttributes(get, attributes);
704 get.addColumn(family, qualifier);
705 get.setMaxVersions(numVersions);
706 Result result = table.get(get);
707 return ThriftUtilities.cellFromHBase(result.raw());
708 } catch (IOException e) {
709 LOG.warn(e.getMessage(), e);
710 throw new IOError(e.getMessage());
711 }
712 }
713
714 @Deprecated
715 @Override
716 public List<TCell> getVerTs(ByteBuffer tableName,
717 ByteBuffer row,
718 ByteBuffer column,
719 long timestamp,
720 int numVersions,
721 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
722 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
723 if(famAndQf.length == 1) {
724 return getVerTs(tableName, row, famAndQf[0], new byte[0], timestamp,
725 numVersions, attributes);
726 }
727 return getVerTs(tableName, row, famAndQf[0], famAndQf[1], timestamp,
728 numVersions, attributes);
729 }
730
731 protected List<TCell> getVerTs(ByteBuffer tableName,
732 ByteBuffer row, byte [] family,
733 byte [] qualifier, long timestamp, int numVersions,
734 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
735 try {
736 HTable table = getTable(tableName);
737 Get get = new Get(getBytes(row));
738 addAttributes(get, attributes);
739 get.addColumn(family, qualifier);
740 get.setTimeRange(Long.MIN_VALUE, timestamp);
741 get.setMaxVersions(numVersions);
742 Result result = table.get(get);
743 return ThriftUtilities.cellFromHBase(result.raw());
744 } catch (IOException e) {
745 LOG.warn(e.getMessage(), e);
746 throw new IOError(e.getMessage());
747 }
748 }
749
750 @Override
751 public List<TRowResult> getRow(ByteBuffer tableName, ByteBuffer row,
752 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
753 return getRowWithColumnsTs(tableName, row, null,
754 HConstants.LATEST_TIMESTAMP,
755 attributes);
756 }
757
758 @Override
759 public List<TRowResult> getRowWithColumns(ByteBuffer tableName,
760 ByteBuffer row,
761 List<ByteBuffer> columns,
762 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
763 return getRowWithColumnsTs(tableName, row, columns,
764 HConstants.LATEST_TIMESTAMP,
765 attributes);
766 }
767
768 @Override
769 public List<TRowResult> getRowTs(ByteBuffer tableName, ByteBuffer row,
770 long timestamp, Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
771 return getRowWithColumnsTs(tableName, row, null,
772 timestamp, attributes);
773 }
774
775 @Override
776 public List<TRowResult> getRowWithColumnsTs(
777 ByteBuffer tableName, ByteBuffer row, List<ByteBuffer> columns,
778 long timestamp, Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
779 try {
780 HTable table = getTable(tableName);
781 if (columns == null) {
782 Get get = new Get(getBytes(row));
783 addAttributes(get, attributes);
784 get.setTimeRange(Long.MIN_VALUE, timestamp);
785 Result result = table.get(get);
786 return ThriftUtilities.rowResultFromHBase(result);
787 }
788 Get get = new Get(getBytes(row));
789 addAttributes(get, attributes);
790 for(ByteBuffer column : columns) {
791 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
792 if (famAndQf.length == 1) {
793 get.addFamily(famAndQf[0]);
794 } else {
795 get.addColumn(famAndQf[0], famAndQf[1]);
796 }
797 }
798 get.setTimeRange(Long.MIN_VALUE, timestamp);
799 Result result = table.get(get);
800 return ThriftUtilities.rowResultFromHBase(result);
801 } catch (IOException e) {
802 LOG.warn(e.getMessage(), e);
803 throw new IOError(e.getMessage());
804 }
805 }
806
807 @Override
808 public List<TRowResult> getRows(ByteBuffer tableName,
809 List<ByteBuffer> rows,
810 Map<ByteBuffer, ByteBuffer> attributes)
811 throws IOError {
812 return getRowsWithColumnsTs(tableName, rows, null,
813 HConstants.LATEST_TIMESTAMP,
814 attributes);
815 }
816
817 @Override
818 public List<TRowResult> getRowsWithColumns(ByteBuffer tableName,
819 List<ByteBuffer> rows,
820 List<ByteBuffer> columns,
821 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
822 return getRowsWithColumnsTs(tableName, rows, columns,
823 HConstants.LATEST_TIMESTAMP,
824 attributes);
825 }
826
827 @Override
828 public List<TRowResult> getRowsTs(ByteBuffer tableName,
829 List<ByteBuffer> rows,
830 long timestamp,
831 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
832 return getRowsWithColumnsTs(tableName, rows, null,
833 timestamp, attributes);
834 }
835
836 @Override
837 public List<TRowResult> getRowsWithColumnsTs(ByteBuffer tableName,
838 List<ByteBuffer> rows,
839 List<ByteBuffer> columns, long timestamp,
840 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
841 try {
842 List<Get> gets = new ArrayList<Get>(rows.size());
843 HTable table = getTable(tableName);
844 if (metrics != null) {
845 metrics.incNumRowKeysInBatchGet(rows.size());
846 }
847 for (ByteBuffer row : rows) {
848 Get get = new Get(getBytes(row));
849 addAttributes(get, attributes);
850 if (columns != null) {
851
852 for(ByteBuffer column : columns) {
853 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
854 if (famAndQf.length == 1) {
855 get.addFamily(famAndQf[0]);
856 } else {
857 get.addColumn(famAndQf[0], famAndQf[1]);
858 }
859 }
860 }
861 get.setTimeRange(Long.MIN_VALUE, timestamp);
862 gets.add(get);
863 }
864 Result[] result = table.get(gets);
865 return ThriftUtilities.rowResultFromHBase(result);
866 } catch (IOException e) {
867 LOG.warn(e.getMessage(), e);
868 throw new IOError(e.getMessage());
869 }
870 }
871
872 @Override
873 public void deleteAll(
874 ByteBuffer tableName, ByteBuffer row, ByteBuffer column,
875 Map<ByteBuffer, ByteBuffer> attributes)
876 throws IOError {
877 deleteAllTs(tableName, row, column, HConstants.LATEST_TIMESTAMP,
878 attributes);
879 }
880
881 @Override
882 public void deleteAllTs(ByteBuffer tableName,
883 ByteBuffer row,
884 ByteBuffer column,
885 long timestamp, Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
886 try {
887 HTable table = getTable(tableName);
888 Delete delete = new Delete(getBytes(row));
889 addAttributes(delete, attributes);
890 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
891 if (famAndQf.length == 1) {
892 delete.deleteFamily(famAndQf[0], timestamp);
893 } else {
894 delete.deleteColumns(famAndQf[0], famAndQf[1], timestamp);
895 }
896 table.delete(delete);
897
898 } catch (IOException e) {
899 LOG.warn(e.getMessage(), e);
900 throw new IOError(e.getMessage());
901 }
902 }
903
904 @Override
905 public void deleteAllRow(
906 ByteBuffer tableName, ByteBuffer row,
907 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
908 deleteAllRowTs(tableName, row, HConstants.LATEST_TIMESTAMP, attributes);
909 }
910
911 @Override
912 public void deleteAllRowTs(
913 ByteBuffer tableName, ByteBuffer row, long timestamp,
914 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
915 try {
916 HTable table = getTable(tableName);
917 Delete delete = new Delete(getBytes(row), timestamp);
918 addAttributes(delete, attributes);
919 table.delete(delete);
920 } catch (IOException e) {
921 LOG.warn(e.getMessage(), e);
922 throw new IOError(e.getMessage());
923 }
924 }
925
926 @Override
927 public void createTable(ByteBuffer in_tableName,
928 List<ColumnDescriptor> columnFamilies) throws IOError,
929 IllegalArgument, AlreadyExists {
930 byte [] tableName = getBytes(in_tableName);
931 try {
932 if (getHBaseAdmin().tableExists(tableName)) {
933 throw new AlreadyExists("table name already in use");
934 }
935 HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
936 for (ColumnDescriptor col : columnFamilies) {
937 HColumnDescriptor colDesc = ThriftUtilities.colDescFromThrift(col);
938 desc.addFamily(colDesc);
939 }
940 getHBaseAdmin().createTable(desc);
941 } catch (IOException e) {
942 LOG.warn(e.getMessage(), e);
943 throw new IOError(e.getMessage());
944 } catch (IllegalArgumentException e) {
945 LOG.warn(e.getMessage(), e);
946 throw new IllegalArgument(e.getMessage());
947 }
948 }
949
950 @Override
951 public void deleteTable(ByteBuffer in_tableName) throws IOError {
952 byte [] tableName = getBytes(in_tableName);
953 if (LOG.isDebugEnabled()) {
954 LOG.debug("deleteTable: table=" + Bytes.toString(tableName));
955 }
956 try {
957 if (!getHBaseAdmin().tableExists(tableName)) {
958 throw new IOException("table does not exist");
959 }
960 getHBaseAdmin().deleteTable(tableName);
961 } catch (IOException e) {
962 LOG.warn(e.getMessage(), e);
963 throw new IOError(e.getMessage());
964 }
965 }
966
967 @Override
968 public void mutateRow(ByteBuffer tableName, ByteBuffer row,
969 List<Mutation> mutations, Map<ByteBuffer, ByteBuffer> attributes)
970 throws IOError, IllegalArgument {
971 mutateRowTs(tableName, row, mutations, HConstants.LATEST_TIMESTAMP,
972 attributes);
973 }
974
975 @Override
976 public void mutateRowTs(ByteBuffer tableName, ByteBuffer row,
977 List<Mutation> mutations, long timestamp,
978 Map<ByteBuffer, ByteBuffer> attributes)
979 throws IOError, IllegalArgument {
980 HTable table = null;
981 try {
982 table = getTable(tableName);
983 Put put = new Put(getBytes(row), timestamp);
984 addAttributes(put, attributes);
985
986 Delete delete = new Delete(getBytes(row));
987 addAttributes(delete, attributes);
988 if (metrics != null) {
989 metrics.incNumRowKeysInBatchMutate(mutations.size());
990 }
991
992
993 for (Mutation m : mutations) {
994 byte[][] famAndQf = KeyValue.parseColumn(getBytes(m.column));
995 if (m.isDelete) {
996 if (famAndQf.length == 1) {
997 delete.deleteFamily(famAndQf[0], timestamp);
998 } else {
999 delete.deleteColumns(famAndQf[0], famAndQf[1], timestamp);
1000 }
1001 delete.setDurability(m.writeToWAL ? Durability.SYNC_WAL
1002 : Durability.SKIP_WAL);
1003 } else {
1004 if(famAndQf.length == 1) {
1005 put.add(famAndQf[0], HConstants.EMPTY_BYTE_ARRAY,
1006 m.value != null ? getBytes(m.value)
1007 : HConstants.EMPTY_BYTE_ARRAY);
1008 } else {
1009 put.add(famAndQf[0], famAndQf[1],
1010 m.value != null ? getBytes(m.value)
1011 : HConstants.EMPTY_BYTE_ARRAY);
1012 }
1013 put.setDurability(m.writeToWAL ? Durability.SYNC_WAL : Durability.SKIP_WAL);
1014 }
1015 }
1016 if (!delete.isEmpty())
1017 table.delete(delete);
1018 if (!put.isEmpty())
1019 table.put(put);
1020 } catch (IOException e) {
1021 LOG.warn(e.getMessage(), e);
1022 throw new IOError(e.getMessage());
1023 } catch (IllegalArgumentException e) {
1024 LOG.warn(e.getMessage(), e);
1025 throw new IllegalArgument(e.getMessage());
1026 }
1027 }
1028
1029 @Override
1030 public void mutateRows(ByteBuffer tableName, List<BatchMutation> rowBatches,
1031 Map<ByteBuffer, ByteBuffer> attributes)
1032 throws IOError, IllegalArgument, TException {
1033 mutateRowsTs(tableName, rowBatches, HConstants.LATEST_TIMESTAMP, attributes);
1034 }
1035
1036 @Override
1037 public void mutateRowsTs(
1038 ByteBuffer tableName, List<BatchMutation> rowBatches, long timestamp,
1039 Map<ByteBuffer, ByteBuffer> attributes)
1040 throws IOError, IllegalArgument, TException {
1041 List<Put> puts = new ArrayList<Put>();
1042 List<Delete> deletes = new ArrayList<Delete>();
1043
1044 for (BatchMutation batch : rowBatches) {
1045 byte[] row = getBytes(batch.row);
1046 List<Mutation> mutations = batch.mutations;
1047 Delete delete = new Delete(row);
1048 addAttributes(delete, attributes);
1049 Put put = new Put(row, timestamp);
1050 addAttributes(put, attributes);
1051 for (Mutation m : mutations) {
1052 byte[][] famAndQf = KeyValue.parseColumn(getBytes(m.column));
1053 if (m.isDelete) {
1054
1055 if (famAndQf.length == 1) {
1056 delete.deleteFamily(famAndQf[0], timestamp);
1057 } else {
1058 delete.deleteColumns(famAndQf[0], famAndQf[1], timestamp);
1059 }
1060 delete.setDurability(m.writeToWAL ? Durability.SYNC_WAL
1061 : Durability.SKIP_WAL);
1062 } else {
1063 if(famAndQf.length == 1) {
1064 put.add(famAndQf[0], HConstants.EMPTY_BYTE_ARRAY,
1065 m.value != null ? getBytes(m.value)
1066 : HConstants.EMPTY_BYTE_ARRAY);
1067 } else {
1068 put.add(famAndQf[0], famAndQf[1],
1069 m.value != null ? getBytes(m.value)
1070 : HConstants.EMPTY_BYTE_ARRAY);
1071 }
1072 put.setDurability(m.writeToWAL ? Durability.SYNC_WAL : Durability.SKIP_WAL);
1073 }
1074 }
1075 if (!delete.isEmpty())
1076 deletes.add(delete);
1077 if (!put.isEmpty())
1078 puts.add(put);
1079 }
1080
1081 HTable table = null;
1082 try {
1083 table = getTable(tableName);
1084 if (!puts.isEmpty())
1085 table.put(puts);
1086 if (!deletes.isEmpty())
1087 table.delete(deletes);
1088
1089 } catch (IOException e) {
1090 LOG.warn(e.getMessage(), e);
1091 throw new IOError(e.getMessage());
1092 } catch (IllegalArgumentException e) {
1093 LOG.warn(e.getMessage(), e);
1094 throw new IllegalArgument(e.getMessage());
1095 }
1096 }
1097
1098 @Deprecated
1099 @Override
1100 public long atomicIncrement(
1101 ByteBuffer tableName, ByteBuffer row, ByteBuffer column, long amount)
1102 throws IOError, IllegalArgument, TException {
1103 byte [][] famAndQf = KeyValue.parseColumn(getBytes(column));
1104 if(famAndQf.length == 1) {
1105 return atomicIncrement(tableName, row, famAndQf[0], new byte[0],
1106 amount);
1107 }
1108 return atomicIncrement(tableName, row, famAndQf[0], famAndQf[1], amount);
1109 }
1110
1111 protected long atomicIncrement(ByteBuffer tableName, ByteBuffer row,
1112 byte [] family, byte [] qualifier, long amount)
1113 throws IOError, IllegalArgument, TException {
1114 HTable table;
1115 try {
1116 table = getTable(tableName);
1117 return table.incrementColumnValue(
1118 getBytes(row), family, qualifier, amount);
1119 } catch (IOException e) {
1120 LOG.warn(e.getMessage(), e);
1121 throw new IOError(e.getMessage());
1122 }
1123 }
1124
1125 public void scannerClose(int id) throws IOError, IllegalArgument {
1126 LOG.debug("scannerClose: id=" + id);
1127 ResultScannerWrapper resultScannerWrapper = getScanner(id);
1128 if (resultScannerWrapper == null) {
1129 String message = "scanner ID is invalid";
1130 LOG.warn(message);
1131 throw new IllegalArgument("scanner ID is invalid");
1132 }
1133 resultScannerWrapper.getScanner().close();
1134 removeScanner(id);
1135 }
1136
1137 @Override
1138 public List<TRowResult> scannerGetList(int id,int nbRows)
1139 throws IllegalArgument, IOError {
1140 LOG.debug("scannerGetList: id=" + id);
1141 ResultScannerWrapper resultScannerWrapper = getScanner(id);
1142 if (null == resultScannerWrapper) {
1143 String message = "scanner ID is invalid";
1144 LOG.warn(message);
1145 throw new IllegalArgument("scanner ID is invalid");
1146 }
1147
1148 Result [] results = null;
1149 try {
1150 results = resultScannerWrapper.getScanner().next(nbRows);
1151 if (null == results) {
1152 return new ArrayList<TRowResult>();
1153 }
1154 } catch (IOException e) {
1155 LOG.warn(e.getMessage(), e);
1156 throw new IOError(e.getMessage());
1157 }
1158 return ThriftUtilities.rowResultFromHBase(results, resultScannerWrapper.isColumnSorted());
1159 }
1160
1161 @Override
1162 public List<TRowResult> scannerGet(int id) throws IllegalArgument, IOError {
1163 return scannerGetList(id,1);
1164 }
1165
1166 public int scannerOpenWithScan(ByteBuffer tableName, TScan tScan,
1167 Map<ByteBuffer, ByteBuffer> attributes)
1168 throws IOError {
1169 try {
1170 HTable table = getTable(tableName);
1171 Scan scan = new Scan();
1172 addAttributes(scan, attributes);
1173 if (tScan.isSetStartRow()) {
1174 scan.setStartRow(tScan.getStartRow());
1175 }
1176 if (tScan.isSetStopRow()) {
1177 scan.setStopRow(tScan.getStopRow());
1178 }
1179 if (tScan.isSetTimestamp()) {
1180 scan.setTimeRange(Long.MIN_VALUE, tScan.getTimestamp());
1181 }
1182 if (tScan.isSetCaching()) {
1183 scan.setCaching(tScan.getCaching());
1184 }
1185 if (tScan.isSetBatchSize()) {
1186 scan.setBatch(tScan.getBatchSize());
1187 }
1188 if (tScan.isSetColumns() && tScan.getColumns().size() != 0) {
1189 for(ByteBuffer column : tScan.getColumns()) {
1190 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
1191 if(famQf.length == 1) {
1192 scan.addFamily(famQf[0]);
1193 } else {
1194 scan.addColumn(famQf[0], famQf[1]);
1195 }
1196 }
1197 }
1198 if (tScan.isSetFilterString()) {
1199 ParseFilter parseFilter = new ParseFilter();
1200 scan.setFilter(
1201 parseFilter.parseFilterString(tScan.getFilterString()));
1202 }
1203 return addScanner(table.getScanner(scan), tScan.sortColumns);
1204 } catch (IOException e) {
1205 LOG.warn(e.getMessage(), e);
1206 throw new IOError(e.getMessage());
1207 }
1208 }
1209
1210 @Override
1211 public int scannerOpen(ByteBuffer tableName, ByteBuffer startRow,
1212 List<ByteBuffer> columns,
1213 Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
1214 try {
1215 HTable table = getTable(tableName);
1216 Scan scan = new Scan(getBytes(startRow));
1217 addAttributes(scan, attributes);
1218 if(columns != null && columns.size() != 0) {
1219 for(ByteBuffer column : columns) {
1220 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
1221 if(famQf.length == 1) {
1222 scan.addFamily(famQf[0]);
1223 } else {
1224 scan.addColumn(famQf[0], famQf[1]);
1225 }
1226 }
1227 }
1228 return addScanner(table.getScanner(scan), false);
1229 } catch (IOException e) {
1230 LOG.warn(e.getMessage(), e);
1231 throw new IOError(e.getMessage());
1232 }
1233 }
1234
1235 @Override
1236 public int scannerOpenWithStop(ByteBuffer tableName, ByteBuffer startRow,
1237 ByteBuffer stopRow, List<ByteBuffer> columns,
1238 Map<ByteBuffer, ByteBuffer> attributes)
1239 throws IOError, TException {
1240 try {
1241 HTable table = getTable(tableName);
1242 Scan scan = new Scan(getBytes(startRow), getBytes(stopRow));
1243 addAttributes(scan, attributes);
1244 if(columns != null && columns.size() != 0) {
1245 for(ByteBuffer column : columns) {
1246 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
1247 if(famQf.length == 1) {
1248 scan.addFamily(famQf[0]);
1249 } else {
1250 scan.addColumn(famQf[0], famQf[1]);
1251 }
1252 }
1253 }
1254 return addScanner(table.getScanner(scan), false);
1255 } catch (IOException e) {
1256 LOG.warn(e.getMessage(), e);
1257 throw new IOError(e.getMessage());
1258 }
1259 }
1260
1261 @Override
1262 public int scannerOpenWithPrefix(ByteBuffer tableName,
1263 ByteBuffer startAndPrefix,
1264 List<ByteBuffer> columns,
1265 Map<ByteBuffer, ByteBuffer> attributes)
1266 throws IOError, TException {
1267 try {
1268 HTable table = getTable(tableName);
1269 Scan scan = new Scan(getBytes(startAndPrefix));
1270 addAttributes(scan, attributes);
1271 Filter f = new WhileMatchFilter(
1272 new PrefixFilter(getBytes(startAndPrefix)));
1273 scan.setFilter(f);
1274 if (columns != null && columns.size() != 0) {
1275 for(ByteBuffer column : columns) {
1276 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
1277 if(famQf.length == 1) {
1278 scan.addFamily(famQf[0]);
1279 } else {
1280 scan.addColumn(famQf[0], famQf[1]);
1281 }
1282 }
1283 }
1284 return addScanner(table.getScanner(scan), false);
1285 } catch (IOException e) {
1286 LOG.warn(e.getMessage(), e);
1287 throw new IOError(e.getMessage());
1288 }
1289 }
1290
1291 @Override
1292 public int scannerOpenTs(ByteBuffer tableName, ByteBuffer startRow,
1293 List<ByteBuffer> columns, long timestamp,
1294 Map<ByteBuffer, ByteBuffer> attributes) throws IOError, TException {
1295 try {
1296 HTable table = getTable(tableName);
1297 Scan scan = new Scan(getBytes(startRow));
1298 addAttributes(scan, attributes);
1299 scan.setTimeRange(Long.MIN_VALUE, timestamp);
1300 if (columns != null && columns.size() != 0) {
1301 for (ByteBuffer column : columns) {
1302 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
1303 if(famQf.length == 1) {
1304 scan.addFamily(famQf[0]);
1305 } else {
1306 scan.addColumn(famQf[0], famQf[1]);
1307 }
1308 }
1309 }
1310 return addScanner(table.getScanner(scan), false);
1311 } catch (IOException e) {
1312 LOG.warn(e.getMessage(), e);
1313 throw new IOError(e.getMessage());
1314 }
1315 }
1316
1317 @Override
1318 public int scannerOpenWithStopTs(ByteBuffer tableName, ByteBuffer startRow,
1319 ByteBuffer stopRow, List<ByteBuffer> columns, long timestamp,
1320 Map<ByteBuffer, ByteBuffer> attributes)
1321 throws IOError, TException {
1322 try {
1323 HTable table = getTable(tableName);
1324 Scan scan = new Scan(getBytes(startRow), getBytes(stopRow));
1325 addAttributes(scan, attributes);
1326 scan.setTimeRange(Long.MIN_VALUE, timestamp);
1327 if (columns != null && columns.size() != 0) {
1328 for (ByteBuffer column : columns) {
1329 byte [][] famQf = KeyValue.parseColumn(getBytes(column));
1330 if(famQf.length == 1) {
1331 scan.addFamily(famQf[0]);
1332 } else {
1333 scan.addColumn(famQf[0], famQf[1]);
1334 }
1335 }
1336 }
1337 scan.setTimeRange(Long.MIN_VALUE, timestamp);
1338 return addScanner(table.getScanner(scan), false);
1339 } catch (IOException e) {
1340 LOG.warn(e.getMessage(), e);
1341 throw new IOError(e.getMessage());
1342 }
1343 }
1344
1345 @Override
1346 public Map<ByteBuffer, ColumnDescriptor> getColumnDescriptors(
1347 ByteBuffer tableName) throws IOError, TException {
1348 try {
1349 TreeMap<ByteBuffer, ColumnDescriptor> columns =
1350 new TreeMap<ByteBuffer, ColumnDescriptor>();
1351
1352 HTable table = getTable(tableName);
1353 HTableDescriptor desc = table.getTableDescriptor();
1354
1355 for (HColumnDescriptor e : desc.getFamilies()) {
1356 ColumnDescriptor col = ThriftUtilities.colDescFromHbase(e);
1357 columns.put(col.name, col);
1358 }
1359 return columns;
1360 } catch (IOException e) {
1361 LOG.warn(e.getMessage(), e);
1362 throw new IOError(e.getMessage());
1363 }
1364 }
1365
1366 @Override
1367 public List<TCell> getRowOrBefore(ByteBuffer tableName, ByteBuffer row,
1368 ByteBuffer family) throws IOError {
1369 try {
1370 HTable table = getTable(getBytes(tableName));
1371 Result result = table.getRowOrBefore(getBytes(row), getBytes(family));
1372 return ThriftUtilities.cellFromHBase(result.raw());
1373 } catch (IOException e) {
1374 LOG.warn(e.getMessage(), e);
1375 throw new IOError(e.getMessage());
1376 }
1377 }
1378
1379 @Override
1380 public TRegionInfo getRegionInfo(ByteBuffer searchRow) throws IOError {
1381 try {
1382 HTable table = getTable(TableName.META_TABLE_NAME.getName());
1383 byte[] row = getBytes(searchRow);
1384 Result startRowResult = table.getRowOrBefore(
1385 row, HConstants.CATALOG_FAMILY);
1386
1387 if (startRowResult == null) {
1388 throw new IOException("Cannot find row in "+ TableName.META_TABLE_NAME+", row="
1389 + Bytes.toStringBinary(row));
1390 }
1391
1392
1393 HRegionInfo regionInfo = HRegionInfo.getHRegionInfo(startRowResult);
1394 if (regionInfo == null) {
1395 throw new IOException("HRegionInfo REGIONINFO was null or " +
1396 " empty in Meta for row="
1397 + Bytes.toStringBinary(row));
1398 }
1399 TRegionInfo region = new TRegionInfo();
1400 region.setStartKey(regionInfo.getStartKey());
1401 region.setEndKey(regionInfo.getEndKey());
1402 region.id = regionInfo.getRegionId();
1403 region.setName(regionInfo.getRegionName());
1404 region.version = regionInfo.getVersion();
1405
1406
1407 ServerName serverName = HRegionInfo.getServerName(startRowResult);
1408 if (serverName != null) {
1409 region.setServerName(Bytes.toBytes(serverName.getHostname()));
1410 region.port = serverName.getPort();
1411 }
1412 return region;
1413 } catch (IOException e) {
1414 LOG.warn(e.getMessage(), e);
1415 throw new IOError(e.getMessage());
1416 }
1417 }
1418
1419 private void initMetrics(ThriftMetrics metrics) {
1420 this.metrics = metrics;
1421 }
1422
1423 @Override
1424 public void increment(TIncrement tincrement) throws IOError, TException {
1425
1426 if (tincrement.getRow().length == 0 || tincrement.getTable().length == 0) {
1427 throw new TException("Must supply a table and a row key; can't increment");
1428 }
1429
1430 if (conf.getBoolean(COALESCE_INC_KEY, false)) {
1431 this.coalescer.queueIncrement(tincrement);
1432 return;
1433 }
1434
1435 try {
1436 HTable table = getTable(tincrement.getTable());
1437 Increment inc = ThriftUtilities.incrementFromThrift(tincrement);
1438 table.increment(inc);
1439 } catch (IOException e) {
1440 LOG.warn(e.getMessage(), e);
1441 throw new IOError(e.getMessage());
1442 }
1443 }
1444
1445 @Override
1446 public void incrementRows(List<TIncrement> tincrements) throws IOError, TException {
1447 if (conf.getBoolean(COALESCE_INC_KEY, false)) {
1448 this.coalescer.queueIncrements(tincrements);
1449 return;
1450 }
1451 for (TIncrement tinc : tincrements) {
1452 increment(tinc);
1453 }
1454 }
1455 }
1456
1457
1458
1459
1460
1461
1462 private static void addAttributes(OperationWithAttributes op,
1463 Map<ByteBuffer, ByteBuffer> attributes) {
1464 if (attributes == null || attributes.size() == 0) {
1465 return;
1466 }
1467 for (Map.Entry<ByteBuffer, ByteBuffer> entry : attributes.entrySet()) {
1468 String name = Bytes.toStringBinary(getBytes(entry.getKey()));
1469 byte[] value = getBytes(entry.getValue());
1470 op.setAttribute(name, value);
1471 }
1472 }
1473
1474 public static void registerFilters(Configuration conf) {
1475 String[] filters = conf.getStrings("hbase.thrift.filters");
1476 if(filters != null) {
1477 for(String filterClass: filters) {
1478 String[] filterPart = filterClass.split(":");
1479 if(filterPart.length != 2) {
1480 LOG.warn("Invalid filter specification " + filterClass + " - skipping");
1481 } else {
1482 ParseFilter.registerFilter(filterPart[0], filterPart[1]);
1483 }
1484 }
1485 }
1486 }
1487 }