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.IOException;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.NavigableSet;
29 import java.util.TreeMap;
30 import java.util.TreeSet;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.hadoop.hbase.classification.InterfaceAudience;
35 import org.apache.hadoop.hbase.classification.InterfaceStability;
36 import org.apache.hadoop.hbase.HConstants;
37 import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
38 import org.apache.hadoop.hbase.filter.Filter;
39 import org.apache.hadoop.hbase.filter.IncompatibleFilterException;
40 import org.apache.hadoop.hbase.io.TimeRange;
41 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
42 import org.apache.hadoop.hbase.security.access.Permission;
43 import org.apache.hadoop.hbase.security.visibility.Authorizations;
44 import org.apache.hadoop.hbase.util.Bytes;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
89 @InterfaceAudience.Public
90 @InterfaceStability.Stable
91 public class Scan extends Query {
92 private static final Log LOG = LogFactory.getLog(Scan.class);
93
94 private static final String RAW_ATTR = "_raw_";
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 @Deprecated
114 public static final String HINT_LOOKAHEAD = "_look_ahead_";
115
116 private byte [] startRow = HConstants.EMPTY_START_ROW;
117 private byte [] stopRow = HConstants.EMPTY_END_ROW;
118 private int maxVersions = 1;
119 private int batch = -1;
120
121 private int storeLimit = -1;
122 private int storeOffset = 0;
123 private boolean getScan;
124
125
126
127
128
129 @Deprecated
130 static public final String SCAN_ATTRIBUTES_METRICS_ENABLE = "scan.attributes.metrics.enable";
131
132
133
134
135
136 @Deprecated
137 static public final String SCAN_ATTRIBUTES_METRICS_DATA = "scan.attributes.metrics.data";
138
139
140
141
142 static public final String SCAN_ATTRIBUTES_TABLE_NAME = "scan.attributes.table.name";
143
144
145
146
147 private int caching = -1;
148 private long maxResultSize = -1;
149 private boolean cacheBlocks = true;
150 private boolean reversed = false;
151 private TimeRange tr = new TimeRange();
152 private Map<byte [], NavigableSet<byte []>> familyMap =
153 new TreeMap<byte [], NavigableSet<byte []>>(Bytes.BYTES_COMPARATOR);
154 private Boolean loadColumnFamiliesOnDemand = null;
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 private boolean small = false;
175
176
177
178
179 public Scan() {}
180
181 public Scan(byte [] startRow, Filter filter) {
182 this(startRow);
183 this.filter = filter;
184 }
185
186
187
188
189
190
191
192
193 public Scan(byte [] startRow) {
194 this.startRow = startRow;
195 }
196
197
198
199
200
201
202 public Scan(byte [] startRow, byte [] stopRow) {
203 this.startRow = startRow;
204 this.stopRow = stopRow;
205
206 this.getScan = isStartRowAndEqualsStopRow();
207 }
208
209
210
211
212
213
214
215 public Scan(Scan scan) throws IOException {
216 startRow = scan.getStartRow();
217 stopRow = scan.getStopRow();
218 maxVersions = scan.getMaxVersions();
219 batch = scan.getBatch();
220 storeLimit = scan.getMaxResultsPerColumnFamily();
221 storeOffset = scan.getRowOffsetPerColumnFamily();
222 caching = scan.getCaching();
223 maxResultSize = scan.getMaxResultSize();
224 cacheBlocks = scan.getCacheBlocks();
225 getScan = scan.isGetScan();
226 filter = scan.getFilter();
227 loadColumnFamiliesOnDemand = scan.getLoadColumnFamiliesOnDemandValue();
228 consistency = scan.getConsistency();
229 reversed = scan.isReversed();
230 small = scan.isSmall();
231 TimeRange ctr = scan.getTimeRange();
232 tr = new TimeRange(ctr.getMin(), ctr.getMax());
233 Map<byte[], NavigableSet<byte[]>> fams = scan.getFamilyMap();
234 for (Map.Entry<byte[],NavigableSet<byte[]>> entry : fams.entrySet()) {
235 byte [] fam = entry.getKey();
236 NavigableSet<byte[]> cols = entry.getValue();
237 if (cols != null && cols.size() > 0) {
238 for (byte[] col : cols) {
239 addColumn(fam, col);
240 }
241 } else {
242 addFamily(fam);
243 }
244 }
245 for (Map.Entry<String, byte[]> attr : scan.getAttributesMap().entrySet()) {
246 setAttribute(attr.getKey(), attr.getValue());
247 }
248 }
249
250
251
252
253
254 public Scan(Get get) {
255 this.startRow = get.getRow();
256 this.stopRow = get.getRow();
257 this.filter = get.getFilter();
258 this.cacheBlocks = get.getCacheBlocks();
259 this.maxVersions = get.getMaxVersions();
260 this.storeLimit = get.getMaxResultsPerColumnFamily();
261 this.storeOffset = get.getRowOffsetPerColumnFamily();
262 this.tr = get.getTimeRange();
263 this.familyMap = get.getFamilyMap();
264 this.getScan = true;
265 this.consistency = get.getConsistency();
266 for (Map.Entry<String, byte[]> attr : get.getAttributesMap().entrySet()) {
267 setAttribute(attr.getKey(), attr.getValue());
268 }
269 }
270
271 public boolean isGetScan() {
272 return this.getScan || isStartRowAndEqualsStopRow();
273 }
274
275 private boolean isStartRowAndEqualsStopRow() {
276 return this.startRow != null && this.startRow.length > 0 &&
277 Bytes.equals(this.startRow, this.stopRow);
278 }
279
280
281
282
283
284
285
286 public Scan addFamily(byte [] family) {
287 familyMap.remove(family);
288 familyMap.put(family, null);
289 return this;
290 }
291
292
293
294
295
296
297
298
299
300 public Scan addColumn(byte [] family, byte [] qualifier) {
301 NavigableSet<byte []> set = familyMap.get(family);
302 if(set == null) {
303 set = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR);
304 }
305 if (qualifier == null) {
306 qualifier = HConstants.EMPTY_BYTE_ARRAY;
307 }
308 set.add(qualifier);
309 familyMap.put(family, set);
310 return this;
311 }
312
313
314
315
316
317
318
319
320
321
322
323
324
325 public Scan setTimeRange(long minStamp, long maxStamp)
326 throws IOException {
327 tr = new TimeRange(minStamp, maxStamp);
328 return this;
329 }
330
331
332
333
334
335
336
337
338
339
340
341 public Scan setTimeStamp(long timestamp)
342 throws IOException {
343 try {
344 tr = new TimeRange(timestamp, timestamp+1);
345 } catch(IOException e) {
346
347 LOG.error("TimeRange failed, likely caused by integer overflow. ", e);
348 throw e;
349 }
350 return this;
351 }
352
353
354
355
356
357
358
359 public Scan setStartRow(byte [] startRow) {
360 this.startRow = startRow;
361 return this;
362 }
363
364
365
366
367
368
369
370
371
372
373 public Scan setStopRow(byte [] stopRow) {
374 this.stopRow = stopRow;
375 return this;
376 }
377
378
379
380
381
382
383
384
385
386
387
388
389 public Scan setRowPrefixFilter(byte[] rowPrefix) {
390 if (rowPrefix == null) {
391 setStartRow(HConstants.EMPTY_START_ROW);
392 setStopRow(HConstants.EMPTY_END_ROW);
393 } else {
394 this.setStartRow(rowPrefix);
395 this.setStopRow(calculateTheClosestNextRowKeyForPrefix(rowPrefix));
396 }
397 return this;
398 }
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417 private byte[] calculateTheClosestNextRowKeyForPrefix(byte[] rowKeyPrefix) {
418
419
420 int offset = rowKeyPrefix.length;
421 while (offset > 0) {
422 if (rowKeyPrefix[offset - 1] != (byte) 0xFF) {
423 break;
424 }
425 offset--;
426 }
427
428 if (offset == 0) {
429
430
431
432 return HConstants.EMPTY_END_ROW;
433 }
434
435
436 byte[] newStopRow = Arrays.copyOfRange(rowKeyPrefix, 0, offset);
437
438 newStopRow[newStopRow.length - 1]++;
439 return newStopRow;
440 }
441
442
443
444
445
446 public Scan setMaxVersions() {
447 this.maxVersions = Integer.MAX_VALUE;
448 return this;
449 }
450
451
452
453
454
455
456 public Scan setMaxVersions(int maxVersions) {
457 this.maxVersions = maxVersions;
458 return this;
459 }
460
461
462
463
464
465 public Scan setBatch(int batch) {
466 if (this.hasFilter() && this.filter.hasFilterRow()) {
467 throw new IncompatibleFilterException(
468 "Cannot set batch on a scan using a filter" +
469 " that returns true for filter.hasFilterRow");
470 }
471 this.batch = batch;
472 return this;
473 }
474
475
476
477
478
479 public Scan setMaxResultsPerColumnFamily(int limit) {
480 this.storeLimit = limit;
481 return this;
482 }
483
484
485
486
487
488 public Scan setRowOffsetPerColumnFamily(int offset) {
489 this.storeOffset = offset;
490 return this;
491 }
492
493
494
495
496
497
498
499
500 public Scan setCaching(int caching) {
501 this.caching = caching;
502 return this;
503 }
504
505
506
507
508 public long getMaxResultSize() {
509 return maxResultSize;
510 }
511
512
513
514
515
516
517
518
519 public Scan setMaxResultSize(long maxResultSize) {
520 this.maxResultSize = maxResultSize;
521 return this;
522 }
523
524 @Override
525 public Scan setFilter(Filter filter) {
526 super.setFilter(filter);
527 return this;
528 }
529
530
531
532
533
534
535 public Scan setFamilyMap(Map<byte [], NavigableSet<byte []>> familyMap) {
536 this.familyMap = familyMap;
537 return this;
538 }
539
540
541
542
543
544 public Map<byte [], NavigableSet<byte []>> getFamilyMap() {
545 return this.familyMap;
546 }
547
548
549
550
551 public int numFamilies() {
552 if(hasFamilies()) {
553 return this.familyMap.size();
554 }
555 return 0;
556 }
557
558
559
560
561 public boolean hasFamilies() {
562 return !this.familyMap.isEmpty();
563 }
564
565
566
567
568 public byte[][] getFamilies() {
569 if(hasFamilies()) {
570 return this.familyMap.keySet().toArray(new byte[0][0]);
571 }
572 return null;
573 }
574
575
576
577
578 public byte [] getStartRow() {
579 return this.startRow;
580 }
581
582
583
584
585 public byte [] getStopRow() {
586 return this.stopRow;
587 }
588
589
590
591
592 public int getMaxVersions() {
593 return this.maxVersions;
594 }
595
596
597
598
599 public int getBatch() {
600 return this.batch;
601 }
602
603
604
605
606 public int getMaxResultsPerColumnFamily() {
607 return this.storeLimit;
608 }
609
610
611
612
613
614
615 public int getRowOffsetPerColumnFamily() {
616 return this.storeOffset;
617 }
618
619
620
621
622 public int getCaching() {
623 return this.caching;
624 }
625
626
627
628
629 public TimeRange getTimeRange() {
630 return this.tr;
631 }
632
633
634
635
636 @Override
637 public Filter getFilter() {
638 return filter;
639 }
640
641
642
643
644 public boolean hasFilter() {
645 return filter != null;
646 }
647
648
649
650
651
652
653
654
655
656
657
658 public Scan setCacheBlocks(boolean cacheBlocks) {
659 this.cacheBlocks = cacheBlocks;
660 return this;
661 }
662
663
664
665
666
667
668 public boolean getCacheBlocks() {
669 return cacheBlocks;
670 }
671
672
673
674
675
676
677
678
679
680 public Scan setReversed(boolean reversed) {
681 this.reversed = reversed;
682 return this;
683 }
684
685
686
687
688
689 public boolean isReversed() {
690 return reversed;
691 }
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709 public Scan setLoadColumnFamiliesOnDemand(boolean value) {
710 this.loadColumnFamiliesOnDemand = value;
711 return this;
712 }
713
714
715
716
717 public Boolean getLoadColumnFamiliesOnDemandValue() {
718 return this.loadColumnFamiliesOnDemand;
719 }
720
721
722
723
724 public boolean doLoadColumnFamiliesOnDemand() {
725 return (this.loadColumnFamiliesOnDemand != null)
726 && this.loadColumnFamiliesOnDemand.booleanValue();
727 }
728
729
730
731
732
733
734
735 @Override
736 public Map<String, Object> getFingerprint() {
737 Map<String, Object> map = new HashMap<String, Object>();
738 List<String> families = new ArrayList<String>();
739 if(this.familyMap.size() == 0) {
740 map.put("families", "ALL");
741 return map;
742 } else {
743 map.put("families", families);
744 }
745 for (Map.Entry<byte [], NavigableSet<byte[]>> entry :
746 this.familyMap.entrySet()) {
747 families.add(Bytes.toStringBinary(entry.getKey()));
748 }
749 return map;
750 }
751
752
753
754
755
756
757
758
759 @Override
760 public Map<String, Object> toMap(int maxCols) {
761
762 Map<String, Object> map = getFingerprint();
763
764 Map<String, List<String>> familyColumns =
765 new HashMap<String, List<String>>();
766 map.put("families", familyColumns);
767
768 map.put("startRow", Bytes.toStringBinary(this.startRow));
769 map.put("stopRow", Bytes.toStringBinary(this.stopRow));
770 map.put("maxVersions", this.maxVersions);
771 map.put("batch", this.batch);
772 map.put("caching", this.caching);
773 map.put("maxResultSize", this.maxResultSize);
774 map.put("cacheBlocks", this.cacheBlocks);
775 map.put("loadColumnFamiliesOnDemand", this.loadColumnFamiliesOnDemand);
776 List<Long> timeRange = new ArrayList<Long>();
777 timeRange.add(this.tr.getMin());
778 timeRange.add(this.tr.getMax());
779 map.put("timeRange", timeRange);
780 int colCount = 0;
781
782 for (Map.Entry<byte [], NavigableSet<byte[]>> entry :
783 this.familyMap.entrySet()) {
784 List<String> columns = new ArrayList<String>();
785 familyColumns.put(Bytes.toStringBinary(entry.getKey()), columns);
786 if(entry.getValue() == null) {
787 colCount++;
788 --maxCols;
789 columns.add("ALL");
790 } else {
791 colCount += entry.getValue().size();
792 if (maxCols <= 0) {
793 continue;
794 }
795 for (byte [] column : entry.getValue()) {
796 if (--maxCols <= 0) {
797 continue;
798 }
799 columns.add(Bytes.toStringBinary(column));
800 }
801 }
802 }
803 map.put("totalColumns", colCount);
804 if (this.filter != null) {
805 map.put("filter", this.filter.toString());
806 }
807
808 if (getId() != null) {
809 map.put("id", getId());
810 }
811 return map;
812 }
813
814
815
816
817
818
819
820
821
822
823
824 public Scan setRaw(boolean raw) {
825 setAttribute(RAW_ATTR, Bytes.toBytes(raw));
826 return this;
827 }
828
829
830
831
832 public boolean isRaw() {
833 byte[] attr = getAttribute(RAW_ATTR);
834 return attr == null ? false : Bytes.toBoolean(attr);
835 }
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859 public Scan setSmall(boolean small) {
860 this.small = small;
861 return this;
862 }
863
864
865
866
867
868 public boolean isSmall() {
869 return small;
870 }
871
872 @Override
873 public Scan setAttribute(String name, byte[] value) {
874 return (Scan) super.setAttribute(name, value);
875 }
876
877 @Override
878 public Scan setId(String id) {
879 return (Scan) super.setId(id);
880 }
881
882 @Override
883 public Scan setAuthorizations(Authorizations authorizations) {
884 return (Scan) super.setAuthorizations(authorizations);
885 }
886
887 @Override
888 public Scan setACL(Map<String, Permission> perms) {
889 return (Scan) super.setACL(perms);
890 }
891
892 @Override
893 public Scan setACL(String user, Permission perms) {
894 return (Scan) super.setACL(user, perms);
895 }
896
897 @Override
898 public Scan setConsistency(Consistency consistency) {
899 return (Scan) super.setConsistency(consistency);
900 }
901
902 @Override
903 public Scan setReplicaId(int Id) {
904 return (Scan) super.setReplicaId(Id);
905 }
906
907 @Override
908 public Scan setIsolationLevel(IsolationLevel level) {
909 return (Scan) super.setIsolationLevel(level);
910 }
911
912
913
914
915
916
917
918
919
920 static Scan createGetClosestRowOrBeforeReverseScan(byte[] row) {
921
922
923 Scan scan = new Scan(row);
924 scan.setSmall(true);
925 scan.setReversed(true);
926 scan.setCaching(1);
927 return scan;
928 }
929
930
931
932
933
934 public Scan setScanMetricsEnabled(final boolean enabled) {
935 setAttribute(Scan.SCAN_ATTRIBUTES_METRICS_ENABLE, Bytes.toBytes(Boolean.valueOf(enabled)));
936 return this;
937 }
938
939
940
941
942 public boolean isScanMetricsEnabled() {
943 byte[] attr = getAttribute(Scan.SCAN_ATTRIBUTES_METRICS_ENABLE);
944 return attr == null ? false : Bytes.toBoolean(attr);
945 }
946
947
948
949
950
951 public ScanMetrics getScanMetrics() {
952 byte [] bytes = getAttribute(Scan.SCAN_ATTRIBUTES_METRICS_DATA);
953 if (bytes == null) return null;
954 return ProtobufUtil.toScanMetrics(bytes);
955 }
956 }