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