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