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