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