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.nio.BufferOverflowException;
23 import java.nio.ByteBuffer;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Comparator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.NavigableMap;
30 import java.util.TreeMap;
31
32 import org.apache.hadoop.hbase.classification.InterfaceAudience;
33 import org.apache.hadoop.hbase.classification.InterfaceStability;
34 import org.apache.hadoop.hbase.Cell;
35 import org.apache.hadoop.hbase.CellScannable;
36 import org.apache.hadoop.hbase.CellScanner;
37 import org.apache.hadoop.hbase.CellUtil;
38 import org.apache.hadoop.hbase.KeyValue;
39 import org.apache.hadoop.hbase.KeyValueUtil;
40 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
41 import org.apache.hadoop.hbase.util.Bytes;
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 @InterfaceAudience.Public
77 @InterfaceStability.Stable
78 public class Result implements CellScannable, CellScanner {
79 private Cell[] cells;
80 private Boolean exists;
81
82
83 private transient byte [] row = null;
84
85 private transient NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> familyMap = null;
86
87 private static ThreadLocal<byte[]> localBuffer = new ThreadLocal<byte[]>();
88 private static final int PAD_WIDTH = 128;
89 public static final Result EMPTY_RESULT = new Result(true);
90
91 private final static int INITIAL_CELLSCANNER_INDEX = -1;
92
93
94
95
96 private int cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
97 private ClientProtos.RegionLoadStats loadStats;
98
99 private final boolean readonly;
100
101
102
103
104
105
106
107 public Result() {
108 this(false);
109 }
110
111
112
113
114
115
116 private Result(boolean readonly) {
117 this.readonly = readonly;
118 }
119
120
121
122
123 @Deprecated
124 public Result(KeyValue [] cells) {
125 this(cells, null);
126 }
127
128
129
130
131 @Deprecated
132 public Result(List<KeyValue> kvs) {
133
134 this(kvs.toArray(new Cell[kvs.size()]), null);
135 }
136
137
138
139
140
141
142 public static Result create(List<Cell> cells) {
143 return new Result(cells.toArray(new Cell[cells.size()]), null);
144 }
145
146 public static Result create(List<Cell> cells, Boolean exists) {
147 if (exists != null){
148 return new Result(null, exists);
149 }
150 return new Result(cells.toArray(new Cell[cells.size()]), null);
151 }
152
153
154
155
156
157
158 public static Result create(Cell[] cells) {
159 return new Result(cells, null);
160 }
161
162
163 private Result(Cell[] cells, Boolean exists) {
164 this.cells = cells;
165 this.exists = exists;
166 this.readonly = false;
167 }
168
169
170
171
172
173
174 public byte [] getRow() {
175 if (this.row == null) {
176 this.row = this.cells == null || this.cells.length == 0? null: CellUtil.cloneRow(this.cells[0]);
177 }
178 return this.row;
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201 public Cell[] rawCells() {
202 return cells;
203 }
204
205
206
207
208
209
210
211
212
213
214
215 @Deprecated
216 public KeyValue[] raw() {
217 KeyValue[] kvs = new KeyValue[cells.length];
218 for (int i = 0 ; i < kvs.length; i++) {
219 kvs[i] = KeyValueUtil.ensureKeyValue(cells[i]);
220 }
221 return kvs;
222 }
223
224
225
226
227
228
229
230
231 public List<Cell> listCells() {
232 return isEmpty()? null: Arrays.asList(rawCells());
233 }
234
235
236
237
238
239
240
241
242
243
244
245 @Deprecated
246 public List<KeyValue> list() {
247 return isEmpty() ? null : Arrays.asList(raw());
248 }
249
250
251
252
253 @Deprecated
254 public List<KeyValue> getColumn(byte [] family, byte [] qualifier) {
255 return KeyValueUtil.ensureKeyValues(getColumnCells(family, qualifier));
256 }
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273 public List<Cell> getColumnCells(byte [] family, byte [] qualifier) {
274 List<Cell> result = new ArrayList<Cell>();
275
276 Cell [] kvs = rawCells();
277
278 if (kvs == null || kvs.length == 0) {
279 return result;
280 }
281 int pos = binarySearch(kvs, family, qualifier);
282 if (pos == -1) {
283 return result;
284 }
285
286 for (int i = pos ; i < kvs.length ; i++ ) {
287 KeyValue kv = KeyValueUtil.ensureKeyValue(kvs[i]);
288 if (kv.matchingColumn(family,qualifier)) {
289 result.add(kv);
290 } else {
291 break;
292 }
293 }
294
295 return result;
296 }
297
298 protected int binarySearch(final Cell [] kvs,
299 final byte [] family,
300 final byte [] qualifier) {
301 Cell searchTerm =
302 KeyValue.createFirstOnRow(CellUtil.cloneRow(kvs[0]),
303 family, qualifier);
304
305
306 int pos = Arrays.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
307
308 if (pos < 0) {
309 pos = (pos+1) * -1;
310
311 }
312 if (pos == kvs.length) {
313 return -1;
314 }
315 return pos;
316 }
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331 protected int binarySearch(final Cell [] kvs,
332 final byte [] family, final int foffset, final int flength,
333 final byte [] qualifier, final int qoffset, final int qlength) {
334
335 double keyValueSize = (double)
336 KeyValue.getKeyValueDataStructureSize(kvs[0].getRowLength(), flength, qlength, 0);
337
338 byte[] buffer = localBuffer.get();
339 if (buffer == null || keyValueSize > buffer.length) {
340
341 buffer = new byte[(int) Math.ceil(keyValueSize / PAD_WIDTH) * PAD_WIDTH];
342 localBuffer.set(buffer);
343 }
344
345 Cell searchTerm = KeyValue.createFirstOnRow(buffer, 0,
346 kvs[0].getRowArray(), kvs[0].getRowOffset(), kvs[0].getRowLength(),
347 family, foffset, flength,
348 qualifier, qoffset, qlength);
349
350
351 int pos = Arrays.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
352
353 if (pos < 0) {
354 pos = (pos+1) * -1;
355
356 }
357 if (pos == kvs.length) {
358 return -1;
359 }
360 return pos;
361 }
362
363
364
365
366 @Deprecated
367 public KeyValue getColumnLatest(byte [] family, byte [] qualifier) {
368 return KeyValueUtil.ensureKeyValue(getColumnLatestCell(family, qualifier));
369 }
370
371
372
373
374
375
376
377
378
379
380 public Cell getColumnLatestCell(byte [] family, byte [] qualifier) {
381 Cell [] kvs = rawCells();
382 if (kvs == null || kvs.length == 0) {
383 return null;
384 }
385 int pos = binarySearch(kvs, family, qualifier);
386 if (pos == -1) {
387 return null;
388 }
389 KeyValue kv = KeyValueUtil.ensureKeyValue(kvs[pos]);
390 if (kv.matchingColumn(family, qualifier)) {
391 return kv;
392 }
393 return null;
394 }
395
396
397
398
399 @Deprecated
400 public KeyValue getColumnLatest(byte [] family, int foffset, int flength,
401 byte [] qualifier, int qoffset, int qlength) {
402 return KeyValueUtil.ensureKeyValue(
403 getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength));
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419 public Cell getColumnLatestCell(byte [] family, int foffset, int flength,
420 byte [] qualifier, int qoffset, int qlength) {
421
422 Cell [] kvs = rawCells();
423 if (kvs == null || kvs.length == 0) {
424 return null;
425 }
426 int pos = binarySearch(kvs, family, foffset, flength, qualifier, qoffset, qlength);
427 if (pos == -1) {
428 return null;
429 }
430 KeyValue kv = KeyValueUtil.ensureKeyValue(kvs[pos]);
431 if (kv.matchingColumn(family, foffset, flength, qualifier, qoffset, qlength)) {
432 return kv;
433 }
434 return null;
435 }
436
437
438
439
440
441
442
443 public byte[] getValue(byte [] family, byte [] qualifier) {
444 Cell kv = getColumnLatestCell(family, qualifier);
445 if (kv == null) {
446 return null;
447 }
448 return CellUtil.cloneValue(kv);
449 }
450
451
452
453
454
455
456
457
458
459 public ByteBuffer getValueAsByteBuffer(byte [] family, byte [] qualifier) {
460
461 Cell kv = getColumnLatestCell(family, 0, family.length, qualifier, 0, qualifier.length);
462
463 if (kv == null) {
464 return null;
465 }
466 return ByteBuffer.wrap(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength());
467 }
468
469
470
471
472
473
474
475
476
477
478
479
480
481 public ByteBuffer getValueAsByteBuffer(byte [] family, int foffset, int flength,
482 byte [] qualifier, int qoffset, int qlength) {
483
484 Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
485
486 if (kv == null) {
487 return null;
488 }
489 return ByteBuffer.wrap(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength());
490 }
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505 public boolean loadValue(byte [] family, byte [] qualifier, ByteBuffer dst)
506 throws BufferOverflowException {
507 return loadValue(family, 0, family.length, qualifier, 0, qualifier.length, dst);
508 }
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527 public boolean loadValue(byte [] family, int foffset, int flength,
528 byte [] qualifier, int qoffset, int qlength, ByteBuffer dst)
529 throws BufferOverflowException {
530 Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
531
532 if (kv == null) {
533 return false;
534 }
535 dst.put(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength());
536 return true;
537 }
538
539
540
541
542
543
544
545
546
547 public boolean containsNonEmptyColumn(byte [] family, byte [] qualifier) {
548
549 return containsNonEmptyColumn(family, 0, family.length, qualifier, 0, qualifier.length);
550 }
551
552
553
554
555
556
557
558
559
560
561
562
563
564 public boolean containsNonEmptyColumn(byte [] family, int foffset, int flength,
565 byte [] qualifier, int qoffset, int qlength) {
566
567 Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
568
569 return (kv != null) && (kv.getValueLength() > 0);
570 }
571
572
573
574
575
576
577
578
579
580 public boolean containsEmptyColumn(byte [] family, byte [] qualifier) {
581
582 return containsEmptyColumn(family, 0, family.length, qualifier, 0, qualifier.length);
583 }
584
585
586
587
588
589
590
591
592
593
594
595
596
597 public boolean containsEmptyColumn(byte [] family, int foffset, int flength,
598 byte [] qualifier, int qoffset, int qlength) {
599 Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
600
601 return (kv != null) && (kv.getValueLength() == 0);
602 }
603
604
605
606
607
608
609
610
611
612 public boolean containsColumn(byte [] family, byte [] qualifier) {
613 Cell kv = getColumnLatestCell(family, qualifier);
614 return kv != null;
615 }
616
617
618
619
620
621
622
623
624
625
626
627
628
629 public boolean containsColumn(byte [] family, int foffset, int flength,
630 byte [] qualifier, int qoffset, int qlength) {
631
632 return getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength) != null;
633 }
634
635
636
637
638
639
640
641
642
643
644 public NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> getMap() {
645 if (this.familyMap != null) {
646 return this.familyMap;
647 }
648 if(isEmpty()) {
649 return null;
650 }
651 this.familyMap = new TreeMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>>(Bytes.BYTES_COMPARATOR);
652 for(Cell kv : this.cells) {
653 byte [] family = CellUtil.cloneFamily(kv);
654 NavigableMap<byte[], NavigableMap<Long, byte[]>> columnMap =
655 familyMap.get(family);
656 if(columnMap == null) {
657 columnMap = new TreeMap<byte[], NavigableMap<Long, byte[]>>
658 (Bytes.BYTES_COMPARATOR);
659 familyMap.put(family, columnMap);
660 }
661 byte [] qualifier = CellUtil.cloneQualifier(kv);
662 NavigableMap<Long, byte[]> versionMap = columnMap.get(qualifier);
663 if(versionMap == null) {
664 versionMap = new TreeMap<Long, byte[]>(new Comparator<Long>() {
665 public int compare(Long l1, Long l2) {
666 return l2.compareTo(l1);
667 }
668 });
669 columnMap.put(qualifier, versionMap);
670 }
671 Long timestamp = kv.getTimestamp();
672 byte [] value = CellUtil.cloneValue(kv);
673
674 versionMap.put(timestamp, value);
675 }
676 return this.familyMap;
677 }
678
679
680
681
682
683
684
685
686
687 public NavigableMap<byte[], NavigableMap<byte[], byte[]>> getNoVersionMap() {
688 if(this.familyMap == null) {
689 getMap();
690 }
691 if(isEmpty()) {
692 return null;
693 }
694 NavigableMap<byte[], NavigableMap<byte[], byte[]>> returnMap =
695 new TreeMap<byte[], NavigableMap<byte[], byte[]>>(Bytes.BYTES_COMPARATOR);
696 for(Map.Entry<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>>
697 familyEntry : familyMap.entrySet()) {
698 NavigableMap<byte[], byte[]> qualifierMap =
699 new TreeMap<byte[], byte[]>(Bytes.BYTES_COMPARATOR);
700 for(Map.Entry<byte[], NavigableMap<Long, byte[]>> qualifierEntry :
701 familyEntry.getValue().entrySet()) {
702 byte [] value =
703 qualifierEntry.getValue().get(qualifierEntry.getValue().firstKey());
704 qualifierMap.put(qualifierEntry.getKey(), value);
705 }
706 returnMap.put(familyEntry.getKey(), qualifierMap);
707 }
708 return returnMap;
709 }
710
711
712
713
714
715
716
717
718 public NavigableMap<byte[], byte[]> getFamilyMap(byte [] family) {
719 if(this.familyMap == null) {
720 getMap();
721 }
722 if(isEmpty()) {
723 return null;
724 }
725 NavigableMap<byte[], byte[]> returnMap =
726 new TreeMap<byte[], byte[]>(Bytes.BYTES_COMPARATOR);
727 NavigableMap<byte[], NavigableMap<Long, byte[]>> qualifierMap =
728 familyMap.get(family);
729 if(qualifierMap == null) {
730 return returnMap;
731 }
732 for(Map.Entry<byte[], NavigableMap<Long, byte[]>> entry :
733 qualifierMap.entrySet()) {
734 byte [] value =
735 entry.getValue().get(entry.getValue().firstKey());
736 returnMap.put(entry.getKey(), value);
737 }
738 return returnMap;
739 }
740
741
742
743
744
745 public byte [] value() {
746 if (isEmpty()) {
747 return null;
748 }
749 return CellUtil.cloneValue(cells[0]);
750 }
751
752
753
754
755
756 public boolean isEmpty() {
757 return this.cells == null || this.cells.length == 0;
758 }
759
760
761
762
763 public int size() {
764 return this.cells == null? 0: this.cells.length;
765 }
766
767
768
769
770 @Override
771 public String toString() {
772 StringBuilder sb = new StringBuilder();
773 sb.append("keyvalues=");
774 if(isEmpty()) {
775 sb.append("NONE");
776 return sb.toString();
777 }
778 sb.append("{");
779 boolean moreThanOne = false;
780 for(Cell kv : this.cells) {
781 if(moreThanOne) {
782 sb.append(", ");
783 } else {
784 moreThanOne = true;
785 }
786 sb.append(kv.toString());
787 }
788 sb.append("}");
789 return sb.toString();
790 }
791
792
793
794
795
796
797
798 public static void compareResults(Result res1, Result res2)
799 throws Exception {
800 if (res2 == null) {
801 throw new Exception("There wasn't enough rows, we stopped at "
802 + Bytes.toStringBinary(res1.getRow()));
803 }
804 if (res1.size() != res2.size()) {
805 throw new Exception("This row doesn't have the same number of KVs: "
806 + res1.toString() + " compared to " + res2.toString());
807 }
808 Cell[] ourKVs = res1.rawCells();
809 Cell[] replicatedKVs = res2.rawCells();
810 for (int i = 0; i < res1.size(); i++) {
811 if (!ourKVs[i].equals(replicatedKVs[i]) ||
812 !Bytes.equals(CellUtil.cloneValue(ourKVs[i]), CellUtil.cloneValue(replicatedKVs[i]))) {
813 throw new Exception("This result was different: "
814 + res1.toString() + " compared to " + res2.toString());
815 }
816 }
817 }
818
819
820
821
822
823
824
825 public void copyFrom(Result other) {
826 checkReadonly();
827 this.row = null;
828 this.familyMap = null;
829 this.cells = other.cells;
830 }
831
832 @Override
833 public CellScanner cellScanner() {
834
835 this.cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
836 return this;
837 }
838
839 @Override
840 public Cell current() {
841 if (cells == null) return null;
842 return (cellScannerIndex < 0)? null: this.cells[cellScannerIndex];
843 }
844
845 @Override
846 public boolean advance() {
847 if (cells == null) return false;
848 return ++cellScannerIndex < this.cells.length;
849 }
850
851 public Boolean getExists() {
852 return exists;
853 }
854
855 public void setExists(Boolean exists) {
856 checkReadonly();
857 this.exists = exists;
858 }
859
860
861
862
863
864
865
866 public void addResults(ClientProtos.RegionLoadStats loadStats) {
867 checkReadonly();
868 this.loadStats = loadStats;
869 }
870
871
872
873
874
875 public ClientProtos.RegionLoadStats getStats() {
876 return loadStats;
877 }
878
879
880
881
882
883 private void checkReadonly() {
884 if (readonly == true) {
885 throw new UnsupportedOperationException("Attempting to modify readonly EMPTY_RESULT!");
886 }
887 }
888 }