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