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