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