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