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