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