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