1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.client;
21
22 import java.io.DataInput;
23 import java.io.DataOutput;
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Iterator;
28 import java.util.LinkedList;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.TreeMap;
32 import java.util.concurrent.ExecutorService;
33 import java.util.concurrent.SynchronousQueue;
34 import java.util.concurrent.ThreadFactory;
35 import java.util.concurrent.ThreadPoolExecutor;
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.conf.Configuration;
42 import org.apache.hadoop.hbase.DoNotRetryIOException;
43 import org.apache.hadoop.hbase.HBaseConfiguration;
44 import org.apache.hadoop.hbase.HConstants;
45 import org.apache.hadoop.hbase.HRegionInfo;
46 import org.apache.hadoop.hbase.HRegionLocation;
47 import org.apache.hadoop.hbase.HServerAddress;
48 import org.apache.hadoop.hbase.HTableDescriptor;
49 import org.apache.hadoop.hbase.KeyValue;
50 import org.apache.hadoop.hbase.NotServingRegionException;
51 import org.apache.hadoop.hbase.UnknownScannerException;
52 import org.apache.hadoop.hbase.ZooKeeperConnectionException;
53 import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor;
54 import org.apache.hadoop.hbase.util.Bytes;
55 import org.apache.hadoop.hbase.util.Pair;
56 import org.apache.hadoop.hbase.util.Writables;
57 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
58 import org.apache.zookeeper.KeeperException;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 public class HTable implements HTableInterface {
89 private static final Log LOG = LogFactory.getLog(HTable.class);
90 private final HConnection connection;
91 private final byte [] tableName;
92 protected final int scannerTimeout;
93 private volatile Configuration configuration;
94 private final ArrayList<Put> writeBuffer = new ArrayList<Put>();
95 private long writeBufferSize;
96 private boolean autoFlush;
97 private long currentWriteBufferSize;
98 protected int scannerCaching;
99 private int maxKeyValueSize;
100 private ExecutorService pool;
101 private long maxScannerResultSize;
102
103
104
105
106
107
108
109
110
111
112
113 public HTable(final String tableName)
114 throws IOException {
115 this(HBaseConfiguration.create(), Bytes.toBytes(tableName));
116 }
117
118
119
120
121
122
123
124
125
126
127
128
129 public HTable(final byte [] tableName)
130 throws IOException {
131 this(HBaseConfiguration.create(), tableName);
132 }
133
134
135
136
137
138
139
140
141
142
143
144 public HTable(Configuration conf, final String tableName)
145 throws IOException {
146 this(conf, Bytes.toBytes(tableName));
147 }
148
149
150
151
152
153
154
155
156
157
158
159
160 public HTable(Configuration conf, final byte [] tableName)
161 throws IOException {
162 this.tableName = tableName;
163 if (conf == null) {
164 this.scannerTimeout = 0;
165 this.connection = null;
166 return;
167 }
168 this.connection = HConnectionManager.getConnection(conf);
169 this.scannerTimeout =
170 (int) conf.getLong(HConstants.HBASE_REGIONSERVER_LEASE_PERIOD_KEY, HConstants.DEFAULT_HBASE_REGIONSERVER_LEASE_PERIOD);
171 this.configuration = conf;
172 this.connection.locateRegion(tableName, HConstants.EMPTY_START_ROW);
173 this.writeBufferSize = conf.getLong("hbase.client.write.buffer", 2097152);
174 this.autoFlush = true;
175 this.currentWriteBufferSize = 0;
176 this.scannerCaching = conf.getInt("hbase.client.scanner.caching", 1);
177
178 this.maxScannerResultSize = conf.getLong(
179 HConstants.HBASE_CLIENT_SCANNER_MAX_RESULT_SIZE_KEY,
180 HConstants.DEFAULT_HBASE_CLIENT_SCANNER_MAX_RESULT_SIZE);
181 this.maxKeyValueSize = conf.getInt("hbase.client.keyvalue.maxsize", -1);
182
183 int maxThreads = conf.getInt("hbase.htable.threads.max", Integer.MAX_VALUE);
184 if (maxThreads == 0) {
185 maxThreads = 1;
186 }
187
188
189
190
191
192 this.pool = new ThreadPoolExecutor(1, maxThreads,
193 60, TimeUnit.SECONDS,
194 new SynchronousQueue<Runnable>(),
195 new DaemonThreadFactory());
196 ((ThreadPoolExecutor)this.pool).allowCoreThreadTimeOut(true);
197 }
198
199
200
201
202
203 public int getCurrentNrHRS() throws IOException {
204 try {
205
206
207 return ZKUtil.getNumberOfChildren(this.connection.getZooKeeperWatcher(),
208 this.connection.getZooKeeperWatcher().rsZNode);
209 } catch (KeeperException ke) {
210 throw new IOException("Unexpected ZooKeeper exception", ke);
211 }
212 }
213
214 public Configuration getConfiguration() {
215 return configuration;
216 }
217
218
219
220
221
222
223
224
225 public static boolean isTableEnabled(String tableName) throws IOException {
226 return isTableEnabled(Bytes.toBytes(tableName));
227 }
228
229
230
231
232
233
234
235
236 public static boolean isTableEnabled(byte[] tableName) throws IOException {
237 return isTableEnabled(HBaseConfiguration.create(), tableName);
238 }
239
240
241
242
243
244
245
246
247
248 public static boolean isTableEnabled(Configuration conf, String tableName)
249 throws IOException {
250 return isTableEnabled(conf, Bytes.toBytes(tableName));
251 }
252
253
254
255
256
257
258
259
260 public static boolean isTableEnabled(Configuration conf, byte[] tableName)
261 throws IOException {
262 return HConnectionManager.getConnection(conf).isTableEnabled(tableName);
263 }
264
265
266
267
268
269
270
271 public HRegionLocation getRegionLocation(final String row)
272 throws IOException {
273 return connection.getRegionLocation(tableName, Bytes.toBytes(row), false);
274 }
275
276
277
278
279
280
281
282 public HRegionLocation getRegionLocation(final byte [] row)
283 throws IOException {
284 return connection.getRegionLocation(tableName, row, false);
285 }
286
287 @Override
288 public byte [] getTableName() {
289 return this.tableName;
290 }
291
292
293
294
295
296
297
298 public HConnection getConnection() {
299 return this.connection;
300 }
301
302
303
304
305
306
307 public int getScannerCaching() {
308 return scannerCaching;
309 }
310
311
312
313
314
315
316
317
318
319
320
321 public void setScannerCaching(int scannerCaching) {
322 this.scannerCaching = scannerCaching;
323 }
324
325 @Override
326 public HTableDescriptor getTableDescriptor() throws IOException {
327 return new UnmodifyableHTableDescriptor(
328 this.connection.getHTableDescriptor(this.tableName));
329 }
330
331
332
333
334
335
336
337
338 public byte [][] getStartKeys() throws IOException {
339 return getStartEndKeys().getFirst();
340 }
341
342
343
344
345
346
347
348
349 public byte[][] getEndKeys() throws IOException {
350 return getStartEndKeys().getSecond();
351 }
352
353
354
355
356
357
358
359
360
361 @SuppressWarnings("unchecked")
362 public Pair<byte[][],byte[][]> getStartEndKeys() throws IOException {
363 final List<byte[]> startKeyList = new ArrayList<byte[]>();
364 final List<byte[]> endKeyList = new ArrayList<byte[]>();
365 MetaScannerVisitor visitor = new MetaScannerVisitor() {
366 public boolean processRow(Result rowResult) throws IOException {
367 byte [] bytes = rowResult.getValue(HConstants.CATALOG_FAMILY,
368 HConstants.REGIONINFO_QUALIFIER);
369 if (bytes == null) {
370 LOG.warn("Null " + HConstants.REGIONINFO_QUALIFIER + " cell in " +
371 rowResult);
372 return true;
373 }
374 HRegionInfo info = Writables.getHRegionInfo(bytes);
375 if (Bytes.equals(info.getTableDesc().getName(), getTableName())) {
376 if (!(info.isOffline() || info.isSplit())) {
377 startKeyList.add(info.getStartKey());
378 endKeyList.add(info.getEndKey());
379 }
380 }
381 return true;
382 }
383 };
384 MetaScanner.metaScan(configuration, visitor, this.tableName);
385 return new Pair(startKeyList.toArray(new byte[startKeyList.size()][]),
386 endKeyList.toArray(new byte[endKeyList.size()][]));
387 }
388
389
390
391
392
393
394
395
396 public Map<HRegionInfo, HServerAddress> getRegionsInfo() throws IOException {
397 final Map<HRegionInfo, HServerAddress> regionMap =
398 new TreeMap<HRegionInfo, HServerAddress>();
399
400 MetaScannerVisitor visitor = new MetaScannerVisitor() {
401 public boolean processRow(Result rowResult) throws IOException {
402 HRegionInfo info = Writables.getHRegionInfo(
403 rowResult.getValue(HConstants.CATALOG_FAMILY,
404 HConstants.REGIONINFO_QUALIFIER));
405
406 if (!(Bytes.equals(info.getTableDesc().getName(), getTableName()))) {
407 return false;
408 }
409
410 HServerAddress server = new HServerAddress();
411 byte [] value = rowResult.getValue(HConstants.CATALOG_FAMILY,
412 HConstants.SERVER_QUALIFIER);
413 if (value != null && value.length > 0) {
414 String address = Bytes.toString(value);
415 server = new HServerAddress(address);
416 }
417
418 if (!(info.isOffline() || info.isSplit())) {
419 regionMap.put(new UnmodifyableHRegionInfo(info), server);
420 }
421 return true;
422 }
423
424 };
425 MetaScanner.metaScan(configuration, visitor, tableName);
426 return regionMap;
427 }
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451 public void prewarmRegionCache(Map<HRegionInfo, HServerAddress> regionMap) {
452 this.connection.prewarmRegionCache(this.getTableName(), regionMap);
453 }
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475 public void serializeRegionInfo(DataOutput out) throws IOException {
476 Map<HRegionInfo, HServerAddress> allRegions = this.getRegionsInfo();
477
478 out.writeInt(allRegions.size());
479 for (Map.Entry<HRegionInfo, HServerAddress> es : allRegions.entrySet()) {
480 es.getKey().write(out);
481 es.getValue().write(out);
482 }
483 }
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501 public Map<HRegionInfo, HServerAddress> deserializeRegionInfo(DataInput in)
502 throws IOException {
503 final Map<HRegionInfo, HServerAddress> allRegions =
504 new TreeMap<HRegionInfo, HServerAddress>();
505
506
507 int regionsCount = in.readInt();
508 for (int i = 0; i < regionsCount; ++i) {
509 HRegionInfo hri = new HRegionInfo();
510 hri.readFields(in);
511 HServerAddress hsa = new HServerAddress();
512 hsa.readFields(in);
513 allRegions.put(hri, hsa);
514 }
515 return allRegions;
516 }
517
518 @Override
519 public Result getRowOrBefore(final byte[] row, final byte[] family)
520 throws IOException {
521 return connection.getRegionServerWithRetries(
522 new ServerCallable<Result>(connection, tableName, row) {
523 public Result call() throws IOException {
524 return server.getClosestRowBefore(location.getRegionInfo().getRegionName(),
525 row, family);
526 }
527 });
528 }
529
530 @Override
531 public ResultScanner getScanner(final Scan scan) throws IOException {
532 ClientScanner s = new ClientScanner(scan);
533 s.initialize();
534 return s;
535 }
536
537 @Override
538 public ResultScanner getScanner(byte [] family) throws IOException {
539 Scan scan = new Scan();
540 scan.addFamily(family);
541 return getScanner(scan);
542 }
543
544 @Override
545 public ResultScanner getScanner(byte [] family, byte [] qualifier)
546 throws IOException {
547 Scan scan = new Scan();
548 scan.addColumn(family, qualifier);
549 return getScanner(scan);
550 }
551
552 public Result get(final Get get) throws IOException {
553 return connection.getRegionServerWithRetries(
554 new ServerCallable<Result>(connection, tableName, get.getRow()) {
555 public Result call() throws IOException {
556 return server.get(location.getRegionInfo().getRegionName(), get);
557 }
558 }
559 );
560 }
561
562 public Result[] get(List<Get> gets) throws IOException {
563 try {
564 Object [] r1 = batch((List)gets);
565
566
567 Result [] results = new Result[r1.length];
568 int i=0;
569 for (Object o : r1) {
570
571 results[i++] = (Result) o;
572 }
573
574 return results;
575 } catch (InterruptedException e) {
576 throw new IOException(e);
577 }
578 }
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593 @Override
594 public synchronized void batch(final List<Row> actions, final Object[] results)
595 throws InterruptedException, IOException {
596 connection.processBatch(actions, tableName, pool, results);
597 }
598
599
600
601
602
603
604
605
606
607 @Override
608 public synchronized Object[] batch(final List<Row> actions) throws InterruptedException, IOException {
609 Object[] results = new Object[actions.size()];
610 connection.processBatch(actions, tableName, pool, results);
611 return results;
612 }
613
614
615
616
617
618
619
620
621 @Override
622 public void delete(final Delete delete)
623 throws IOException {
624 connection.getRegionServerWithRetries(
625 new ServerCallable<Boolean>(connection, tableName, delete.getRow()) {
626 public Boolean call() throws IOException {
627 server.delete(location.getRegionInfo().getRegionName(), delete);
628 return null;
629 }
630 }
631 );
632 }
633
634
635
636
637
638
639
640
641
642
643
644 @Override
645 public void delete(final List<Delete> deletes)
646 throws IOException {
647 Object[] results = new Object[deletes.size()];
648 try {
649 connection.processBatch((List) deletes, tableName, pool, results);
650 } catch (InterruptedException e) {
651 throw new IOException(e);
652 } finally {
653
654
655
656 for (int i = results.length - 1; i>=0; i--) {
657
658 if (results[i] instanceof Result) {
659 deletes.remove(i);
660 }
661 }
662 }
663 }
664
665 @Override
666 public void put(final Put put) throws IOException {
667 doPut(Arrays.asList(put));
668 }
669
670 @Override
671 public void put(final List<Put> puts) throws IOException {
672 doPut(puts);
673 }
674
675 private void doPut(final List<Put> puts) throws IOException {
676 for (Put put : puts) {
677 validatePut(put);
678 writeBuffer.add(put);
679 currentWriteBufferSize += put.heapSize();
680 }
681 if (autoFlush || currentWriteBufferSize > writeBufferSize) {
682 flushCommits();
683 }
684 }
685
686 @Override
687 public Result increment(final Increment increment) throws IOException {
688 if (!increment.hasFamilies()) {
689 throw new IOException(
690 "Invalid arguments to increment, no columns specified");
691 }
692 return connection.getRegionServerWithRetries(
693 new ServerCallable<Result>(connection, tableName, increment.getRow()) {
694 public Result call() throws IOException {
695 return server.increment(
696 location.getRegionInfo().getRegionName(), increment);
697 }
698 }
699 );
700 }
701
702 @Override
703 public long incrementColumnValue(final byte [] row, final byte [] family,
704 final byte [] qualifier, final long amount)
705 throws IOException {
706 return incrementColumnValue(row, family, qualifier, amount, true);
707 }
708
709 @Override
710 public long incrementColumnValue(final byte [] row, final byte [] family,
711 final byte [] qualifier, final long amount, final boolean writeToWAL)
712 throws IOException {
713 NullPointerException npe = null;
714 if (row == null) {
715 npe = new NullPointerException("row is null");
716 } else if (family == null) {
717 npe = new NullPointerException("column is null");
718 }
719 if (npe != null) {
720 throw new IOException(
721 "Invalid arguments to incrementColumnValue", npe);
722 }
723 return connection.getRegionServerWithRetries(
724 new ServerCallable<Long>(connection, tableName, row) {
725 public Long call() throws IOException {
726 return server.incrementColumnValue(
727 location.getRegionInfo().getRegionName(), row, family,
728 qualifier, amount, writeToWAL);
729 }
730 }
731 );
732 }
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747 @Override
748 public boolean checkAndPut(final byte [] row,
749 final byte [] family, final byte [] qualifier, final byte [] value,
750 final Put put)
751 throws IOException {
752 return connection.getRegionServerWithRetries(
753 new ServerCallable<Boolean>(connection, tableName, row) {
754 public Boolean call() throws IOException {
755 return server.checkAndPut(location.getRegionInfo().getRegionName(),
756 row, family, qualifier, value, put) ? Boolean.TRUE : Boolean.FALSE;
757 }
758 }
759 );
760 }
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775 @Override
776 public boolean checkAndDelete(final byte [] row,
777 final byte [] family, final byte [] qualifier, final byte [] value,
778 final Delete delete)
779 throws IOException {
780 return connection.getRegionServerWithRetries(
781 new ServerCallable<Boolean>(connection, tableName, row) {
782 public Boolean call() throws IOException {
783 return server.checkAndDelete(
784 location.getRegionInfo().getRegionName(),
785 row, family, qualifier, value, delete)
786 ? Boolean.TRUE : Boolean.FALSE;
787 }
788 }
789 );
790 }
791
792
793
794
795
796
797
798
799
800
801
802
803 @Override
804 public boolean exists(final Get get) throws IOException {
805 return connection.getRegionServerWithRetries(
806 new ServerCallable<Boolean>(connection, tableName, get.getRow()) {
807 public Boolean call() throws IOException {
808 return server.
809 exists(location.getRegionInfo().getRegionName(), get);
810 }
811 }
812 );
813 }
814
815
816
817
818
819
820
821
822
823 @Override
824 public void flushCommits() throws IOException {
825 try {
826 connection.processBatchOfPuts(writeBuffer, tableName, pool);
827 } finally {
828
829 currentWriteBufferSize = 0;
830 for (Put aPut : writeBuffer) {
831 currentWriteBufferSize += aPut.heapSize();
832 }
833 }
834 }
835
836 @Override
837 public void close() throws IOException {
838 flushCommits();
839 this.pool.shutdown();
840 }
841
842
843 private void validatePut(final Put put) throws IllegalArgumentException{
844 if (put.isEmpty()) {
845 throw new IllegalArgumentException("No columns to insert");
846 }
847 if (maxKeyValueSize > 0) {
848 for (List<KeyValue> list : put.getFamilyMap().values()) {
849 for (KeyValue kv : list) {
850 if (kv.getLength() > maxKeyValueSize) {
851 throw new IllegalArgumentException("KeyValue size too large");
852 }
853 }
854 }
855 }
856 }
857
858 @Override
859 public RowLock lockRow(final byte [] row)
860 throws IOException {
861 return connection.getRegionServerWithRetries(
862 new ServerCallable<RowLock>(connection, tableName, row) {
863 public RowLock call() throws IOException {
864 long lockId =
865 server.lockRow(location.getRegionInfo().getRegionName(), row);
866 return new RowLock(row,lockId);
867 }
868 }
869 );
870 }
871
872 @Override
873 public void unlockRow(final RowLock rl)
874 throws IOException {
875 connection.getRegionServerWithRetries(
876 new ServerCallable<Boolean>(connection, tableName, rl.getRow()) {
877 public Boolean call() throws IOException {
878 server.unlockRow(location.getRegionInfo().getRegionName(),
879 rl.getLockId());
880 return null;
881 }
882 }
883 );
884 }
885
886
887
888
889
890 public void clearRegionCache() {
891 this.connection.clearRegionCache();
892 }
893
894 @Override
895 public boolean isAutoFlush() {
896 return autoFlush;
897 }
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917 public void setAutoFlush(boolean autoFlush) {
918 this.autoFlush = autoFlush;
919 }
920
921
922
923
924
925
926
927
928 public long getWriteBufferSize() {
929 return writeBufferSize;
930 }
931
932
933
934
935
936
937
938
939
940 public void setWriteBufferSize(long writeBufferSize) throws IOException {
941 this.writeBufferSize = writeBufferSize;
942 if(currentWriteBufferSize > writeBufferSize) {
943 flushCommits();
944 }
945 }
946
947
948
949
950
951 public ArrayList<Put> getWriteBuffer() {
952 return writeBuffer;
953 }
954
955
956
957
958
959
960 protected class ClientScanner implements ResultScanner {
961 private final Log CLIENT_LOG = LogFactory.getLog(this.getClass());
962
963 private Scan scan;
964 private boolean closed = false;
965
966
967 private HRegionInfo currentRegion = null;
968 private ScannerCallable callable = null;
969 private final LinkedList<Result> cache = new LinkedList<Result>();
970 private final int caching;
971 private long lastNext;
972
973 private Result lastResult = null;
974
975 protected ClientScanner(final Scan scan) {
976 if (CLIENT_LOG.isDebugEnabled()) {
977 CLIENT_LOG.debug("Creating scanner over "
978 + Bytes.toString(getTableName())
979 + " starting at key '" + Bytes.toStringBinary(scan.getStartRow()) + "'");
980 }
981 this.scan = scan;
982 this.lastNext = System.currentTimeMillis();
983
984
985 if (this.scan.getCaching() > 0) {
986 this.caching = this.scan.getCaching();
987 } else {
988 this.caching = HTable.this.scannerCaching;
989 }
990
991
992
993
994
995
996
997 }
998
999 public void initialize() throws IOException {
1000 nextScanner(this.caching, false);
1001 }
1002
1003 protected Scan getScan() {
1004 return scan;
1005 }
1006
1007 protected long getTimestamp() {
1008 return lastNext;
1009 }
1010
1011
1012 private boolean checkScanStopRow(final byte [] endKey) {
1013 if (this.scan.getStopRow().length > 0) {
1014
1015 byte [] stopRow = scan.getStopRow();
1016 int cmp = Bytes.compareTo(stopRow, 0, stopRow.length,
1017 endKey, 0, endKey.length);
1018 if (cmp <= 0) {
1019
1020
1021 return true;
1022 }
1023 }
1024 return false;
1025 }
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036 private boolean nextScanner(int nbRows, final boolean done)
1037 throws IOException {
1038
1039 if (this.callable != null) {
1040 this.callable.setClose();
1041 getConnection().getRegionServerWithRetries(callable);
1042 this.callable = null;
1043 }
1044
1045
1046 byte [] localStartKey;
1047
1048
1049 if (this.currentRegion != null) {
1050 byte [] endKey = this.currentRegion.getEndKey();
1051 if (endKey == null ||
1052 Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY) ||
1053 checkScanStopRow(endKey) ||
1054 done) {
1055 close();
1056 if (CLIENT_LOG.isDebugEnabled()) {
1057 CLIENT_LOG.debug("Finished with scanning at " + this.currentRegion);
1058 }
1059 return false;
1060 }
1061 localStartKey = endKey;
1062 if (CLIENT_LOG.isDebugEnabled()) {
1063 CLIENT_LOG.debug("Finished with region " + this.currentRegion);
1064 }
1065 } else {
1066 localStartKey = this.scan.getStartRow();
1067 }
1068
1069 if (CLIENT_LOG.isDebugEnabled()) {
1070 CLIENT_LOG.debug("Advancing internal scanner to startKey at '" +
1071 Bytes.toStringBinary(localStartKey) + "'");
1072 }
1073 try {
1074 callable = getScannerCallable(localStartKey, nbRows);
1075
1076
1077 getConnection().getRegionServerWithRetries(callable);
1078 this.currentRegion = callable.getHRegionInfo();
1079 } catch (IOException e) {
1080 close();
1081 throw e;
1082 }
1083 return true;
1084 }
1085
1086 protected ScannerCallable getScannerCallable(byte [] localStartKey,
1087 int nbRows) {
1088 scan.setStartRow(localStartKey);
1089 ScannerCallable s = new ScannerCallable(getConnection(),
1090 getTableName(), scan);
1091 s.setCaching(nbRows);
1092 return s;
1093 }
1094
1095 public Result next() throws IOException {
1096
1097
1098 if (cache.size() == 0 && this.closed) {
1099 return null;
1100 }
1101 if (cache.size() == 0) {
1102 Result [] values = null;
1103 long remainingResultSize = maxScannerResultSize;
1104 int countdown = this.caching;
1105
1106
1107 callable.setCaching(this.caching);
1108
1109
1110 boolean skipFirst = false;
1111 do {
1112 try {
1113 if (skipFirst) {
1114
1115
1116 callable.setCaching(1);
1117 values = getConnection().getRegionServerWithRetries(callable);
1118 callable.setCaching(this.caching);
1119 skipFirst = false;
1120 }
1121
1122
1123
1124 values = getConnection().getRegionServerWithRetries(callable);
1125 } catch (DoNotRetryIOException e) {
1126 if (e instanceof UnknownScannerException) {
1127 long timeout = lastNext + scannerTimeout;
1128
1129
1130
1131 if (timeout < System.currentTimeMillis()) {
1132 long elapsed = System.currentTimeMillis() - lastNext;
1133 ScannerTimeoutException ex = new ScannerTimeoutException(
1134 elapsed + "ms passed since the last invocation, " +
1135 "timeout is currently set to " + scannerTimeout);
1136 ex.initCause(e);
1137 throw ex;
1138 }
1139 } else {
1140 Throwable cause = e.getCause();
1141 if (cause == null || !(cause instanceof NotServingRegionException)) {
1142 throw e;
1143 }
1144 }
1145
1146
1147 if (this.lastResult != null) {
1148 this.scan.setStartRow(this.lastResult.getRow());
1149
1150
1151 skipFirst = true;
1152 }
1153
1154 this.currentRegion = null;
1155 continue;
1156 }
1157 lastNext = System.currentTimeMillis();
1158 if (values != null && values.length > 0) {
1159 for (Result rs : values) {
1160 cache.add(rs);
1161 for (KeyValue kv : rs.raw()) {
1162 remainingResultSize -= kv.heapSize();
1163 }
1164 countdown--;
1165 this.lastResult = rs;
1166 }
1167 }
1168
1169 } while (remainingResultSize > 0 && countdown > 0 && nextScanner(countdown, values == null));
1170 }
1171
1172 if (cache.size() > 0) {
1173 return cache.poll();
1174 }
1175 return null;
1176 }
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187 public Result [] next(int nbRows) throws IOException {
1188
1189 ArrayList<Result> resultSets = new ArrayList<Result>(nbRows);
1190 for(int i = 0; i < nbRows; i++) {
1191 Result next = next();
1192 if (next != null) {
1193 resultSets.add(next);
1194 } else {
1195 break;
1196 }
1197 }
1198 return resultSets.toArray(new Result[resultSets.size()]);
1199 }
1200
1201 public void close() {
1202 if (callable != null) {
1203 callable.setClose();
1204 try {
1205 getConnection().getRegionServerWithRetries(callable);
1206 } catch (IOException e) {
1207
1208
1209
1210
1211 }
1212 callable = null;
1213 }
1214 closed = true;
1215 }
1216
1217 public Iterator<Result> iterator() {
1218 return new Iterator<Result>() {
1219
1220 Result next = null;
1221
1222
1223
1224
1225
1226 public boolean hasNext() {
1227 if (next == null) {
1228 try {
1229 next = ClientScanner.this.next();
1230 return next != null;
1231 } catch (IOException e) {
1232 throw new RuntimeException(e);
1233 }
1234 }
1235 return true;
1236 }
1237
1238
1239
1240 public Result next() {
1241
1242
1243 if (!hasNext()) {
1244 return null;
1245 }
1246
1247
1248
1249
1250 Result temp = next;
1251 next = null;
1252 return temp;
1253 }
1254
1255 public void remove() {
1256 throw new UnsupportedOperationException();
1257 }
1258 };
1259 }
1260 }
1261
1262
1263
1264
1265
1266 ExecutorService getPool() {
1267 return this.pool;
1268 }
1269
1270 static class DaemonThreadFactory implements ThreadFactory {
1271 static final AtomicInteger poolNumber = new AtomicInteger(1);
1272 final ThreadGroup group;
1273 final AtomicInteger threadNumber = new AtomicInteger(1);
1274 final String namePrefix;
1275
1276 DaemonThreadFactory() {
1277 SecurityManager s = System.getSecurityManager();
1278 group = (s != null)? s.getThreadGroup() :
1279 Thread.currentThread().getThreadGroup();
1280 namePrefix = "pool-" +
1281 poolNumber.getAndIncrement() +
1282 "-thread-";
1283 }
1284
1285 public Thread newThread(Runnable r) {
1286 Thread t = new Thread(group, r,
1287 namePrefix + threadNumber.getAndIncrement(),
1288 0);
1289 if (!t.isDaemon()) {
1290 t.setDaemon(true);
1291 }
1292 if (t.getPriority() != Thread.NORM_PRIORITY) {
1293 t.setPriority(Thread.NORM_PRIORITY);
1294 }
1295 return t;
1296 }
1297 }
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308 public static void setRegionCachePrefetch(final byte[] tableName,
1309 boolean enable) throws ZooKeeperConnectionException {
1310 HConnectionManager.getConnection(HBaseConfiguration.create()).
1311 setRegionCachePrefetch(tableName, enable);
1312 }
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324 public static void setRegionCachePrefetch(final Configuration conf,
1325 final byte[] tableName, boolean enable) throws ZooKeeperConnectionException {
1326 HConnectionManager.getConnection(conf).setRegionCachePrefetch(
1327 tableName, enable);
1328 }
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338 public static boolean getRegionCachePrefetch(final Configuration conf,
1339 final byte[] tableName) throws ZooKeeperConnectionException {
1340 return HConnectionManager.getConnection(conf).getRegionCachePrefetch(
1341 tableName);
1342 }
1343
1344
1345
1346
1347
1348
1349
1350
1351 public static boolean getRegionCachePrefetch(final byte[] tableName) throws ZooKeeperConnectionException {
1352 return HConnectionManager.getConnection(HBaseConfiguration.create()).
1353 getRegionCachePrefetch(tableName);
1354 }
1355 }