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.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 Cell} objects, each representing
62   * an HBase cell defined by the row, family, qualifier, timestamp, and value.<p>
63   *
64   * The underlying {@link Cell} objects can be accessed through the method {@link #listCells()}.
65   * This will create a List from the internal Cell []. Better is to exploit the fact that
66   * a new Result instance is a primed {@link CellScanner}; just call {@link #advance()} and
67   * {@link #current()} to iterate over Cells as you would any {@link CellScanner}.
68   * Call {@link #cellScanner()} to reset should you need to iterate the same Result over again
69   * ({@link CellScanner}s are one-shot).
70   *
71   * If you need to overwrite a Result with another Result instance -- as in the old 'mapred'
72   * RecordReader next invocations -- then create an empty Result with the null constructor and
73   * in then use {@link #copyFrom(Result)}
74   */
75  @InterfaceAudience.Public
76  @InterfaceStability.Stable
77  public class Result implements CellScannable, CellScanner {
78    private Cell[] cells;
79    private Boolean exists; // if the query was just to check existence.
80    // We're not using java serialization.  Transient here is just a marker to say
81    // that this is where we cache row if we're ever asked for it.
82    private transient byte [] row = null;
83    // Ditto for familyMap.  It can be composed on fly from passed in kvs.
84    private transient NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> familyMap = null;
85  
86    // never use directly
87    private static byte [] buffer = null;
88    private static final int PAD_WIDTH = 128;
89    public static final Result EMPTY_RESULT = new Result();
90  
91    private final static int INITIAL_CELLSCANNER_INDEX = -1;
92  
93    /**
94     * Index for where we are when Result is acting as a {@link CellScanner}.
95     */
96    private int cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
97  
98    /**
99     * Creates an empty Result w/ no KeyValue payload; returns null if you call {@link #rawCells()}.
100    * Use this to represent no results if <code>null</code> won't do or in old 'mapred' as oppposed to 'mapreduce' package
101    * MapReduce where you need to overwrite a Result
102    * instance with a {@link #copyFrom(Result)} call.
103    */
104   public Result() {
105     super();
106   }
107 
108   /**
109    * @deprecated Use {@link #create(List)} instead.
110    */
111   @Deprecated
112   public Result(KeyValue [] cells) {
113     this.cells = cells;
114   }
115 
116   /**
117    * @deprecated Use {@link #create(List)} instead.
118    */
119   @Deprecated
120   public Result(List<KeyValue> kvs) {
121     // TODO: Here we presume the passed in Cells are KVs.  One day this won't always be so.
122     this(kvs.toArray(new Cell[kvs.size()]), null);
123   }
124 
125   /**
126    * Instantiate a Result with the specified List of KeyValues.
127    * <br><strong>Note:</strong> You must ensure that the keyvalues are already sorted.
128    * @param cells List of cells
129    */
130   public static Result create(List<Cell> cells) {
131     return new Result(cells.toArray(new Cell[cells.size()]), null);
132   }
133 
134   public static Result create(List<Cell> cells, Boolean exists) {
135     if (exists != null){
136       return new Result(null, exists);
137     }
138     return new Result(cells.toArray(new Cell[cells.size()]), null);
139   }
140 
141   /**
142    * Instantiate a Result with the specified array of KeyValues.
143    * <br><strong>Note:</strong> You must ensure that the keyvalues are already sorted.
144    * @param cells array of cells
145    */
146   public static Result create(Cell[] cells) {
147     return new Result(cells, null);
148   }
149 
150   /** Private ctor. Use {@link #create(Cell[])}. */
151   private Result(Cell[] cells, Boolean exists) {
152     this.cells = cells;
153     this.exists = exists;
154   }
155 
156   /**
157    * Method for retrieving the row key that corresponds to
158    * the row from which this Result was created.
159    * @return row
160    */
161   public byte [] getRow() {
162     if (this.row == null) {
163       this.row = this.cells == null || this.cells.length == 0? null: CellUtil.cloneRow(this.cells[0]);
164     }
165     return this.row;
166   }
167 
168   /**
169    * Return the array of Cells backing this Result instance.
170    *
171    * The array is sorted from smallest -> largest using the
172    * {@link KeyValue#COMPARATOR}.
173    *
174    * The array only contains what your Get or Scan specifies and no more.
175    * For example if you request column "A" 1 version you will have at most 1
176    * Cell in the array. If you request column "A" with 2 version you will
177    * have at most 2 Cells, with the first one being the newer timestamp and
178    * the second being the older timestamp (this is the sort order defined by
179    * {@link KeyValue#COMPARATOR}).  If columns don't exist, they won't be
180    * present in the result. Therefore if you ask for 1 version all columns,
181    * it is safe to iterate over this array and expect to see 1 Cell for
182    * each column and no more.
183    *
184    * This API is faster than using getFamilyMap() and getMap()
185    *
186    * @return array of Cells; can be null if nothing in the result
187    */
188   public Cell[] rawCells() {
189     return cells;
190   }
191 
192   /**
193    * Return an cells of a Result as an array of KeyValues
194    *
195    * WARNING do not use, expensive.  This does an arraycopy of the cell[]'s value.
196    *
197    * Added to ease transition from  0.94 -> 0.96.
198    *
199    * @deprecated as of 0.96, use {@link #rawCells()}
200    * @return array of KeyValues, empty array if nothing in result.
201    */
202   @Deprecated
203   public KeyValue[] raw() {
204     KeyValue[] kvs = new KeyValue[cells.length];
205     for (int i = 0 ; i < kvs.length; i++) {
206       kvs[i] = KeyValueUtil.ensureKeyValue(cells[i]);
207     }
208     return kvs;
209   }
210 
211   /**
212    * Create a sorted list of the Cell's in this result.
213    *
214    * Since HBase 0.20.5 this is equivalent to raw().
215    *
216    * @return sorted List of Cells; can be null if no cells in the result
217    */
218   public List<Cell> listCells() {
219     return isEmpty()? null: Arrays.asList(rawCells());
220   }
221 
222   /**
223    * Return an cells of a Result as an array of KeyValues
224    *
225    * WARNING do not use, expensive.  This does  an arraycopy of the cell[]'s value.
226    *
227    * Added to ease transition from  0.94 -> 0.96.
228    *
229    * @deprecated as of 0.96, use {@link #listCells()}
230    * @return all sorted List of KeyValues; can be null if no cells in the result
231    */
232   @Deprecated
233   public List<KeyValue> list() {
234     return isEmpty() ? null : Arrays.asList(raw());
235   }
236 
237   /**
238    * @deprecated Use {@link #getColumnCells(byte[], byte[])} instead.
239    */
240   @Deprecated
241   public List<KeyValue> getColumn(byte [] family, byte [] qualifier) {
242     return KeyValueUtil.ensureKeyValues(getColumnCells(family, qualifier));
243   }
244 
245   /**
246    * Return the Cells for the specific column.  The Cells are sorted in
247    * the {@link KeyValue#COMPARATOR} order.  That implies the first entry in
248    * the list is the most recent column.  If the query (Scan or Get) only
249    * requested 1 version the list will contain at most 1 entry.  If the column
250    * did not exist in the result set (either the column does not exist
251    * or the column was not selected in the query) the list will be empty.
252    *
253    * Also see getColumnLatest which returns just a Cell
254    *
255    * @param family the family
256    * @param qualifier
257    * @return a list of Cells for this column or empty list if the column
258    * did not exist in the result set
259    */
260   public List<Cell> getColumnCells(byte [] family, byte [] qualifier) {
261     List<Cell> result = new ArrayList<Cell>();
262 
263     Cell [] kvs = rawCells();
264 
265     if (kvs == null || kvs.length == 0) {
266       return result;
267     }
268     int pos = binarySearch(kvs, family, qualifier);
269     if (pos == -1) {
270       return result; // cant find it
271     }
272 
273     for (int i = pos ; i < kvs.length ; i++ ) {
274       KeyValue kv = KeyValueUtil.ensureKeyValue(kvs[i]);
275       if (kv.matchingColumn(family,qualifier)) {
276         result.add(kv);
277       } else {
278         break;
279       }
280     }
281 
282     return result;
283   }
284 
285   protected int binarySearch(final Cell [] kvs,
286                              final byte [] family,
287                              final byte [] qualifier) {
288     Cell searchTerm =
289         KeyValue.createFirstOnRow(CellUtil.cloneRow(kvs[0]),
290             family, qualifier);
291 
292     // pos === ( -(insertion point) - 1)
293     int pos = Arrays.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
294     // never will exact match
295     if (pos < 0) {
296       pos = (pos+1) * -1;
297       // pos is now insertion point
298     }
299     if (pos == kvs.length) {
300       return -1; // doesn't exist
301     }
302     return pos;
303   }
304 
305   /**
306    * Searches for the latest value for the specified column.
307    *
308    * @param kvs the array to search
309    * @param family family name
310    * @param foffset family offset
311    * @param flength family length
312    * @param qualifier column qualifier
313    * @param qoffset qualifier offset
314    * @param qlength qualifier length
315    *
316    * @return the index where the value was found, or -1 otherwise
317    */
318   protected int binarySearch(final Cell [] kvs,
319       final byte [] family, final int foffset, final int flength,
320       final byte [] qualifier, final int qoffset, final int qlength) {
321 
322     double keyValueSize = (double)
323         KeyValue.getKeyValueDataStructureSize(kvs[0].getRowLength(), flength, qlength, 0);
324 
325     if (buffer == null || keyValueSize > buffer.length) {
326       // pad to the smallest multiple of the pad width
327       buffer = new byte[(int) Math.ceil(keyValueSize / PAD_WIDTH) * PAD_WIDTH];
328     }
329 
330     Cell searchTerm = KeyValue.createFirstOnRow(buffer, 0,
331         kvs[0].getRowArray(), kvs[0].getRowOffset(), kvs[0].getRowLength(),
332         family, foffset, flength,
333         qualifier, qoffset, qlength);
334 
335     // pos === ( -(insertion point) - 1)
336     int pos = Arrays.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
337     // never will exact match
338     if (pos < 0) {
339       pos = (pos+1) * -1;
340       // pos is now insertion point
341     }
342     if (pos == kvs.length) {
343       return -1; // doesn't exist
344     }
345     return pos;
346   }
347 
348   /**
349    * @deprecated Use {@link #getColumnLatestCell(byte[], byte[])} instead.
350    */
351   @Deprecated
352   public KeyValue getColumnLatest(byte [] family, byte [] qualifier) {
353     return KeyValueUtil.ensureKeyValue(getColumnLatestCell(family, qualifier));
354   }
355 
356   /**
357    * The Cell for the most recent timestamp for a given column.
358    *
359    * @param family
360    * @param qualifier
361    *
362    * @return the Cell for the column, or null if no value exists in the row or none have been
363    * selected in the query (Get/Scan)
364    */
365   public Cell getColumnLatestCell(byte [] family, byte [] qualifier) {
366     Cell [] kvs = rawCells(); // side effect possibly.
367     if (kvs == null || kvs.length == 0) {
368       return null;
369     }
370     int pos = binarySearch(kvs, family, qualifier);
371     if (pos == -1) {
372       return null;
373     }
374     KeyValue kv = KeyValueUtil.ensureKeyValue(kvs[pos]);
375     if (kv.matchingColumn(family, qualifier)) {
376       return kv;
377     }
378     return null;
379   }
380 
381   /**
382    * @deprecated Use {@link #getColumnLatestCell(byte[], int, int, byte[], int, int)} instead.
383    */
384   @Deprecated
385   public KeyValue getColumnLatest(byte [] family, int foffset, int flength,
386       byte [] qualifier, int qoffset, int qlength) {
387     return KeyValueUtil.ensureKeyValue(
388         getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength));
389   }
390 
391   /**
392    * The Cell for the most recent timestamp for a given column.
393    *
394    * @param family family name
395    * @param foffset family offset
396    * @param flength family length
397    * @param qualifier column qualifier
398    * @param qoffset qualifier offset
399    * @param qlength qualifier length
400    *
401    * @return the Cell for the column, or null if no value exists in the row or none have been
402    * selected in the query (Get/Scan)
403    */
404   public Cell getColumnLatestCell(byte [] family, int foffset, int flength,
405       byte [] qualifier, int qoffset, int qlength) {
406 
407     Cell [] kvs = rawCells(); // side effect possibly.
408     if (kvs == null || kvs.length == 0) {
409       return null;
410     }
411     int pos = binarySearch(kvs, family, foffset, flength, qualifier, qoffset, qlength);
412     if (pos == -1) {
413       return null;
414     }
415     KeyValue kv = KeyValueUtil.ensureKeyValue(kvs[pos]);
416     if (kv.matchingColumn(family, foffset, flength, qualifier, qoffset, qlength)) {
417       return kv;
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           public int compare(Long l1, Long l2) {
651             return l2.compareTo(l1);
652           }
653         });
654         columnMap.put(qualifier, versionMap);
655       }
656       Long timestamp = kv.getTimestamp();
657       byte [] value = CellUtil.cloneValue(kv);
658 
659       versionMap.put(timestamp, value);
660     }
661     return this.familyMap;
662   }
663 
664   /**
665    * Map of families to their most recent qualifiers and values.
666    * <p>
667    * Returns a two level Map of the form: <code>Map&amp;family,Map&lt;qualifier,value>></code>
668    * <p>
669    * The most recent version of each qualifier will be used.
670    * @return map from families to qualifiers and value
671    */
672   public NavigableMap<byte[], NavigableMap<byte[], byte[]>> getNoVersionMap() {
673     if(this.familyMap == null) {
674       getMap();
675     }
676     if(isEmpty()) {
677       return null;
678     }
679     NavigableMap<byte[], NavigableMap<byte[], byte[]>> returnMap =
680       new TreeMap<byte[], NavigableMap<byte[], byte[]>>(Bytes.BYTES_COMPARATOR);
681     for(Map.Entry<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>>
682       familyEntry : familyMap.entrySet()) {
683       NavigableMap<byte[], byte[]> qualifierMap =
684         new TreeMap<byte[], byte[]>(Bytes.BYTES_COMPARATOR);
685       for(Map.Entry<byte[], NavigableMap<Long, byte[]>> qualifierEntry :
686         familyEntry.getValue().entrySet()) {
687         byte [] value =
688           qualifierEntry.getValue().get(qualifierEntry.getValue().firstKey());
689         qualifierMap.put(qualifierEntry.getKey(), value);
690       }
691       returnMap.put(familyEntry.getKey(), qualifierMap);
692     }
693     return returnMap;
694   }
695 
696   /**
697    * Map of qualifiers to values.
698    * <p>
699    * Returns a Map of the form: <code>Map&lt;qualifier,value></code>
700    * @param family column family to get
701    * @return map of qualifiers to values
702    */
703   public NavigableMap<byte[], byte[]> getFamilyMap(byte [] family) {
704     if(this.familyMap == null) {
705       getMap();
706     }
707     if(isEmpty()) {
708       return null;
709     }
710     NavigableMap<byte[], byte[]> returnMap =
711       new TreeMap<byte[], byte[]>(Bytes.BYTES_COMPARATOR);
712     NavigableMap<byte[], NavigableMap<Long, byte[]>> qualifierMap =
713       familyMap.get(family);
714     if(qualifierMap == null) {
715       return returnMap;
716     }
717     for(Map.Entry<byte[], NavigableMap<Long, byte[]>> entry :
718       qualifierMap.entrySet()) {
719       byte [] value =
720         entry.getValue().get(entry.getValue().firstKey());
721       returnMap.put(entry.getKey(), value);
722     }
723     return returnMap;
724   }
725 
726   /**
727    * Returns the value of the first column in the Result.
728    * @return value of the first column
729    */
730   public byte [] value() {
731     if (isEmpty()) {
732       return null;
733     }
734     return CellUtil.cloneValue(cells[0]);
735   }
736 
737   /**
738    * Check if the underlying Cell [] is empty or not
739    * @return true if empty
740    */
741   public boolean isEmpty() {
742     return this.cells == null || this.cells.length == 0;
743   }
744 
745   /**
746    * @return the size of the underlying Cell []
747    */
748   public int size() {
749     return this.cells == null? 0: this.cells.length;
750   }
751 
752   /**
753    * @return String
754    */
755   @Override
756   public String toString() {
757     StringBuilder sb = new StringBuilder();
758     sb.append("keyvalues=");
759     if(isEmpty()) {
760       sb.append("NONE");
761       return sb.toString();
762     }
763     sb.append("{");
764     boolean moreThanOne = false;
765     for(Cell kv : this.cells) {
766       if(moreThanOne) {
767         sb.append(", ");
768       } else {
769         moreThanOne = true;
770       }
771       sb.append(kv.toString());
772     }
773     sb.append("}");
774     return sb.toString();
775   }
776 
777   /**
778    * Does a deep comparison of two Results, down to the byte arrays.
779    * @param res1 first result to compare
780    * @param res2 second result to compare
781    * @throws Exception Every difference is throwing an exception
782    */
783   public static void compareResults(Result res1, Result res2)
784       throws Exception {
785     if (res2 == null) {
786       throw new Exception("There wasn't enough rows, we stopped at "
787           + Bytes.toStringBinary(res1.getRow()));
788     }
789     if (res1.size() != res2.size()) {
790       throw new Exception("This row doesn't have the same number of KVs: "
791           + res1.toString() + " compared to " + res2.toString());
792     }
793     Cell[] ourKVs = res1.rawCells();
794     Cell[] replicatedKVs = res2.rawCells();
795     for (int i = 0; i < res1.size(); i++) {
796       if (!ourKVs[i].equals(replicatedKVs[i]) ||
797           !Bytes.equals(CellUtil.cloneValue(ourKVs[i]), CellUtil.cloneValue(replicatedKVs[i]))) {
798         throw new Exception("This result was different: "
799             + res1.toString() + " compared to " + res2.toString());
800       }
801     }
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     // Reset
817     this.cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
818     return this;
819   }
820 
821   @Override
822   public Cell current() {
823     if (cells == null) return null;
824     return (cellScannerIndex < 0)? null: this.cells[cellScannerIndex];
825   }
826 
827   @Override
828   public boolean advance() {
829     if (cells == null) return false;
830     return ++cellScannerIndex < this.cells.length;
831   }
832 
833   public Boolean getExists() {
834     return exists;
835   }
836 
837   public void setExists(Boolean exists) {
838     this.exists = exists;
839   }
840 
841 }