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