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