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    private static ThreadLocal<byte[]> localBuffer = new ThreadLocal<byte[]>();
87    private static final int PAD_WIDTH = 128;
88    public static final Result EMPTY_RESULT = new Result();
89  
90    private final static int INITIAL_CELLSCANNER_INDEX = -1;
91  
92    /**
93     * Index for where we are when Result is acting as a {@link CellScanner}.
94     */
95    private int cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
96  
97    /**
98     * Creates an empty Result w/ no KeyValue payload; returns null if you call {@link #rawCells()}.
99     * Use this to represent no results if <code>null</code> won't do or in old 'mapred' as oppposed to 'mapreduce' package
100    * MapReduce where you need to overwrite a Result
101    * instance with a {@link #copyFrom(Result)} call.
102    */
103   public Result() {
104     super();
105   }
106 
107   /**
108    * @deprecated Use {@link #create(List)} instead.
109    */
110   @Deprecated
111   public Result(KeyValue [] cells) {
112     this.cells = cells;
113   }
114 
115   /**
116    * @deprecated Use {@link #create(List)} instead.
117    */
118   @Deprecated
119   public Result(List<KeyValue> kvs) {
120     // TODO: Here we presume the passed in Cells are KVs.  One day this won't always be so.
121     this(kvs.toArray(new Cell[kvs.size()]), null);
122   }
123 
124   /**
125    * Instantiate a Result with the specified List of KeyValues.
126    * <br><strong>Note:</strong> You must ensure that the keyvalues are already sorted.
127    * @param cells List of cells
128    */
129   public static Result create(List<Cell> cells) {
130     return new Result(cells.toArray(new Cell[cells.size()]), null);
131   }
132 
133   public static Result create(List<Cell> cells, Boolean exists) {
134     if (exists != null){
135       return new Result(null, exists);
136     }
137     return new Result(cells.toArray(new Cell[cells.size()]), null);
138   }
139 
140   /**
141    * Instantiate a Result with the specified array of KeyValues.
142    * <br><strong>Note:</strong> You must ensure that the keyvalues are already sorted.
143    * @param cells array of cells
144    */
145   public static Result create(Cell[] cells) {
146     return new Result(cells, null);
147   }
148 
149   /** Private ctor. Use {@link #create(Cell[])}. */
150   private Result(Cell[] cells, Boolean exists) {
151     this.cells = cells;
152     this.exists = exists;
153   }
154 
155   /**
156    * Method for retrieving the row key that corresponds to
157    * the row from which this Result was created.
158    * @return row
159    */
160   public byte [] getRow() {
161     if (this.row == null) {
162       this.row = this.cells == null || this.cells.length == 0? null: CellUtil.cloneRow(this.cells[0]);
163     }
164     return this.row;
165   }
166 
167   /**
168    * Return the array of Cells backing this Result instance.
169    *
170    * The array is sorted from smallest -> largest using the
171    * {@link KeyValue#COMPARATOR}.
172    *
173    * The array only contains what your Get or Scan specifies and no more.
174    * For example if you request column "A" 1 version you will have at most 1
175    * Cell in the array. If you request column "A" with 2 version you will
176    * have at most 2 Cells, with the first one being the newer timestamp and
177    * the second being the older timestamp (this is the sort order defined by
178    * {@link KeyValue#COMPARATOR}).  If columns don't exist, they won't be
179    * present in the result. Therefore if you ask for 1 version all columns,
180    * it is safe to iterate over this array and expect to see 1 Cell for
181    * each column and no more.
182    *
183    * This API is faster than using getFamilyMap() and getMap()
184    *
185    * @return array of Cells; can be null if nothing in the result
186    */
187   public Cell[] rawCells() {
188     return cells;
189   }
190 
191   /**
192    * Return an cells of a Result as an array of KeyValues
193    *
194    * WARNING do not use, expensive.  This does an arraycopy of the cell[]'s value.
195    *
196    * Added to ease transition from  0.94 -> 0.96.
197    *
198    * @deprecated as of 0.96, use {@link #rawCells()}
199    * @return array of KeyValues, empty array if nothing in result.
200    */
201   @Deprecated
202   public KeyValue[] raw() {
203     KeyValue[] kvs = new KeyValue[cells.length];
204     for (int i = 0 ; i < kvs.length; i++) {
205       kvs[i] = KeyValueUtil.ensureKeyValue(cells[i]);
206     }
207     return kvs;
208   }
209 
210   /**
211    * Create a sorted list of the Cell's in this result.
212    *
213    * Since HBase 0.20.5 this is equivalent to raw().
214    *
215    * @return sorted List of Cells; can be null if no cells in the result
216    */
217   public List<Cell> listCells() {
218     return isEmpty()? null: Arrays.asList(rawCells());
219   }
220 
221   /**
222    * Return an cells of a Result as an array of KeyValues
223    *
224    * WARNING do not use, expensive.  This does  an arraycopy of the cell[]'s value.
225    *
226    * Added to ease transition from  0.94 -> 0.96.
227    *
228    * @deprecated as of 0.96, use {@link #listCells()}
229    * @return all sorted List of KeyValues; can be null if no cells in the result
230    */
231   @Deprecated
232   public List<KeyValue> list() {
233     return isEmpty() ? null : Arrays.asList(raw());
234   }
235 
236   /**
237    * @deprecated Use {@link #getColumnCells(byte[], byte[])} instead.
238    */
239   @Deprecated
240   public List<KeyValue> getColumn(byte [] family, byte [] qualifier) {
241     return KeyValueUtil.ensureKeyValues(getColumnCells(family, qualifier));
242   }
243 
244   /**
245    * Return the Cells for the specific column.  The Cells are sorted in
246    * the {@link KeyValue#COMPARATOR} order.  That implies the first entry in
247    * the list is the most recent column.  If the query (Scan or Get) only
248    * requested 1 version the list will contain at most 1 entry.  If the column
249    * did not exist in the result set (either the column does not exist
250    * or the column was not selected in the query) the list will be empty.
251    *
252    * Also see getColumnLatest which returns just a Cell
253    *
254    * @param family the family
255    * @param qualifier
256    * @return a list of Cells for this column or empty list if the column
257    * did not exist in the result set
258    */
259   public List<Cell> getColumnCells(byte [] family, byte [] qualifier) {
260     List<Cell> result = new ArrayList<Cell>();
261 
262     Cell [] kvs = rawCells();
263 
264     if (kvs == null || kvs.length == 0) {
265       return result;
266     }
267     int pos = binarySearch(kvs, family, qualifier);
268     if (pos == -1) {
269       return result; // cant find it
270     }
271 
272     for (int i = pos ; i < kvs.length ; i++ ) {
273       KeyValue kv = KeyValueUtil.ensureKeyValue(kvs[i]);
274       if (kv.matchingColumn(family,qualifier)) {
275         result.add(kv);
276       } else {
277         break;
278       }
279     }
280 
281     return result;
282   }
283 
284   protected int binarySearch(final Cell [] kvs,
285                              final byte [] family,
286                              final byte [] qualifier) {
287     Cell searchTerm =
288         KeyValue.createFirstOnRow(CellUtil.cloneRow(kvs[0]),
289             family, qualifier);
290 
291     // pos === ( -(insertion point) - 1)
292     int pos = Arrays.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
293     // never will exact match
294     if (pos < 0) {
295       pos = (pos+1) * -1;
296       // pos is now insertion point
297     }
298     if (pos == kvs.length) {
299       return -1; // doesn't exist
300     }
301     return pos;
302   }
303 
304   /**
305    * Searches for the latest value for the specified column.
306    *
307    * @param kvs the array to search
308    * @param family family name
309    * @param foffset family offset
310    * @param flength family length
311    * @param qualifier column qualifier
312    * @param qoffset qualifier offset
313    * @param qlength qualifier length
314    *
315    * @return the index where the value was found, or -1 otherwise
316    */
317   protected int binarySearch(final Cell [] kvs,
318       final byte [] family, final int foffset, final int flength,
319       final byte [] qualifier, final int qoffset, final int qlength) {
320 
321     double keyValueSize = (double)
322         KeyValue.getKeyValueDataStructureSize(kvs[0].getRowLength(), flength, qlength, 0);
323 
324     byte[] buffer = localBuffer.get();
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       localBuffer.set(buffer);
329     }
330 
331     Cell searchTerm = KeyValue.createFirstOnRow(buffer, 0,
332         kvs[0].getRowArray(), kvs[0].getRowOffset(), kvs[0].getRowLength(),
333         family, foffset, flength,
334         qualifier, qoffset, qlength);
335 
336     // pos === ( -(insertion point) - 1)
337     int pos = Arrays.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
338     // never will exact match
339     if (pos < 0) {
340       pos = (pos+1) * -1;
341       // pos is now insertion point
342     }
343     if (pos == kvs.length) {
344       return -1; // doesn't exist
345     }
346     return pos;
347   }
348 
349   /**
350    * @deprecated Use {@link #getColumnLatestCell(byte[], byte[])} instead.
351    */
352   @Deprecated
353   public KeyValue getColumnLatest(byte [] family, byte [] qualifier) {
354     return KeyValueUtil.ensureKeyValue(getColumnLatestCell(family, qualifier));
355   }
356 
357   /**
358    * The Cell for the most recent timestamp for a given column.
359    *
360    * @param family
361    * @param qualifier
362    *
363    * @return the Cell for the column, or null if no value exists in the row or none have been
364    * selected in the query (Get/Scan)
365    */
366   public Cell getColumnLatestCell(byte [] family, byte [] qualifier) {
367     Cell [] kvs = rawCells(); // side effect possibly.
368     if (kvs == null || kvs.length == 0) {
369       return null;
370     }
371     int pos = binarySearch(kvs, family, qualifier);
372     if (pos == -1) {
373       return null;
374     }
375     KeyValue kv = KeyValueUtil.ensureKeyValue(kvs[pos]);
376     if (kv.matchingColumn(family, qualifier)) {
377       return kv;
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     KeyValue kv = KeyValueUtil.ensureKeyValue(kvs[pos]);
417     if (kv.matchingColumn(family, foffset, flength, qualifier, qoffset, qlength)) {
418       return kv;
419     }
420     return null;
421   }
422 
423   /**
424    * Get the latest version of the specified column.
425    * @param family family name
426    * @param qualifier column qualifier
427    * @return value of latest version of column, null if none found
428    */
429   public byte[] getValue(byte [] family, byte [] qualifier) {
430     Cell kv = getColumnLatestCell(family, qualifier);
431     if (kv == null) {
432       return null;
433     }
434     return CellUtil.cloneValue(kv);
435   }
436 
437   /**
438    * Returns the value wrapped in a new <code>ByteBuffer</code>.
439    *
440    * @param family family name
441    * @param qualifier column qualifier
442    *
443    * @return the latest version of the column, or <code>null</code> if none found
444    */
445   public ByteBuffer getValueAsByteBuffer(byte [] family, byte [] qualifier) {
446 
447     Cell kv = getColumnLatestCell(family, 0, family.length, qualifier, 0, qualifier.length);
448 
449     if (kv == null) {
450       return null;
451     }
452     return ByteBuffer.wrap(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength());
453   }
454 
455   /**
456    * Returns the value wrapped in a new <code>ByteBuffer</code>.
457    *
458    * @param family family name
459    * @param foffset family offset
460    * @param flength family length
461    * @param qualifier column qualifier
462    * @param qoffset qualifier offset
463    * @param qlength qualifier length
464    *
465    * @return the latest version of the column, or <code>null</code> if none found
466    */
467   public ByteBuffer getValueAsByteBuffer(byte [] family, int foffset, int flength,
468       byte [] qualifier, int qoffset, int qlength) {
469 
470     Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
471 
472     if (kv == null) {
473       return null;
474     }
475     return ByteBuffer.wrap(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength());
476   }
477 
478   /**
479    * Loads the latest version of the specified column into the provided <code>ByteBuffer</code>.
480    * <p>
481    * Does not clear or flip the buffer.
482    *
483    * @param family family name
484    * @param qualifier column qualifier
485    * @param dst the buffer where to write the value
486    *
487    * @return <code>true</code> if a value was found, <code>false</code> otherwise
488    *
489    * @throws BufferOverflowException there is insufficient space remaining in the buffer
490    */
491   public boolean loadValue(byte [] family, byte [] qualifier, ByteBuffer dst)
492           throws BufferOverflowException {
493     return loadValue(family, 0, family.length, qualifier, 0, qualifier.length, dst);
494   }
495 
496   /**
497    * Loads the latest version of the specified column into the provided <code>ByteBuffer</code>.
498    * <p>
499    * Does not clear or flip the buffer.
500    *
501    * @param family family name
502    * @param foffset family offset
503    * @param flength family length
504    * @param qualifier column qualifier
505    * @param qoffset qualifier offset
506    * @param qlength qualifier length
507    * @param dst the buffer where to write the value
508    *
509    * @return <code>true</code> if a value was found, <code>false</code> otherwise
510    *
511    * @throws BufferOverflowException there is insufficient space remaining in the buffer
512    */
513   public boolean loadValue(byte [] family, int foffset, int flength,
514       byte [] qualifier, int qoffset, int qlength, ByteBuffer dst)
515           throws BufferOverflowException {
516     Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
517 
518     if (kv == null) {
519       return false;
520     }
521     dst.put(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength());
522     return true;
523   }
524 
525   /**
526    * Checks if the specified column contains a non-empty value (not a zero-length byte array).
527    *
528    * @param family family name
529    * @param qualifier column qualifier
530    *
531    * @return whether or not a latest value exists and is not empty
532    */
533   public boolean containsNonEmptyColumn(byte [] family, byte [] qualifier) {
534 
535     return containsNonEmptyColumn(family, 0, family.length, qualifier, 0, qualifier.length);
536   }
537 
538   /**
539    * Checks if the specified column contains a non-empty value (not a zero-length byte array).
540    *
541    * @param family family name
542    * @param foffset family offset
543    * @param flength family length
544    * @param qualifier column qualifier
545    * @param qoffset qualifier offset
546    * @param qlength qualifier length
547    *
548    * @return whether or not a latest value exists and is not empty
549    */
550   public boolean containsNonEmptyColumn(byte [] family, int foffset, int flength,
551       byte [] qualifier, int qoffset, int qlength) {
552 
553     Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
554 
555     return (kv != null) && (kv.getValueLength() > 0);
556   }
557 
558   /**
559    * Checks if the specified column contains an empty value (a zero-length byte array).
560    *
561    * @param family family name
562    * @param qualifier column qualifier
563    *
564    * @return whether or not a latest value exists and is empty
565    */
566   public boolean containsEmptyColumn(byte [] family, byte [] qualifier) {
567 
568     return containsEmptyColumn(family, 0, family.length, qualifier, 0, qualifier.length);
569   }
570 
571   /**
572    * Checks if the specified column contains an empty value (a zero-length byte array).
573    *
574    * @param family family name
575    * @param foffset family offset
576    * @param flength family length
577    * @param qualifier column qualifier
578    * @param qoffset qualifier offset
579    * @param qlength qualifier length
580    *
581    * @return whether or not a latest value exists and is empty
582    */
583   public boolean containsEmptyColumn(byte [] family, int foffset, int flength,
584       byte [] qualifier, int qoffset, int qlength) {
585     Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
586 
587     return (kv != null) && (kv.getValueLength() == 0);
588   }
589 
590   /**
591    * Checks for existence of a value for the specified column (empty or not).
592    *
593    * @param family family name
594    * @param qualifier column qualifier
595    *
596    * @return true if at least one value exists in the result, false if not
597    */
598   public boolean containsColumn(byte [] family, byte [] qualifier) {
599     Cell kv = getColumnLatestCell(family, qualifier);
600     return kv != null;
601   }
602 
603   /**
604    * Checks for existence of a value for the specified column (empty or not).
605    *
606    * @param family family name
607    * @param foffset family offset
608    * @param flength family length
609    * @param qualifier column qualifier
610    * @param qoffset qualifier offset
611    * @param qlength qualifier length
612    *
613    * @return true if at least one value exists in the result, false if not
614    */
615   public boolean containsColumn(byte [] family, int foffset, int flength,
616       byte [] qualifier, int qoffset, int qlength) {
617 
618     return getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength) != null;
619   }
620 
621   /**
622    * Map of families to all versions of its qualifiers and values.
623    * <p>
624    * Returns a three level Map of the form:
625    * <code>Map&amp;family,Map&lt;qualifier,Map&lt;timestamp,value>>></code>
626    * <p>
627    * Note: All other map returning methods make use of this map internally.
628    * @return map from families to qualifiers to versions
629    */
630   public NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> getMap() {
631     if (this.familyMap != null) {
632       return this.familyMap;
633     }
634     if(isEmpty()) {
635       return null;
636     }
637     this.familyMap = new TreeMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>>(Bytes.BYTES_COMPARATOR);
638     for(Cell kv : this.cells) {
639       byte [] family = CellUtil.cloneFamily(kv);
640       NavigableMap<byte[], NavigableMap<Long, byte[]>> columnMap =
641         familyMap.get(family);
642       if(columnMap == null) {
643         columnMap = new TreeMap<byte[], NavigableMap<Long, byte[]>>
644           (Bytes.BYTES_COMPARATOR);
645         familyMap.put(family, columnMap);
646       }
647       byte [] qualifier = CellUtil.cloneQualifier(kv);
648       NavigableMap<Long, byte[]> versionMap = columnMap.get(qualifier);
649       if(versionMap == null) {
650         versionMap = new TreeMap<Long, byte[]>(new Comparator<Long>() {
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    * Copy another Result into this one. Needed for the old Mapred framework
807    * @param other
808    */
809   public void copyFrom(Result other) {
810     this.row = null;
811     this.familyMap = null;
812     this.cells = other.cells;
813   }
814 
815   @Override
816   public CellScanner cellScanner() {
817     // Reset
818     this.cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
819     return this;
820   }
821 
822   @Override
823   public Cell current() {
824     if (cells == null) return null;
825     return (cellScannerIndex < 0)? null: this.cells[cellScannerIndex];
826   }
827 
828   @Override
829   public boolean advance() {
830     if (cells == null) return false;
831     return ++cellScannerIndex < this.cells.length;
832   }
833 
834   public Boolean getExists() {
835     return exists;
836   }
837 
838   public void setExists(Boolean exists) {
839     this.exists = exists;
840   }
841 
842 }