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