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