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