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