1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.client;
22
23 import org.apache.hadoop.hbase.HConstants;
24 import org.apache.hadoop.hbase.filter.Filter;
25 import org.apache.hadoop.hbase.filter.IncompatibleFilterException;
26 import org.apache.hadoop.hbase.io.TimeRange;
27 import org.apache.hadoop.hbase.util.Bytes;
28 import org.apache.hadoop.hbase.util.Classes;
29 import org.apache.hadoop.io.Writable;
30
31 import java.io.DataInput;
32 import java.io.DataOutput;
33 import java.io.IOException;
34 import java.util.ArrayList;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.NavigableSet;
39 import java.util.TreeMap;
40 import java.util.TreeSet;
41
42
43
44
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 public class Scan extends OperationWithAttributes implements Writable {
83 private static final String RAW_ATTR = "_raw_";
84 private static final String ONDEMAND_ATTR = "_ondemand_";
85 private static final String ISOLATION_LEVEL = "_isolationlevel_";
86
87
88 private static final String SMALL_ATTR = "_small_";
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 public static final String HINT_LOOKAHEAD = "_look_ahead_";
105
106 private static final byte SCAN_VERSION = (byte)2;
107 private byte [] startRow = HConstants.EMPTY_START_ROW;
108 private byte [] stopRow = HConstants.EMPTY_END_ROW;
109 private int maxVersions = 1;
110 private int batch = -1;
111
112
113 static public String SCAN_ATTRIBUTES_METRICS_ENABLE = "scan.attributes.metrics.enable";
114 static public String SCAN_ATTRIBUTES_METRICS_DATA = "scan.attributes.metrics.data";
115
116
117
118
119 static public final String SCAN_ATTRIBUTES_TABLE_NAME = "scan.attributes.table.name";
120
121
122
123
124 private int caching = -1;
125 private boolean cacheBlocks = true;
126 private Filter filter = null;
127 private TimeRange tr = new TimeRange();
128 private Map<byte [], NavigableSet<byte []>> familyMap =
129 new TreeMap<byte [], NavigableSet<byte []>>(Bytes.BYTES_COMPARATOR);
130
131
132
133
134 public Scan() {}
135
136 public Scan(byte [] startRow, Filter filter) {
137 this(startRow);
138 this.filter = filter;
139 }
140
141
142
143
144
145
146
147
148 public Scan(byte [] startRow) {
149 this.startRow = startRow;
150 }
151
152
153
154
155
156
157 public Scan(byte [] startRow, byte [] stopRow) {
158 this.startRow = startRow;
159 this.stopRow = stopRow;
160 }
161
162
163
164
165
166
167
168 public Scan(Scan scan) throws IOException {
169 startRow = scan.getStartRow();
170 stopRow = scan.getStopRow();
171 maxVersions = scan.getMaxVersions();
172 batch = scan.getBatch();
173 caching = scan.getCaching();
174 cacheBlocks = scan.getCacheBlocks();
175 filter = scan.getFilter();
176 TimeRange ctr = scan.getTimeRange();
177 tr = new TimeRange(ctr.getMin(), ctr.getMax());
178 Map<byte[], NavigableSet<byte[]>> fams = scan.getFamilyMap();
179 for (Map.Entry<byte[],NavigableSet<byte[]>> entry : fams.entrySet()) {
180 byte [] fam = entry.getKey();
181 NavigableSet<byte[]> cols = entry.getValue();
182 if (cols != null && cols.size() > 0) {
183 for (byte[] col : cols) {
184 addColumn(fam, col);
185 }
186 } else {
187 addFamily(fam);
188 }
189 }
190 for (Map.Entry<String, byte[]> attr : scan.getAttributesMap().entrySet()) {
191 setAttribute(attr.getKey(), attr.getValue());
192 }
193 }
194
195
196
197
198
199 public Scan(Get get) {
200 this.startRow = get.getRow();
201 this.stopRow = get.getRow();
202 this.filter = get.getFilter();
203 this.cacheBlocks = get.getCacheBlocks();
204 this.maxVersions = get.getMaxVersions();
205 this.tr = get.getTimeRange();
206 this.familyMap = get.getFamilyMap();
207 }
208
209 public boolean isGetScan() {
210 return this.startRow != null && this.startRow.length > 0 &&
211 Bytes.equals(this.startRow, this.stopRow);
212 }
213
214
215
216
217
218
219
220
221 public Scan addFamily(byte [] family) {
222 familyMap.remove(family);
223 familyMap.put(family, null);
224 return this;
225 }
226
227
228
229
230
231
232
233
234
235 public Scan addColumn(byte [] family, byte [] qualifier) {
236 NavigableSet<byte []> set = familyMap.get(family);
237 if(set == null) {
238 set = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR);
239 }
240 if (qualifier == null) {
241 qualifier = HConstants.EMPTY_BYTE_ARRAY;
242 }
243 set.add(qualifier);
244 familyMap.put(family, set);
245
246 return this;
247 }
248
249
250
251
252
253
254
255
256
257
258
259
260
261 public Scan setTimeRange(long minStamp, long maxStamp)
262 throws IOException {
263 tr = new TimeRange(minStamp, maxStamp);
264 return this;
265 }
266
267
268
269
270
271
272
273
274
275
276
277 public Scan setTimeStamp(long timestamp) {
278 try {
279 tr = new TimeRange(timestamp, timestamp+1);
280 } catch(IOException e) {
281
282 }
283 return this;
284 }
285
286
287
288
289
290
291
292 public Scan setStartRow(byte [] startRow) {
293 this.startRow = startRow == null ? HConstants.EMPTY_START_ROW : startRow;
294 return this;
295 }
296
297
298
299
300
301
302
303 public Scan setStopRow(byte [] stopRow) {
304 this.stopRow = stopRow == null ? HConstants.EMPTY_END_ROW : stopRow;
305 return this;
306 }
307
308
309
310
311
312 public Scan setMaxVersions() {
313 this.maxVersions = Integer.MAX_VALUE;
314 return this;
315 }
316
317
318
319
320
321
322 public Scan setMaxVersions(int maxVersions) {
323 this.maxVersions = maxVersions;
324 return this;
325 }
326
327
328
329
330
331 public void setBatch(int batch) {
332 if (this.hasFilter() && this.filter.hasFilterRow()) {
333 throw new IncompatibleFilterException(
334 "Cannot set batch on a scan using a filter" +
335 " that returns true for filter.hasFilterRow");
336 }
337 this.batch = batch;
338 }
339
340
341
342
343
344
345
346 public void setCaching(int caching) {
347 this.caching = caching;
348 }
349
350
351
352
353
354
355 public Scan setFilter(Filter filter) {
356 this.filter = filter;
357 return this;
358 }
359
360
361
362
363
364
365 public Scan setFamilyMap(Map<byte [], NavigableSet<byte []>> familyMap) {
366 this.familyMap = familyMap;
367 return this;
368 }
369
370
371
372
373
374 public Map<byte [], NavigableSet<byte []>> getFamilyMap() {
375 return this.familyMap;
376 }
377
378
379
380
381 public int numFamilies() {
382 if(hasFamilies()) {
383 return this.familyMap.size();
384 }
385 return 0;
386 }
387
388
389
390
391 public boolean hasFamilies() {
392 return !this.familyMap.isEmpty();
393 }
394
395
396
397
398 public byte[][] getFamilies() {
399 if(hasFamilies()) {
400 return this.familyMap.keySet().toArray(new byte[0][0]);
401 }
402 return null;
403 }
404
405
406
407
408 public byte [] getStartRow() {
409 return this.startRow;
410 }
411
412
413
414
415 public byte [] getStopRow() {
416 return this.stopRow;
417 }
418
419
420
421
422 public int getMaxVersions() {
423 return this.maxVersions;
424 }
425
426
427
428
429 public int getBatch() {
430 return this.batch;
431 }
432
433
434
435
436 public int getCaching() {
437 return this.caching;
438 }
439
440
441
442
443 public TimeRange getTimeRange() {
444 return this.tr;
445 }
446
447
448
449
450 public Filter getFilter() {
451 return filter;
452 }
453
454
455
456
457 public boolean hasFilter() {
458 return filter != null;
459 }
460
461
462
463
464
465
466
467
468
469
470
471 public void setCacheBlocks(boolean cacheBlocks) {
472 this.cacheBlocks = cacheBlocks;
473 }
474
475
476
477
478
479
480 public boolean getCacheBlocks() {
481 return cacheBlocks;
482 }
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500 public void setLoadColumnFamiliesOnDemand(boolean value) {
501 setAttribute(ONDEMAND_ATTR, Bytes.toBytes(value));
502 }
503
504
505
506
507 public boolean doLoadColumnFamiliesOnDemand() {
508 byte[] attr = getAttribute(ONDEMAND_ATTR);
509 return attr == null ? false : Bytes.toBoolean(attr);
510 }
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532 public void setSmall(boolean small) {
533 setAttribute(SMALL_ATTR, Bytes.toBytes(small));
534 }
535
536
537
538
539
540 public boolean isSmall() {
541 byte[] attr = getAttribute(SMALL_ATTR);
542 return attr == null ? false : Bytes.toBoolean(attr);
543 }
544
545
546
547
548
549
550
551 @Override
552 public Map<String, Object> getFingerprint() {
553 Map<String, Object> map = new HashMap<String, Object>();
554 List<String> families = new ArrayList<String>();
555 if(this.familyMap.size() == 0) {
556 map.put("families", "ALL");
557 return map;
558 } else {
559 map.put("families", families);
560 }
561 for (Map.Entry<byte [], NavigableSet<byte[]>> entry :
562 this.familyMap.entrySet()) {
563 families.add(Bytes.toStringBinary(entry.getKey()));
564 }
565 return map;
566 }
567
568
569
570
571
572
573
574
575 @Override
576 public Map<String, Object> toMap(int maxCols) {
577
578 Map<String, Object> map = getFingerprint();
579
580 Map<String, List<String>> familyColumns =
581 new HashMap<String, List<String>>();
582 map.put("families", familyColumns);
583
584 map.put("startRow", Bytes.toStringBinary(this.startRow));
585 map.put("stopRow", Bytes.toStringBinary(this.stopRow));
586 map.put("maxVersions", this.maxVersions);
587 map.put("batch", this.batch);
588 map.put("caching", this.caching);
589 map.put("cacheBlocks", this.cacheBlocks);
590 List<Long> timeRange = new ArrayList<Long>();
591 timeRange.add(this.tr.getMin());
592 timeRange.add(this.tr.getMax());
593 map.put("timeRange", timeRange);
594 int colCount = 0;
595
596 for (Map.Entry<byte [], NavigableSet<byte[]>> entry :
597 this.familyMap.entrySet()) {
598 List<String> columns = new ArrayList<String>();
599 familyColumns.put(Bytes.toStringBinary(entry.getKey()), columns);
600 if(entry.getValue() == null) {
601 colCount++;
602 --maxCols;
603 columns.add("ALL");
604 } else {
605 colCount += entry.getValue().size();
606 if (maxCols <= 0) {
607 continue;
608 }
609 for (byte [] column : entry.getValue()) {
610 if (--maxCols <= 0) {
611 continue;
612 }
613 columns.add(Bytes.toStringBinary(column));
614 }
615 }
616 }
617 map.put("totalColumns", colCount);
618 if (this.filter != null) {
619 map.put("filter", this.filter.toString());
620 }
621
622 if (getId() != null) {
623 map.put("id", getId());
624 }
625 return map;
626 }
627
628
629 public void readFields(final DataInput in)
630 throws IOException {
631 int version = in.readByte();
632 if (version > (int)SCAN_VERSION) {
633 throw new IOException("version not supported");
634 }
635 this.startRow = Bytes.readByteArray(in);
636 this.stopRow = Bytes.readByteArray(in);
637 this.maxVersions = in.readInt();
638 this.batch = in.readInt();
639 this.caching = in.readInt();
640 this.cacheBlocks = in.readBoolean();
641 if(in.readBoolean()) {
642 this.filter = Classes.createWritableForName(
643 Bytes.toString(Bytes.readByteArray(in)));
644 this.filter.readFields(in);
645 }
646 this.tr = new TimeRange();
647 tr.readFields(in);
648 int numFamilies = in.readInt();
649 this.familyMap =
650 new TreeMap<byte [], NavigableSet<byte []>>(Bytes.BYTES_COMPARATOR);
651 for(int i=0; i<numFamilies; i++) {
652 byte [] family = Bytes.readByteArray(in);
653 int numColumns = in.readInt();
654 TreeSet<byte []> set = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR);
655 for(int j=0; j<numColumns; j++) {
656 byte [] qualifier = Bytes.readByteArray(in);
657 set.add(qualifier);
658 }
659 this.familyMap.put(family, set);
660 }
661
662 if (version > 1) {
663 readAttributes(in);
664 }
665 }
666
667 public void write(final DataOutput out)
668 throws IOException {
669 out.writeByte(SCAN_VERSION);
670 Bytes.writeByteArray(out, this.startRow);
671 Bytes.writeByteArray(out, this.stopRow);
672 out.writeInt(this.maxVersions);
673 out.writeInt(this.batch);
674 out.writeInt(this.caching);
675 out.writeBoolean(this.cacheBlocks);
676 if(this.filter == null) {
677 out.writeBoolean(false);
678 } else {
679 out.writeBoolean(true);
680 Bytes.writeByteArray(out, Bytes.toBytes(filter.getClass().getName()));
681 filter.write(out);
682 }
683 tr.write(out);
684 out.writeInt(familyMap.size());
685 for(Map.Entry<byte [], NavigableSet<byte []>> entry : familyMap.entrySet()) {
686 Bytes.writeByteArray(out, entry.getKey());
687 NavigableSet<byte []> columnSet = entry.getValue();
688 if(columnSet != null){
689 out.writeInt(columnSet.size());
690 for(byte [] qualifier : columnSet) {
691 Bytes.writeByteArray(out, qualifier);
692 }
693 } else {
694 out.writeInt(0);
695 }
696 }
697 writeAttributes(out);
698 }
699
700
701
702
703
704
705
706
707
708
709
710 public void setRaw(boolean raw) {
711 setAttribute(RAW_ATTR, Bytes.toBytes(raw));
712 }
713
714
715
716
717 public boolean isRaw() {
718 byte[] attr = getAttribute(RAW_ATTR);
719 return attr == null ? false : Bytes.toBoolean(attr);
720 }
721
722
723
724
725
726
727
728
729
730
731
732
733 public void setIsolationLevel(IsolationLevel level) {
734 setAttribute(ISOLATION_LEVEL, level.toBytes());
735 }
736
737
738
739
740
741
742 public IsolationLevel getIsolationLevel() {
743 byte[] attr = getAttribute(ISOLATION_LEVEL);
744 return attr == null ? IsolationLevel.READ_COMMITTED :
745 IsolationLevel.fromBytes(attr);
746 }
747 }