View Javadoc

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