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