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