1 /*
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 package org.apache.hadoop.hbase.client;
21
22 import java.io.IOException;
23 import java.nio.BufferOverflowException;
24 import java.nio.ByteBuffer;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.Comparator;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.NavigableMap;
33 import java.util.NoSuchElementException;
34 import java.util.TreeMap;
35
36 import org.apache.hadoop.hbase.Cell;
37 import org.apache.hadoop.hbase.CellScannable;
38 import org.apache.hadoop.hbase.CellScanner;
39 import org.apache.hadoop.hbase.CellUtil;
40 import org.apache.hadoop.hbase.KeyValue;
41 import org.apache.hadoop.hbase.KeyValueUtil;
42 import org.apache.hadoop.hbase.classification.InterfaceAudience;
43 import org.apache.hadoop.hbase.classification.InterfaceStability;
44 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
45 import org.apache.hadoop.hbase.util.Bytes;
46
47 /**
48 * Single row result of a {@link Get} or {@link Scan} query.<p>
49 *
50 * This class is <b>NOT THREAD SAFE</b>.<p>
51 *
52 * Convenience methods are available that return various {@link Map}
53 * structures and values directly.<p>
54 *
55 * To get a complete mapping of all cells in the Result, which can include
56 * multiple families and multiple versions, use {@link #getMap()}.<p>
57 *
58 * To get a mapping of each family to its columns (qualifiers and values),
59 * including only the latest version of each, use {@link #getNoVersionMap()}.
60 *
61 * To get a mapping of qualifiers to latest values for an individual family use
62 * {@link #getFamilyMap(byte[])}.<p>
63 *
64 * To get the latest value for a specific family and qualifier use {@link #getValue(byte[], byte[])}.
65 *
66 * A Result is backed by an array of {@link Cell} objects, each representing
67 * an HBase cell defined by the row, family, qualifier, timestamp, and value.<p>
68 *
69 * The underlying {@link Cell} objects can be accessed through the method {@link #listCells()}.
70 * This will create a List from the internal Cell []. Better is to exploit the fact that
71 * a new Result instance is a primed {@link CellScanner}; just call {@link #advance()} and
72 * {@link #current()} to iterate over Cells as you would any {@link CellScanner}.
73 * Call {@link #cellScanner()} to reset should you need to iterate the same Result over again
74 * ({@link CellScanner}s are one-shot).
75 *
76 * If you need to overwrite a Result with another Result instance -- as in the old 'mapred'
77 * RecordReader next invocations -- then create an empty Result with the null constructor and
78 * in then use {@link #copyFrom(Result)}
79 */
80 @InterfaceAudience.Public
81 @InterfaceStability.Stable
82 public class Result implements CellScannable, CellScanner {
83 private Cell[] cells;
84 private Boolean exists; // if the query was just to check existence.
85 private boolean stale = false;
86
87 /**
88 * See {@link #mayHaveMoreCellsInRow()}.
89 */
90 private boolean mayHaveMoreCellsInRow = false;
91 // We're not using java serialization. Transient here is just a marker to say
92 // that this is where we cache row if we're ever asked for it.
93 private transient byte [] row = null;
94 // Ditto for familyMap. It can be composed on fly from passed in kvs.
95 private transient NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> familyMap = null;
96
97 private static ThreadLocal<byte[]> localBuffer = new ThreadLocal<byte[]>();
98 private static final int PAD_WIDTH = 128;
99 public static final Result EMPTY_RESULT = new Result(true);
100
101 private final static int INITIAL_CELLSCANNER_INDEX = -1;
102
103 /**
104 * Index for where we are when Result is acting as a {@link CellScanner}.
105 */
106 private int cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
107 private ClientProtos.RegionLoadStats stats;
108
109 private final boolean readonly;
110
111 private Cursor cursor = null;
112
113 /**
114 * Creates an empty Result w/ no KeyValue payload; returns null if you call {@link #rawCells()}.
115 * Use this to represent no results if <code>null</code> won't do or in old 'mapred' as oppposed to 'mapreduce' package
116 * MapReduce where you need to overwrite a Result
117 * instance with a {@link #copyFrom(Result)} call.
118 */
119 public Result() {
120 this(false);
121 }
122
123 /**
124 * Allows to construct special purpose immutable Result objects,
125 * such as EMPTY_RESULT.
126 * @param readonly whether this Result instance is readonly
127 */
128 private Result(boolean readonly) {
129 this.readonly = readonly;
130 }
131
132 /**
133 * @deprecated Use {@link #create(List)} instead.
134 */
135 @Deprecated
136 public Result(KeyValue [] cells) {
137 this(cells, null, false, false);
138 }
139
140 /**
141 * @deprecated Use {@link #create(List)} instead.
142 */
143 @Deprecated
144 public Result(List<KeyValue> kvs) {
145 // TODO: Here we presume the passed in Cells are KVs. One day this won't always be so.
146 this(kvs.toArray(new Cell[kvs.size()]), null, false, false);
147 }
148
149 /**
150 * Instantiate a Result with the specified List of KeyValues.
151 * <br><strong>Note:</strong> You must ensure that the keyvalues are already sorted.
152 * @param cells List of cells
153 */
154 public static Result create(List<Cell> cells) {
155 return create(cells, null);
156 }
157
158 public static Result create(List<Cell> cells, Boolean exists) {
159 return create(cells, exists, false);
160 }
161
162 public static Result create(List<Cell> cells, Boolean exists, boolean stale) {
163 return create(cells, exists, stale, false);
164 }
165
166 public static Result create(List<Cell> cells, Boolean exists, boolean stale, boolean partial) {
167 if (exists != null){
168 return new Result(null, exists, stale, partial);
169 }
170 return new Result(cells.toArray(new Cell[cells.size()]), null, stale, partial);
171 }
172
173 /**
174 * Instantiate a Result with the specified array of KeyValues.
175 * <br><strong>Note:</strong> You must ensure that the keyvalues are already sorted.
176 * @param cells array of cells
177 */
178 public static Result create(Cell[] cells) {
179 return create(cells, null, false);
180 }
181
182 public static Result create(Cell[] cells, Boolean exists, boolean stale) {
183 return create(cells, exists, stale, false);
184 }
185
186 public static Result create(Cell[] cells, Boolean exists, boolean stale,
187 boolean mayHaveMoreCellsInRow) {
188 if (exists != null) {
189 return new Result(null, exists, stale, mayHaveMoreCellsInRow);
190 }
191 return new Result(cells, null, stale, mayHaveMoreCellsInRow);
192 }
193
194 public static Result createCursorResult(Cursor cursor) {
195 return new Result(cursor);
196 }
197
198 private Result(Cursor cursor) {
199 this.cursor = cursor;
200 this.readonly = false;
201 }
202
203 /** Private ctor. Use {@link #create(Cell[])}. */
204 private Result(Cell[] cells, Boolean exists, boolean stale, boolean mayHaveMoreCellsInRow) {
205 this.cells = cells;
206 this.exists = exists;
207 this.stale = stale;
208 this.mayHaveMoreCellsInRow = mayHaveMoreCellsInRow;
209 this.readonly = false;
210 }
211
212 /**
213 * Method for retrieving the row key that corresponds to
214 * the row from which this Result was created.
215 * @return row
216 */
217 public byte [] getRow() {
218 if (this.row == null) {
219 this.row = this.cells == null || this.cells.length == 0? null: CellUtil.cloneRow(this.cells[0]);
220 }
221 return this.row;
222 }
223
224 /**
225 * Return the array of Cells backing this Result instance.
226 *
227 * The array is sorted from smallest -> largest using the
228 * {@link KeyValue#COMPARATOR}.
229 *
230 * The array only contains what your Get or Scan specifies and no more.
231 * For example if you request column "A" 1 version you will have at most 1
232 * Cell in the array. If you request column "A" with 2 version you will
233 * have at most 2 Cells, with the first one being the newer timestamp and
234 * the second being the older timestamp (this is the sort order defined by
235 * {@link KeyValue#COMPARATOR}). If columns don't exist, they won't be
236 * present in the result. Therefore if you ask for 1 version all columns,
237 * it is safe to iterate over this array and expect to see 1 Cell for
238 * each column and no more.
239 *
240 * This API is faster than using getFamilyMap() and getMap()
241 *
242 * @return array of Cells; can be null if nothing in the result
243 */
244 public Cell[] rawCells() {
245 return cells;
246 }
247
248 /**
249 * Return an cells of a Result as an array of KeyValues
250 *
251 * WARNING do not use, expensive. This does an arraycopy of the cell[]'s value.
252 *
253 * Added to ease transition from 0.94 -> 0.96.
254 *
255 * @deprecated as of 0.96, use {@link #rawCells()}
256 * @return array of KeyValues, empty array if nothing in result.
257 */
258 @Deprecated
259 public KeyValue[] raw() {
260 KeyValue[] kvs = new KeyValue[cells.length];
261 for (int i = 0 ; i < kvs.length; i++) {
262 kvs[i] = KeyValueUtil.ensureKeyValue(cells[i]);
263 }
264 return kvs;
265 }
266
267 /**
268 * Create a sorted list of the Cell's in this result.
269 *
270 * Since HBase 0.20.5 this is equivalent to raw().
271 *
272 * @return sorted List of Cells; can be null if no cells in the result
273 */
274 public List<Cell> listCells() {
275 return isEmpty()? null: Arrays.asList(rawCells());
276 }
277
278 /**
279 * Return an cells of a Result as an array of KeyValues
280 *
281 * WARNING do not use, expensive. This does an arraycopy of the cell[]'s value.
282 *
283 * Added to ease transition from 0.94 -> 0.96.
284 *
285 * @deprecated as of 0.96, use {@link #listCells()}
286 * @return all sorted List of KeyValues; can be null if no cells in the result
287 */
288 @Deprecated
289 public List<KeyValue> list() {
290 return isEmpty() ? null : Arrays.asList(raw());
291 }
292
293 /**
294 * @deprecated Use {@link #getColumnCells(byte[], byte[])} instead.
295 */
296 @Deprecated
297 public List<KeyValue> getColumn(byte [] family, byte [] qualifier) {
298 return KeyValueUtil.ensureKeyValues(getColumnCells(family, qualifier));
299 }
300
301 /**
302 * Return the Cells for the specific column. The Cells are sorted in
303 * the {@link KeyValue#COMPARATOR} order. That implies the first entry in
304 * the list is the most recent column. If the query (Scan or Get) only
305 * requested 1 version the list will contain at most 1 entry. If the column
306 * did not exist in the result set (either the column does not exist
307 * or the column was not selected in the query) the list will be empty.
308 *
309 * Also see getColumnLatest which returns just a Cell
310 *
311 * @param family the family
312 * @param qualifier
313 * @return a list of Cells for this column or empty list if the column
314 * did not exist in the result set
315 */
316 public List<Cell> getColumnCells(byte [] family, byte [] qualifier) {
317 List<Cell> result = new ArrayList<Cell>();
318
319 Cell [] kvs = rawCells();
320
321 if (kvs == null || kvs.length == 0) {
322 return result;
323 }
324 int pos = binarySearch(kvs, family, qualifier);
325 if (pos == -1) {
326 return result; // cant find it
327 }
328
329 for (int i = pos ; i < kvs.length ; i++ ) {
330 if (CellUtil.matchingColumn(kvs[i], family,qualifier)) {
331 result.add(kvs[i]);
332 } else {
333 break;
334 }
335 }
336
337 return result;
338 }
339
340 protected int binarySearch(final Cell [] kvs,
341 final byte [] family,
342 final byte [] qualifier) {
343 Cell searchTerm =
344 KeyValueUtil.createFirstOnRow(CellUtil.cloneRow(kvs[0]),
345 family, qualifier);
346
347 // pos === ( -(insertion point) - 1)
348 int pos = Arrays.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
349 // never will exact match
350 if (pos < 0) {
351 pos = (pos+1) * -1;
352 // pos is now insertion point
353 }
354 if (pos == kvs.length) {
355 return -1; // doesn't exist
356 }
357 return pos;
358 }
359
360 /**
361 * Searches for the latest value for the specified column.
362 *
363 * @param kvs the array to search
364 * @param family family name
365 * @param foffset family offset
366 * @param flength family length
367 * @param qualifier column qualifier
368 * @param qoffset qualifier offset
369 * @param qlength qualifier length
370 *
371 * @return the index where the value was found, or -1 otherwise
372 */
373 protected int binarySearch(final Cell [] kvs,
374 final byte [] family, final int foffset, final int flength,
375 final byte [] qualifier, final int qoffset, final int qlength) {
376
377 double keyValueSize = (double)
378 KeyValue.getKeyValueDataStructureSize(kvs[0].getRowLength(), flength, qlength, 0);
379
380 byte[] buffer = localBuffer.get();
381 if (buffer == null || keyValueSize > buffer.length) {
382 // pad to the smallest multiple of the pad width
383 buffer = new byte[(int) Math.ceil(keyValueSize / PAD_WIDTH) * PAD_WIDTH];
384 localBuffer.set(buffer);
385 }
386
387 Cell searchTerm = KeyValueUtil.createFirstOnRow(buffer, 0,
388 kvs[0].getRowArray(), kvs[0].getRowOffset(), kvs[0].getRowLength(),
389 family, foffset, flength,
390 qualifier, qoffset, qlength);
391
392 // pos === ( -(insertion point) - 1)
393 int pos = Arrays.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
394 // never will exact match
395 if (pos < 0) {
396 pos = (pos+1) * -1;
397 // pos is now insertion point
398 }
399 if (pos == kvs.length) {
400 return -1; // doesn't exist
401 }
402 return pos;
403 }
404
405 /**
406 * @deprecated Use {@link #getColumnLatestCell(byte[], byte[])} instead.
407 */
408 @Deprecated
409 public KeyValue getColumnLatest(byte [] family, byte [] qualifier) {
410 return KeyValueUtil.ensureKeyValue(getColumnLatestCell(family, qualifier));
411 }
412
413 /**
414 * The Cell for the most recent timestamp for a given column.
415 *
416 * @param family
417 * @param qualifier
418 *
419 * @return the Cell for the column, or null if no value exists in the row or none have been
420 * selected in the query (Get/Scan)
421 */
422 public Cell getColumnLatestCell(byte [] family, byte [] qualifier) {
423 Cell [] kvs = rawCells(); // side effect possibly.
424 if (kvs == null || kvs.length == 0) {
425 return null;
426 }
427 int pos = binarySearch(kvs, family, qualifier);
428 if (pos == -1) {
429 return null;
430 }
431 if (CellUtil.matchingColumn(kvs[pos], family, qualifier)) {
432 return kvs[pos];
433 }
434 return null;
435 }
436
437 /**
438 * @deprecated Use {@link #getColumnLatestCell(byte[], int, int, byte[], int, int)} instead.
439 */
440 @Deprecated
441 public KeyValue getColumnLatest(byte [] family, int foffset, int flength,
442 byte [] qualifier, int qoffset, int qlength) {
443 return KeyValueUtil.ensureKeyValue(
444 getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength));
445 }
446
447 /**
448 * The Cell for the most recent timestamp for a given column.
449 *
450 * @param family family name
451 * @param foffset family offset
452 * @param flength family length
453 * @param qualifier column qualifier
454 * @param qoffset qualifier offset
455 * @param qlength qualifier length
456 *
457 * @return the Cell for the column, or null if no value exists in the row or none have been
458 * selected in the query (Get/Scan)
459 */
460 public Cell getColumnLatestCell(byte [] family, int foffset, int flength,
461 byte [] qualifier, int qoffset, int qlength) {
462
463 Cell [] kvs = rawCells(); // side effect possibly.
464 if (kvs == null || kvs.length == 0) {
465 return null;
466 }
467 int pos = binarySearch(kvs, family, foffset, flength, qualifier, qoffset, qlength);
468 if (pos == -1) {
469 return null;
470 }
471 if (CellUtil.matchingColumn(kvs[pos], family, foffset, flength, qualifier, qoffset, qlength)) {
472 return kvs[pos];
473 }
474 return null;
475 }
476
477 /**
478 * Get the latest version of the specified column.
479 * Note: this call clones the value content of the hosting Cell. See
480 * {@link #getValueAsByteBuffer(byte[], byte[])}, etc., or {@link #listCells()} if you would
481 * avoid the cloning.
482 * @param family family name
483 * @param qualifier column qualifier
484 * @return value of latest version of column, null if none found
485 */
486 public byte[] getValue(byte [] family, byte [] qualifier) {
487 Cell kv = getColumnLatestCell(family, qualifier);
488 if (kv == null) {
489 return null;
490 }
491 return CellUtil.cloneValue(kv);
492 }
493
494 /**
495 * Returns the value wrapped in a new <code>ByteBuffer</code>.
496 *
497 * @param family family name
498 * @param qualifier column qualifier
499 *
500 * @return the latest version of the column, or <code>null</code> if none found
501 */
502 public ByteBuffer getValueAsByteBuffer(byte [] family, byte [] qualifier) {
503
504 Cell kv = getColumnLatestCell(family, 0, family.length, qualifier, 0, qualifier.length);
505
506 if (kv == null) {
507 return null;
508 }
509 return ByteBuffer.wrap(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()).
510 asReadOnlyBuffer();
511 }
512
513 /**
514 * Returns the value wrapped in a new <code>ByteBuffer</code>.
515 *
516 * @param family family name
517 * @param foffset family offset
518 * @param flength family length
519 * @param qualifier column qualifier
520 * @param qoffset qualifier offset
521 * @param qlength qualifier length
522 *
523 * @return the latest version of the column, or <code>null</code> if none found
524 */
525 public ByteBuffer getValueAsByteBuffer(byte [] family, int foffset, int flength,
526 byte [] qualifier, int qoffset, int qlength) {
527
528 Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
529
530 if (kv == null) {
531 return null;
532 }
533 return ByteBuffer.wrap(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()).
534 asReadOnlyBuffer();
535 }
536
537 /**
538 * Loads the latest version of the specified column into the provided <code>ByteBuffer</code>.
539 * <p>
540 * Does not clear or flip the buffer.
541 *
542 * @param family family name
543 * @param qualifier column qualifier
544 * @param dst the buffer where to write the value
545 *
546 * @return <code>true</code> if a value was found, <code>false</code> otherwise
547 *
548 * @throws BufferOverflowException there is insufficient space remaining in the buffer
549 */
550 public boolean loadValue(byte [] family, byte [] qualifier, ByteBuffer dst)
551 throws BufferOverflowException {
552 return loadValue(family, 0, family.length, qualifier, 0, qualifier.length, dst);
553 }
554
555 /**
556 * Loads the latest version of the specified column into the provided <code>ByteBuffer</code>.
557 * <p>
558 * Does not clear or flip the buffer.
559 *
560 * @param family family name
561 * @param foffset family offset
562 * @param flength family length
563 * @param qualifier column qualifier
564 * @param qoffset qualifier offset
565 * @param qlength qualifier length
566 * @param dst the buffer where to write the value
567 *
568 * @return <code>true</code> if a value was found, <code>false</code> otherwise
569 *
570 * @throws BufferOverflowException there is insufficient space remaining in the buffer
571 */
572 public boolean loadValue(byte [] family, int foffset, int flength,
573 byte [] qualifier, int qoffset, int qlength, ByteBuffer dst)
574 throws BufferOverflowException {
575 Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
576
577 if (kv == null) {
578 return false;
579 }
580 dst.put(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength());
581 return true;
582 }
583
584 /**
585 * Checks if the specified column contains a non-empty value (not a zero-length byte array).
586 *
587 * @param family family name
588 * @param qualifier column qualifier
589 *
590 * @return whether or not a latest value exists and is not empty
591 */
592 public boolean containsNonEmptyColumn(byte [] family, byte [] qualifier) {
593
594 return containsNonEmptyColumn(family, 0, family.length, qualifier, 0, qualifier.length);
595 }
596
597 /**
598 * Checks if the specified column contains a non-empty value (not a zero-length byte array).
599 *
600 * @param family family name
601 * @param foffset family offset
602 * @param flength family length
603 * @param qualifier column qualifier
604 * @param qoffset qualifier offset
605 * @param qlength qualifier length
606 *
607 * @return whether or not a latest value exists and is not empty
608 */
609 public boolean containsNonEmptyColumn(byte [] family, int foffset, int flength,
610 byte [] qualifier, int qoffset, int qlength) {
611
612 Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
613
614 return (kv != null) && (kv.getValueLength() > 0);
615 }
616
617 /**
618 * Checks if the specified column contains an empty value (a zero-length byte array).
619 *
620 * @param family family name
621 * @param qualifier column qualifier
622 *
623 * @return whether or not a latest value exists and is empty
624 */
625 public boolean containsEmptyColumn(byte [] family, byte [] qualifier) {
626
627 return containsEmptyColumn(family, 0, family.length, qualifier, 0, qualifier.length);
628 }
629
630 /**
631 * Checks if the specified column contains an empty value (a zero-length byte array).
632 *
633 * @param family family name
634 * @param foffset family offset
635 * @param flength family length
636 * @param qualifier column qualifier
637 * @param qoffset qualifier offset
638 * @param qlength qualifier length
639 *
640 * @return whether or not a latest value exists and is empty
641 */
642 public boolean containsEmptyColumn(byte [] family, int foffset, int flength,
643 byte [] qualifier, int qoffset, int qlength) {
644 Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
645
646 return (kv != null) && (kv.getValueLength() == 0);
647 }
648
649 /**
650 * Checks for existence of a value for the specified column (empty or not).
651 *
652 * @param family family name
653 * @param qualifier column qualifier
654 *
655 * @return true if at least one value exists in the result, false if not
656 */
657 public boolean containsColumn(byte [] family, byte [] qualifier) {
658 Cell kv = getColumnLatestCell(family, qualifier);
659 return kv != null;
660 }
661
662 /**
663 * Checks for existence of a value for the specified column (empty or not).
664 *
665 * @param family family name
666 * @param foffset family offset
667 * @param flength family length
668 * @param qualifier column qualifier
669 * @param qoffset qualifier offset
670 * @param qlength qualifier length
671 *
672 * @return true if at least one value exists in the result, false if not
673 */
674 public boolean containsColumn(byte [] family, int foffset, int flength,
675 byte [] qualifier, int qoffset, int qlength) {
676
677 return getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength) != null;
678 }
679
680 /**
681 * Map of families to all versions of its qualifiers and values.
682 * <p>
683 * Returns a three level Map of the form:
684 * <code>Map&family,Map<qualifier,Map<timestamp,value>>></code>
685 * <p>
686 * Note: All other map returning methods make use of this map internally.
687 * @return map from families to qualifiers to versions
688 */
689 public NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> getMap() {
690 if (this.familyMap != null) {
691 return this.familyMap;
692 }
693 if(isEmpty()) {
694 return null;
695 }
696 this.familyMap = new TreeMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>>(Bytes.BYTES_COMPARATOR);
697 for(Cell kv : this.cells) {
698 byte [] family = CellUtil.cloneFamily(kv);
699 NavigableMap<byte[], NavigableMap<Long, byte[]>> columnMap =
700 familyMap.get(family);
701 if(columnMap == null) {
702 columnMap = new TreeMap<byte[], NavigableMap<Long, byte[]>>
703 (Bytes.BYTES_COMPARATOR);
704 familyMap.put(family, columnMap);
705 }
706 byte [] qualifier = CellUtil.cloneQualifier(kv);
707 NavigableMap<Long, byte[]> versionMap = columnMap.get(qualifier);
708 if(versionMap == null) {
709 versionMap = new TreeMap<Long, byte[]>(new Comparator<Long>() {
710 @Override
711 public int compare(Long l1, Long l2) {
712 return l2.compareTo(l1);
713 }
714 });
715 columnMap.put(qualifier, versionMap);
716 }
717 Long timestamp = kv.getTimestamp();
718 byte [] value = CellUtil.cloneValue(kv);
719
720 versionMap.put(timestamp, value);
721 }
722 return this.familyMap;
723 }
724
725 /**
726 * Map of families to their most recent qualifiers and values.
727 * <p>
728 * Returns a two level Map of the form: <code>Map&family,Map<qualifier,value>></code>
729 * <p>
730 * The most recent version of each qualifier will be used.
731 * @return map from families to qualifiers and value
732 */
733 public NavigableMap<byte[], NavigableMap<byte[], byte[]>> getNoVersionMap() {
734 if(this.familyMap == null) {
735 getMap();
736 }
737 if(isEmpty()) {
738 return null;
739 }
740 NavigableMap<byte[], NavigableMap<byte[], byte[]>> returnMap =
741 new TreeMap<byte[], NavigableMap<byte[], byte[]>>(Bytes.BYTES_COMPARATOR);
742 for(Map.Entry<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>>
743 familyEntry : familyMap.entrySet()) {
744 NavigableMap<byte[], byte[]> qualifierMap =
745 new TreeMap<byte[], byte[]>(Bytes.BYTES_COMPARATOR);
746 for(Map.Entry<byte[], NavigableMap<Long, byte[]>> qualifierEntry :
747 familyEntry.getValue().entrySet()) {
748 byte [] value =
749 qualifierEntry.getValue().get(qualifierEntry.getValue().firstKey());
750 qualifierMap.put(qualifierEntry.getKey(), value);
751 }
752 returnMap.put(familyEntry.getKey(), qualifierMap);
753 }
754 return returnMap;
755 }
756
757 /**
758 * Map of qualifiers to values.
759 * <p>
760 * Returns a Map of the form: <code>Map<qualifier,value></code>
761 * @param family column family to get
762 * @return map of qualifiers to values
763 */
764 public NavigableMap<byte[], byte[]> getFamilyMap(byte [] family) {
765 if(this.familyMap == null) {
766 getMap();
767 }
768 if(isEmpty()) {
769 return null;
770 }
771 NavigableMap<byte[], byte[]> returnMap =
772 new TreeMap<byte[], byte[]>(Bytes.BYTES_COMPARATOR);
773 NavigableMap<byte[], NavigableMap<Long, byte[]>> qualifierMap =
774 familyMap.get(family);
775 if(qualifierMap == null) {
776 return returnMap;
777 }
778 for(Map.Entry<byte[], NavigableMap<Long, byte[]>> entry :
779 qualifierMap.entrySet()) {
780 byte [] value =
781 entry.getValue().get(entry.getValue().firstKey());
782 returnMap.put(entry.getKey(), value);
783 }
784 return returnMap;
785 }
786
787 /**
788 * Returns the value of the first column in the Result.
789 * @return value of the first column
790 */
791 public byte [] value() {
792 if (isEmpty()) {
793 return null;
794 }
795 return CellUtil.cloneValue(cells[0]);
796 }
797
798 /**
799 * Check if the underlying Cell [] is empty or not
800 * @return true if empty
801 */
802 public boolean isEmpty() {
803 return this.cells == null || this.cells.length == 0;
804 }
805
806 /**
807 * @return the size of the underlying Cell []
808 */
809 public int size() {
810 return this.cells == null? 0: this.cells.length;
811 }
812
813 /**
814 * @return String
815 */
816 @Override
817 public String toString() {
818 StringBuilder sb = new StringBuilder();
819 sb.append("keyvalues=");
820 if(isEmpty()) {
821 sb.append("NONE");
822 return sb.toString();
823 }
824 sb.append("{");
825 boolean moreThanOne = false;
826 for(Cell kv : this.cells) {
827 if(moreThanOne) {
828 sb.append(", ");
829 } else {
830 moreThanOne = true;
831 }
832 sb.append(kv.toString());
833 }
834 sb.append("}");
835 return sb.toString();
836 }
837
838 /**
839 * Does a deep comparison of two Results, down to the byte arrays.
840 * @param res1 first result to compare
841 * @param res2 second result to compare
842 * @throws Exception Every difference is throwing an exception
843 */
844 public static void compareResults(Result res1, Result res2)
845 throws Exception {
846 if (res2 == null) {
847 throw new Exception("There wasn't enough rows, we stopped at "
848 + Bytes.toStringBinary(res1.getRow()));
849 }
850 if (res1.size() != res2.size()) {
851 throw new Exception("This row doesn't have the same number of KVs: "
852 + res1.toString() + " compared to " + res2.toString());
853 }
854 Cell[] ourKVs = res1.rawCells();
855 Cell[] replicatedKVs = res2.rawCells();
856 for (int i = 0; i < res1.size(); i++) {
857 if (!ourKVs[i].equals(replicatedKVs[i]) ||
858 !CellUtil.matchingValue(ourKVs[i], replicatedKVs[i]) ||
859 !CellUtil.matchingTags(ourKVs[i], replicatedKVs[i])) {
860 throw new Exception("This result was different: "
861 + res1.toString() + " compared to " + res2.toString());
862 }
863 }
864 }
865
866 /**
867 * Forms a single result from the partial results in the partialResults list. This method is
868 * useful for reconstructing partial results on the client side.
869 * @param partialResults list of partial results
870 * @return The complete result that is formed by combining all of the partial results together
871 * @throws IOException A complete result cannot be formed because the results in the partial list
872 * come from different rows
873 * @deprecated
874 */
875 @Deprecated
876 public static Result createCompleteResult(List<Result> partialResults)
877 throws IOException {
878 return createCompleteResult((Iterable<Result>)partialResults);
879 }
880
881 /**
882 * Forms a single result from the partial results in the partialResults list. This method is
883 * useful for reconstructing partial results on the client side.
884 * @param partialResults iterable of partial results
885 * @return The complete result that is formed by combining all of the partial results together
886 * @throws IOException A complete result cannot be formed because the results in the partial list
887 * come from different rows
888 */
889 public static Result createCompleteResult(Iterable<Result> partialResults)
890 throws IOException {
891 if (partialResults == null) {
892 return Result.create(Collections.<Cell> emptyList(), null, false);
893 }
894 List<Cell> cells = new ArrayList<>();
895 boolean stale = false;
896 byte[] prevRow = null;
897 byte[] currentRow = null;
898 for (Iterator<Result> iter = partialResults.iterator(); iter.hasNext();) {
899 Result r = iter.next();
900 currentRow = r.getRow();
901 if (prevRow != null && !Bytes.equals(prevRow, currentRow)) {
902 throw new IOException(
903 "Cannot form complete result. Rows of partial results do not match." +
904 " Partial Results: " + partialResults);
905 }
906 // Ensure that all Results except the last one are marked as partials. The last result
907 // may not be marked as a partial because Results are only marked as partials when
908 // the scan on the server side must be stopped due to reaching the maxResultSize.
909 // Visualizing it makes it easier to understand:
910 // maxResultSize: 2 cells
911 // (-x-) represents cell number x in a row
912 // Example: row1: -1- -2- -3- -4- -5- (5 cells total)
913 // How row1 will be returned by the server as partial Results:
914 // Result1: -1- -2- (2 cells, size limit reached, mark as partial)
915 // Result2: -3- -4- (2 cells, size limit reached, mark as partial)
916 // Result3: -5- (1 cell, size limit NOT reached, NOT marked as partial)
917 if (iter.hasNext() && !r.mayHaveMoreCellsInRow()) {
918 throw new IOException("Cannot form complete result. Result is missing partial flag. " +
919 "Partial Results: " + partialResults);
920 }
921 prevRow = currentRow;
922 stale = stale || r.isStale();
923 for (Cell c : r.rawCells()) {
924 cells.add(c);
925 }
926 }
927
928 return Result.create(cells, null, stale);
929 }
930
931 /**
932 * Get total size of raw cells
933 * @param result
934 * @return Total size.
935 */
936 public static long getTotalSizeOfCells(Result result) {
937 long size = 0;
938 if (result.isEmpty()) {
939 return size;
940 }
941 for (Cell c : result.rawCells()) {
942 size += CellUtil.estimatedHeapSizeOf(c);
943 }
944 return size;
945 }
946
947 /**
948 * Copy another Result into this one. Needed for the old Mapred framework
949 * @throws UnsupportedOperationException if invoked on instance of EMPTY_RESULT
950 * (which is supposed to be immutable).
951 * @param other
952 */
953 public void copyFrom(Result other) {
954 checkReadonly();
955 this.row = null;
956 this.familyMap = null;
957 this.cells = other.cells;
958 }
959
960 @Override
961 public CellScanner cellScanner() {
962 // Reset
963 this.cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
964 return this;
965 }
966
967 @Override
968 public Cell current() {
969 if (isEmpty()
970 || cellScannerIndex == INITIAL_CELLSCANNER_INDEX
971 || cellScannerIndex >= cells.length)
972 return null;
973 return this.cells[cellScannerIndex];
974 }
975
976 @Override
977 public boolean advance() {
978 if (isEmpty()) {
979 return false;
980 }
981 cellScannerIndex++;
982 if (cellScannerIndex < this.cells.length) {
983 return true;
984 } else if (cellScannerIndex == this.cells.length) {
985 return false;
986 }
987 throw new NoSuchElementException("Cannot advance beyond the last cell");
988 }
989
990 public Boolean getExists() {
991 return exists;
992 }
993
994 public void setExists(Boolean exists) {
995 checkReadonly();
996 this.exists = exists;
997 }
998
999 /**
1000 * Whether or not the results are coming from possibly stale data. Stale results
1001 * might be returned if {@link Consistency} is not STRONG for the query.
1002 * @return Whether or not the results are coming from possibly stale data.
1003 */
1004 public boolean isStale() {
1005 return stale;
1006 }
1007
1008 /**
1009 * @deprecated the word 'partial' ambiguous, use {@link #mayHaveMoreCellsInRow()} instead.
1010 * Deprecated since 1.4.0.
1011 * @see #mayHaveMoreCellsInRow()
1012 */
1013 @Deprecated
1014 public boolean isPartial() {
1015 return mayHaveMoreCellsInRow;
1016 }
1017
1018 /**
1019 * For scanning large rows, the RS may choose to return the cells chunk by chunk to prevent OOM
1020 * or timeout. This flag is used to tell you if the current Result is the last one of the current
1021 * row. False means this Result is the last one. True means there MAY be more cells belonging to
1022 * the current row.
1023 * If you don't use {@link Scan#setAllowPartialResults(boolean)} or {@link Scan#setBatch(int)},
1024 * this method will always return false because the Result must contains all cells in one Row.
1025 */
1026 public boolean mayHaveMoreCellsInRow() {
1027 return mayHaveMoreCellsInRow;
1028 }
1029
1030 /**
1031 * Add load information about the region to the information about the result
1032 * @param loadStats statistics about the current region from which this was returned
1033 * @deprecated use {@link #setStatistics(ClientProtos.RegionLoadStats)} instead
1034 * @throws UnsupportedOperationException if invoked on instance of EMPTY_RESULT
1035 * (which is supposed to be immutable).
1036 */
1037 @InterfaceAudience.Private
1038 @Deprecated
1039 public void addResults(ClientProtos.RegionLoadStats loadStats) {
1040 checkReadonly();
1041 this.stats = loadStats;
1042 }
1043
1044 /**
1045 * Set load information about the region to the information about the result
1046 * @param loadStats statistics about the current region from which this was returned
1047 */
1048 @InterfaceAudience.Private
1049 @Deprecated
1050 public void setStatistics(ClientProtos.RegionLoadStats loadStats) {
1051 this.stats = loadStats;
1052 }
1053
1054 /**
1055 * @return the associated statistics about the region from which this was returned. Can be
1056 * <tt>null</tt> if stats are disabled.
1057 */
1058 @Deprecated
1059 public ClientProtos.RegionLoadStats getStats() {
1060 return stats;
1061 }
1062
1063 /**
1064 * All methods modifying state of Result object must call this method
1065 * to ensure that special purpose immutable Results can't be accidentally modified.
1066 */
1067 private void checkReadonly() {
1068 if (readonly == true) {
1069 throw new UnsupportedOperationException("Attempting to modify readonly EMPTY_RESULT!");
1070 }
1071 }
1072
1073 /**
1074 * Return true if this Result is a cursor to tell users where the server has scanned.
1075 * In this Result the only meaningful method is {@link #getCursor()}.
1076 *
1077 * {@code
1078 * while (r = scanner.next() && r != null) {
1079 * if(r.isCursor()){
1080 * // scanning is not end, it is a cursor, save its row key and close scanner if you want, or
1081 * // just continue the loop to call next().
1082 * } else {
1083 * // just like before
1084 * }
1085 * }
1086 * // scanning is end
1087 *
1088 * }
1089 * {@link Scan#setNeedCursorResult(boolean)}
1090 * {@link Cursor}
1091 * {@link #getCursor()}
1092 */
1093 public boolean isCursor() {
1094 return cursor != null ;
1095 }
1096
1097 /**
1098 * Return the cursor if this Result is a cursor result.
1099 * {@link Scan#setNeedCursorResult(boolean)}
1100 * {@link Cursor}
1101 * {@link #isCursor()}
1102 */
1103 public Cursor getCursor(){
1104 return cursor;
1105 }
1106 }