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 org.apache.hadoop.hbase.KeyValue;
24 import org.apache.hadoop.hbase.KeyValue.SplitKeyValue;
25 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
26 import org.apache.hadoop.hbase.util.Bytes;
27 import org.apache.hadoop.io.Writable;
28
29 import java.io.DataInput;
30 import java.io.DataOutput;
31 import java.io.IOException;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Comparator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.NavigableMap;
38 import java.util.TreeMap;
39
40
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 public class Result implements Writable {
66 private static final byte RESULT_VERSION = (byte)1;
67
68 private KeyValue [] kvs = null;
69 private NavigableMap<byte[],
70 NavigableMap<byte[], NavigableMap<Long, byte[]>>> familyMap = null;
71
72
73 private transient byte [] row = null;
74 private ImmutableBytesWritable bytes = null;
75
76
77
78
79 public Result() {}
80
81
82
83
84
85 public Result(KeyValue [] kvs) {
86 if(kvs != null && kvs.length > 0) {
87 this.kvs = kvs;
88 }
89 }
90
91
92
93
94
95 public Result(List<KeyValue> kvs) {
96 this(kvs.toArray(new KeyValue[0]));
97 }
98
99
100
101
102
103 public Result(ImmutableBytesWritable bytes) {
104 this.bytes = bytes;
105 }
106
107
108
109
110
111 public synchronized byte [] getRow() {
112 if (this.row == null) {
113 if(this.kvs == null) {
114 readFields();
115 }
116 this.row = this.kvs.length == 0? null: this.kvs[0].getRow();
117 }
118 return this.row;
119 }
120
121
122
123
124
125 public KeyValue[] raw() {
126 if(this.kvs == null) {
127 readFields();
128 }
129 return kvs;
130 }
131
132
133
134
135
136
137 public List<KeyValue> list() {
138 if(this.kvs == null) {
139 readFields();
140 }
141 return isEmpty()? null: Arrays.asList(sorted());
142 }
143
144
145
146
147
148
149
150
151 public KeyValue[] sorted() {
152 if (isEmpty()) {
153 return null;
154 }
155 Arrays.sort(kvs, KeyValue.COMPARATOR);
156 return kvs;
157 }
158
159
160
161
162
163
164
165
166
167
168 public NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> getMap() {
169 if(this.familyMap != null) {
170 return this.familyMap;
171 }
172 if(isEmpty()) {
173 return null;
174 }
175 this.familyMap =
176 new TreeMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>>
177 (Bytes.BYTES_COMPARATOR);
178 for(KeyValue kv : this.kvs) {
179 SplitKeyValue splitKV = kv.split();
180 byte [] family = splitKV.getFamily();
181 NavigableMap<byte[], NavigableMap<Long, byte[]>> columnMap =
182 familyMap.get(family);
183 if(columnMap == null) {
184 columnMap = new TreeMap<byte[], NavigableMap<Long, byte[]>>
185 (Bytes.BYTES_COMPARATOR);
186 familyMap.put(family, columnMap);
187 }
188 byte [] qualifier = splitKV.getQualifier();
189 NavigableMap<Long, byte[]> versionMap = columnMap.get(qualifier);
190 if(versionMap == null) {
191 versionMap = new TreeMap<Long, byte[]>(new Comparator<Long>() {
192 public int compare(Long l1, Long l2) {
193 return l2.compareTo(l1);
194 }
195 });
196 columnMap.put(qualifier, versionMap);
197 }
198 Long timestamp = Bytes.toLong(splitKV.getTimestamp());
199 byte [] value = splitKV.getValue();
200 versionMap.put(timestamp, value);
201 }
202 return this.familyMap;
203 }
204
205
206
207
208
209
210
211
212
213 public NavigableMap<byte[], NavigableMap<byte[], byte[]>> getNoVersionMap() {
214 if(this.familyMap == null) {
215 getMap();
216 }
217 if(isEmpty()) {
218 return null;
219 }
220 NavigableMap<byte[], NavigableMap<byte[], byte[]>> returnMap =
221 new TreeMap<byte[], NavigableMap<byte[], byte[]>>(Bytes.BYTES_COMPARATOR);
222 for(Map.Entry<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>>
223 familyEntry : familyMap.entrySet()) {
224 NavigableMap<byte[], byte[]> qualifierMap =
225 new TreeMap<byte[], byte[]>(Bytes.BYTES_COMPARATOR);
226 for(Map.Entry<byte[], NavigableMap<Long, byte[]>> qualifierEntry :
227 familyEntry.getValue().entrySet()) {
228 byte [] value =
229 qualifierEntry.getValue().get(qualifierEntry.getValue().firstKey());
230 qualifierMap.put(qualifierEntry.getKey(), value);
231 }
232 returnMap.put(familyEntry.getKey(), qualifierMap);
233 }
234 return returnMap;
235 }
236
237
238
239
240
241
242
243
244 public NavigableMap<byte[], byte[]> getFamilyMap(byte [] family) {
245 if(this.familyMap == null) {
246 getMap();
247 }
248 if(isEmpty()) {
249 return null;
250 }
251 NavigableMap<byte[], byte[]> returnMap =
252 new TreeMap<byte[], byte[]>(Bytes.BYTES_COMPARATOR);
253 NavigableMap<byte[], NavigableMap<Long, byte[]>> qualifierMap =
254 familyMap.get(family);
255 if(qualifierMap == null) {
256 return returnMap;
257 }
258 for(Map.Entry<byte[], NavigableMap<Long, byte[]>> entry :
259 qualifierMap.entrySet()) {
260 byte [] value =
261 entry.getValue().get(entry.getValue().firstKey());
262 returnMap.put(entry.getKey(), value);
263 }
264 return returnMap;
265 }
266
267
268
269
270
271
272
273 public byte [] getValue(byte [] family, byte [] qualifier) {
274 Map.Entry<Long,byte[]> entry = getKeyValue(family, qualifier);
275 return entry == null? null: entry.getValue();
276 }
277
278 private Map.Entry<Long,byte[]> getKeyValue(byte[] family, byte[] qualifier) {
279 if(this.familyMap == null) {
280 getMap();
281 }
282 if(isEmpty()) {
283 return null;
284 }
285 NavigableMap<byte [], NavigableMap<Long, byte[]>> qualifierMap =
286 familyMap.get(family);
287 if(qualifierMap == null) {
288 return null;
289 }
290 NavigableMap<Long, byte[]> versionMap =
291 getVersionMap(qualifierMap, qualifier);
292 if(versionMap == null) {
293 return null;
294 }
295 return versionMap.firstEntry();
296 }
297
298 private NavigableMap<Long, byte[]> getVersionMap(
299 NavigableMap<byte [], NavigableMap<Long, byte[]>> qualifierMap, byte [] qualifier) {
300 return qualifier != null?
301 qualifierMap.get(qualifier): qualifierMap.get(new byte[0]);
302 }
303
304
305
306
307
308
309
310 public boolean containsColumn(byte [] family, byte [] qualifier) {
311 if(this.familyMap == null) {
312 getMap();
313 }
314 if(isEmpty()) {
315 return false;
316 }
317 NavigableMap<byte [], NavigableMap<Long, byte[]>> qualifierMap =
318 familyMap.get(family);
319 if(qualifierMap == null) {
320 return false;
321 }
322 NavigableMap<Long, byte[]> versionMap = getVersionMap(qualifierMap, qualifier);
323 return versionMap != null;
324 }
325
326
327
328
329
330 public byte [] value() {
331 if (isEmpty()) {
332 return null;
333 }
334 return kvs[0].getValue();
335 }
336
337
338
339
340
341
342
343
344
345 public ImmutableBytesWritable getBytes() {
346 return this.bytes;
347 }
348
349
350
351
352
353 public boolean isEmpty() {
354 if(this.kvs == null) {
355 readFields();
356 }
357 return this.kvs == null || this.kvs.length == 0;
358 }
359
360
361
362
363 public int size() {
364 if(this.kvs == null) {
365 readFields();
366 }
367 return this.kvs == null? 0: this.kvs.length;
368 }
369
370
371
372
373 @Override
374 public String toString() {
375 StringBuilder sb = new StringBuilder();
376 sb.append("keyvalues=");
377 if(isEmpty()) {
378 sb.append("NONE");
379 return sb.toString();
380 }
381 sb.append("{");
382 boolean moreThanOne = false;
383 for(KeyValue kv : this.kvs) {
384 if(moreThanOne) {
385 sb.append(", ");
386 } else {
387 moreThanOne = true;
388 }
389 sb.append(kv.toString());
390 }
391 sb.append("}");
392 return sb.toString();
393 }
394
395
396 public void readFields(final DataInput in)
397 throws IOException {
398 familyMap = null;
399 row = null;
400 kvs = null;
401 int totalBuffer = in.readInt();
402 if(totalBuffer == 0) {
403 bytes = null;
404 return;
405 }
406 byte [] raw = new byte[totalBuffer];
407 in.readFully(raw, 0, totalBuffer);
408 bytes = new ImmutableBytesWritable(raw, 0, totalBuffer);
409 }
410
411
412 private void readFields() {
413 if (bytes == null) {
414 this.kvs = new KeyValue[0];
415 return;
416 }
417 byte [] buf = bytes.get();
418 int offset = bytes.getOffset();
419 int finalOffset = bytes.getSize() + offset;
420 List<KeyValue> kvs = new ArrayList<KeyValue>();
421 while(offset < finalOffset) {
422 int keyLength = Bytes.toInt(buf, offset);
423 offset += Bytes.SIZEOF_INT;
424 kvs.add(new KeyValue(buf, offset, keyLength));
425 offset += keyLength;
426 }
427 this.kvs = kvs.toArray(new KeyValue[kvs.size()]);
428 }
429
430 public void write(final DataOutput out)
431 throws IOException {
432 if(isEmpty()) {
433 out.writeInt(0);
434 } else {
435 int totalLen = 0;
436 for(KeyValue kv : kvs) {
437 totalLen += kv.getLength() + Bytes.SIZEOF_INT;
438 }
439 out.writeInt(totalLen);
440 for(KeyValue kv : kvs) {
441 out.writeInt(kv.getLength());
442 out.write(kv.getBuffer(), kv.getOffset(), kv.getLength());
443 }
444 }
445 }
446
447 public static void writeArray(final DataOutput out, Result [] results)
448 throws IOException {
449
450
451
452
453 out.writeByte(RESULT_VERSION);
454 if(results == null || results.length == 0) {
455 out.writeInt(0);
456 return;
457 }
458 out.writeInt(results.length);
459 int bufLen = 0;
460 for(Result result : results) {
461 bufLen += Bytes.SIZEOF_INT;
462 if(result == null || result.isEmpty()) {
463 continue;
464 }
465 for(KeyValue key : result.raw()) {
466 bufLen += key.getLength() + Bytes.SIZEOF_INT;
467 }
468 }
469 out.writeInt(bufLen);
470 for(Result result : results) {
471 if(result == null || result.isEmpty()) {
472 out.writeInt(0);
473 continue;
474 }
475 out.writeInt(result.size());
476 for(KeyValue kv : result.raw()) {
477 out.writeInt(kv.getLength());
478 out.write(kv.getBuffer(), kv.getOffset(), kv.getLength());
479 }
480 }
481 }
482
483 public static Result [] readArray(final DataInput in)
484 throws IOException {
485
486
487
488
489 int version = in.readByte();
490 if (version > RESULT_VERSION) {
491 throw new IOException("version not supported");
492 }
493 int numResults = in.readInt();
494 if(numResults == 0) {
495 return new Result[0];
496 }
497 Result [] results = new Result[numResults];
498 int bufSize = in.readInt();
499 byte [] buf = new byte[bufSize];
500 int offset = 0;
501 for(int i=0;i<numResults;i++) {
502 int numKeys = in.readInt();
503 offset += Bytes.SIZEOF_INT;
504 if(numKeys == 0) {
505 results[i] = new Result((ImmutableBytesWritable)null);
506 continue;
507 }
508 int initialOffset = offset;
509 for(int j=0;j<numKeys;j++) {
510 int keyLen = in.readInt();
511 Bytes.putInt(buf, offset, keyLen);
512 offset += Bytes.SIZEOF_INT;
513 in.readFully(buf, offset, keyLen);
514 offset += keyLen;
515 }
516 int totalLength = offset - initialOffset;
517 results[i] = new Result(new ImmutableBytesWritable(buf, initialOffset,
518 totalLength));
519 }
520 return results;
521 }
522 }