001/*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020package org.apache.hadoop.hbase.client;
021
022import java.io.IOException;
023import java.nio.BufferOverflowException;
024import java.nio.ByteBuffer;
025import java.util.ArrayList;
026import java.util.Arrays;
027import java.util.Collections;
028import java.util.Comparator;
029import java.util.Iterator;
030import java.util.List;
031import java.util.Map;
032import java.util.NavigableMap;
033import java.util.NoSuchElementException;
034import java.util.TreeMap;
035
036import org.apache.hadoop.hbase.Cell;
037import org.apache.hadoop.hbase.CellComparator;
038import org.apache.hadoop.hbase.CellScannable;
039import org.apache.hadoop.hbase.CellScanner;
040import org.apache.hadoop.hbase.CellUtil;
041import org.apache.hadoop.hbase.HConstants;
042import org.apache.hadoop.hbase.PrivateCellUtil;
043import org.apache.hadoop.hbase.KeyValue;
044import org.apache.hadoop.hbase.KeyValueUtil;
045import org.apache.yetus.audience.InterfaceAudience;
046import org.apache.hadoop.hbase.util.Bytes;
047
048/**
049 * Single row result of a {@link Get} or {@link Scan} query.<p>
050 *
051 * This class is <b>NOT THREAD SAFE</b>.<p>
052 *
053 * Convenience methods are available that return various {@link Map}
054 * structures and values directly.<p>
055 *
056 * To get a complete mapping of all cells in the Result, which can include
057 * multiple families and multiple versions, use {@link #getMap()}.<p>
058 *
059 * To get a mapping of each family to its columns (qualifiers and values),
060 * including only the latest version of each, use {@link #getNoVersionMap()}.
061 *
062 * To get a mapping of qualifiers to latest values for an individual family use
063 * {@link #getFamilyMap(byte[])}.<p>
064 *
065 * To get the latest value for a specific family and qualifier use
066 * {@link #getValue(byte[], byte[])}.
067 *
068 * A Result is backed by an array of {@link Cell} objects, each representing
069 * an HBase cell defined by the row, family, qualifier, timestamp, and value.<p>
070 *
071 * The underlying {@link Cell} objects can be accessed through the method {@link #listCells()}.
072 * This will create a List from the internal Cell []. Better is to exploit the fact that
073 * a new Result instance is a primed {@link CellScanner}; just call {@link #advance()} and
074 * {@link #current()} to iterate over Cells as you would any {@link CellScanner}.
075 * Call {@link #cellScanner()} to reset should you need to iterate the same Result over again
076 * ({@link CellScanner}s are one-shot).
077 *
078 * If you need to overwrite a Result with another Result instance -- as in the old 'mapred'
079 * RecordReader next invocations -- then create an empty Result with the null constructor and
080 * in then use {@link #copyFrom(Result)}
081 */
082@InterfaceAudience.Public
083public class Result implements CellScannable, CellScanner {
084  private Cell[] cells;
085  private Boolean exists; // if the query was just to check existence.
086  private boolean stale = false;
087
088  /**
089   * See {@link #mayHaveMoreCellsInRow()}.
090   */
091  private boolean mayHaveMoreCellsInRow = false;
092  // We're not using java serialization.  Transient here is just a marker to say
093  // that this is where we cache row if we're ever asked for it.
094  private transient byte [] row = null;
095  // Ditto for familyMap.  It can be composed on fly from passed in kvs.
096  private transient NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>>
097      familyMap = null;
098
099  private static ThreadLocal<byte[]> localBuffer = new ThreadLocal<>();
100  private static final int PAD_WIDTH = 128;
101  public static final Result EMPTY_RESULT = new Result(true);
102
103  private final static int INITIAL_CELLSCANNER_INDEX = -1;
104
105  /**
106   * Index for where we are when Result is acting as a {@link CellScanner}.
107   */
108  private int cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
109  private RegionLoadStats stats;
110
111  private final boolean readonly;
112
113  private Cursor cursor = null;
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    this(false);
123  }
124
125  /**
126   * Allows to construct special purpose immutable Result objects,
127   * such as EMPTY_RESULT.
128   * @param readonly whether this Result instance is readonly
129   */
130  private Result(boolean readonly) {
131    this.readonly = readonly;
132  }
133
134  /**
135   * Instantiate a Result with the specified List of KeyValues.
136   * <br><strong>Note:</strong> You must ensure that the keyvalues are already sorted.
137   * @param cells List of cells
138   */
139  public static Result create(List<Cell> cells) {
140    return create(cells, null);
141  }
142
143  public static Result create(List<Cell> cells, Boolean exists) {
144    return create(cells, exists, false);
145  }
146
147  public static Result create(List<Cell> cells, Boolean exists, boolean stale) {
148    return create(cells, exists, stale, false);
149  }
150
151  public static Result create(List<Cell> cells, Boolean exists, boolean stale,
152      boolean mayHaveMoreCellsInRow) {
153    if (exists != null){
154      return new Result(null, exists, stale, mayHaveMoreCellsInRow);
155    }
156    return new Result(cells.toArray(new Cell[cells.size()]), null, stale, mayHaveMoreCellsInRow);
157  }
158
159  /**
160   * Instantiate a Result with the specified array of KeyValues.
161   * <br><strong>Note:</strong> You must ensure that the keyvalues are already sorted.
162   * @param cells array of cells
163   */
164  public static Result create(Cell[] cells) {
165    return create(cells, null, false);
166  }
167
168  public static Result create(Cell[] cells, Boolean exists, boolean stale) {
169    return create(cells, exists, stale, false);
170  }
171
172  public static Result create(Cell[] cells, Boolean exists, boolean stale,
173      boolean mayHaveMoreCellsInRow) {
174    if (exists != null) {
175      return new Result(null, exists, stale, mayHaveMoreCellsInRow);
176    }
177    return new Result(cells, null, stale, mayHaveMoreCellsInRow);
178  }
179
180  public static Result createCursorResult(Cursor cursor) {
181    return new Result(cursor);
182  }
183
184  private Result(Cursor cursor) {
185    this.cursor = cursor;
186    this.readonly = false;
187  }
188
189  /** Private ctor. Use {@link #create(Cell[])}. */
190  private Result(Cell[] cells, Boolean exists, boolean stale, boolean mayHaveMoreCellsInRow) {
191    this.cells = cells;
192    this.exists = exists;
193    this.stale = stale;
194    this.mayHaveMoreCellsInRow = mayHaveMoreCellsInRow;
195    this.readonly = false;
196  }
197
198  /**
199   * Method for retrieving the row key that corresponds to
200   * the row from which this Result was created.
201   * @return row
202   */
203  public byte [] getRow() {
204    if (this.row == null) {
205      this.row = (this.cells == null || this.cells.length == 0) ?
206          null :
207          CellUtil.cloneRow(this.cells[0]);
208    }
209    return this.row;
210  }
211
212  /**
213   * Return the array of Cells backing this Result instance.
214   *
215   * The array is sorted from smallest -&gt; largest using the
216   * {@link CellComparator}.
217   *
218   * The array only contains what your Get or Scan specifies and no more.
219   * For example if you request column "A" 1 version you will have at most 1
220   * Cell in the array. If you request column "A" with 2 version you will
221   * have at most 2 Cells, with the first one being the newer timestamp and
222   * the second being the older timestamp (this is the sort order defined by
223   * {@link CellComparator}).  If columns don't exist, they won't be
224   * present in the result. Therefore if you ask for 1 version all columns,
225   * it is safe to iterate over this array and expect to see 1 Cell for
226   * each column and no more.
227   *
228   * This API is faster than using getFamilyMap() and getMap()
229   *
230   * @return array of Cells; can be null if nothing in the result
231   */
232  public Cell[] rawCells() {
233    return cells;
234  }
235
236  /**
237   * Create a sorted list of the Cell's in this result.
238   *
239   * Since HBase 0.20.5 this is equivalent to raw().
240   *
241   * @return sorted List of Cells; can be null if no cells in the result
242   */
243  public List<Cell> listCells() {
244    return isEmpty()? null: Arrays.asList(rawCells());
245  }
246
247  /**
248   * Return the Cells for the specific column.  The Cells are sorted in
249   * the {@link CellComparator} order.  That implies the first entry in
250   * the list is the most recent column.  If the query (Scan or Get) only
251   * requested 1 version the list will contain at most 1 entry.  If the column
252   * did not exist in the result set (either the column does not exist
253   * or the column was not selected in the query) the list will be empty.
254   *
255   * Also see getColumnLatest which returns just a Cell
256   *
257   * @param family the family
258   * @param qualifier
259   * @return a list of Cells for this column or empty list if the column
260   * did not exist in the result set
261   */
262  public List<Cell> getColumnCells(byte [] family, byte [] qualifier) {
263    List<Cell> result = new ArrayList<>();
264
265    Cell [] kvs = rawCells();
266
267    if (kvs == null || kvs.length == 0) {
268      return result;
269    }
270    int pos = binarySearch(kvs, family, qualifier);
271    if (pos == -1) {
272      return result; // cant find it
273    }
274
275    for (int i = pos; i < kvs.length; i++) {
276      if (CellUtil.matchingColumn(kvs[i], family,qualifier)) {
277        result.add(kvs[i]);
278      } else {
279        break;
280      }
281    }
282
283    return result;
284  }
285
286  private byte[] notNullBytes(final byte[] bytes) {
287    if (bytes == null) {
288      return HConstants.EMPTY_BYTE_ARRAY;
289    } else {
290      return bytes;
291    }
292  }
293
294  protected int binarySearch(final Cell [] kvs,
295                             final byte [] family,
296                             final byte [] qualifier) {
297    byte[] familyNotNull = notNullBytes(family);
298    byte[] qualifierNotNull = notNullBytes(qualifier);
299    Cell searchTerm =
300        PrivateCellUtil.createFirstOnRow(kvs[0].getRowArray(),
301            kvs[0].getRowOffset(), kvs[0].getRowLength(),
302            familyNotNull, 0, (byte)familyNotNull.length,
303            qualifierNotNull, 0, qualifierNotNull.length);
304
305    // pos === ( -(insertion point) - 1)
306    int pos = Arrays.binarySearch(kvs, searchTerm, CellComparator.getInstance());
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 = KeyValueUtil.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, CellComparator.getInstance());
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   * The Cell for the most recent timestamp for a given column.
365   *
366   * @param family
367   * @param qualifier
368   *
369   * @return the Cell for the column, or null if no value exists in the row or none have been
370   * selected in the query (Get/Scan)
371   */
372  public Cell getColumnLatestCell(byte [] family, byte [] qualifier) {
373    Cell [] kvs = rawCells(); // side effect possibly.
374    if (kvs == null || kvs.length == 0) {
375      return null;
376    }
377    int pos = binarySearch(kvs, family, qualifier);
378    if (pos == -1) {
379      return null;
380    }
381    if (CellUtil.matchingColumn(kvs[pos], family, qualifier)) {
382      return kvs[pos];
383    }
384    return null;
385  }
386
387  /**
388   * The Cell for the most recent timestamp for a given column.
389   *
390   * @param family family name
391   * @param foffset family offset
392   * @param flength family length
393   * @param qualifier column qualifier
394   * @param qoffset qualifier offset
395   * @param qlength qualifier length
396   *
397   * @return the Cell for the column, or null if no value exists in the row or none have been
398   * selected in the query (Get/Scan)
399   */
400  public Cell getColumnLatestCell(byte [] family, int foffset, int flength,
401      byte [] qualifier, int qoffset, int qlength) {
402
403    Cell [] kvs = rawCells(); // side effect possibly.
404    if (kvs == null || kvs.length == 0) {
405      return null;
406    }
407    int pos = binarySearch(kvs, family, foffset, flength, qualifier, qoffset, qlength);
408    if (pos == -1) {
409      return null;
410    }
411    if (PrivateCellUtil.matchingColumn(kvs[pos], family, foffset, flength, qualifier, qoffset,
412      qlength)) {
413      return kvs[pos];
414    }
415    return null;
416  }
417
418  /**
419   * Get the latest version of the specified column.
420   * Note: this call clones the value content of the hosting Cell. See
421   * {@link #getValueAsByteBuffer(byte[], byte[])}, etc., or {@link #listCells()} if you would
422   * avoid the cloning.
423   * @param family family name
424   * @param qualifier column qualifier
425   * @return value of latest version of column, null if none found
426   */
427  public byte[] getValue(byte [] family, byte [] qualifier) {
428    Cell kv = getColumnLatestCell(family, qualifier);
429    if (kv == null) {
430      return null;
431    }
432    return CellUtil.cloneValue(kv);
433  }
434
435  /**
436   * Returns the value wrapped in a new <code>ByteBuffer</code>.
437   *
438   * @param family family name
439   * @param qualifier column qualifier
440   *
441   * @return the latest version of the column, or <code>null</code> if none found
442   */
443  public ByteBuffer getValueAsByteBuffer(byte [] family, byte [] qualifier) {
444
445    Cell kv = getColumnLatestCell(family, 0, family.length, qualifier, 0, qualifier.length);
446
447    if (kv == null) {
448      return null;
449    }
450    return ByteBuffer.wrap(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()).
451      asReadOnlyBuffer();
452  }
453
454  /**
455   * Returns the value wrapped in a new <code>ByteBuffer</code>.
456   *
457   * @param family family name
458   * @param foffset family offset
459   * @param flength family length
460   * @param qualifier column qualifier
461   * @param qoffset qualifier offset
462   * @param qlength qualifier length
463   *
464   * @return the latest version of the column, or <code>null</code> if none found
465   */
466  public ByteBuffer getValueAsByteBuffer(byte [] family, int foffset, int flength,
467      byte [] qualifier, int qoffset, int qlength) {
468
469    Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
470
471    if (kv == null) {
472      return null;
473    }
474    return ByteBuffer.wrap(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()).
475      asReadOnlyBuffer();
476  }
477
478  /**
479   * Loads the latest version of the specified column into the provided <code>ByteBuffer</code>.
480   * <p>
481   * Does not clear or flip the buffer.
482   *
483   * @param family family name
484   * @param qualifier column qualifier
485   * @param dst the buffer where to write the value
486   *
487   * @return <code>true</code> if a value was found, <code>false</code> otherwise
488   *
489   * @throws BufferOverflowException there is insufficient space remaining in the buffer
490   */
491  public boolean loadValue(byte [] family, byte [] qualifier, ByteBuffer dst)
492          throws BufferOverflowException {
493    return loadValue(family, 0, family.length, qualifier, 0, qualifier.length, dst);
494  }
495
496  /**
497   * Loads the latest version of the specified column into the provided <code>ByteBuffer</code>.
498   * <p>
499   * Does not clear or flip the buffer.
500   *
501   * @param family family name
502   * @param foffset family offset
503   * @param flength family length
504   * @param qualifier column qualifier
505   * @param qoffset qualifier offset
506   * @param qlength qualifier length
507   * @param dst the buffer where to write the value
508   *
509   * @return <code>true</code> if a value was found, <code>false</code> otherwise
510   *
511   * @throws BufferOverflowException there is insufficient space remaining in the buffer
512   */
513  public boolean loadValue(byte [] family, int foffset, int flength,
514      byte [] qualifier, int qoffset, int qlength, ByteBuffer dst)
515          throws BufferOverflowException {
516    Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
517
518    if (kv == null) {
519      return false;
520    }
521    dst.put(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength());
522    return true;
523  }
524
525  /**
526   * Checks if the specified column contains a non-empty value (not a zero-length byte array).
527   *
528   * @param family family name
529   * @param qualifier column qualifier
530   *
531   * @return whether or not a latest value exists and is not empty
532   */
533  public boolean containsNonEmptyColumn(byte [] family, byte [] qualifier) {
534
535    return containsNonEmptyColumn(family, 0, family.length, qualifier, 0, qualifier.length);
536  }
537
538  /**
539   * Checks if the specified column contains a non-empty value (not a zero-length byte array).
540   *
541   * @param family family name
542   * @param foffset family offset
543   * @param flength family length
544   * @param qualifier column qualifier
545   * @param qoffset qualifier offset
546   * @param qlength qualifier length
547   *
548   * @return whether or not a latest value exists and is not empty
549   */
550  public boolean containsNonEmptyColumn(byte [] family, int foffset, int flength,
551      byte [] qualifier, int qoffset, int qlength) {
552
553    Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
554
555    return (kv != null) && (kv.getValueLength() > 0);
556  }
557
558  /**
559   * Checks if the specified column contains an empty value (a zero-length byte array).
560   *
561   * @param family family name
562   * @param qualifier column qualifier
563   *
564   * @return whether or not a latest value exists and is empty
565   */
566  public boolean containsEmptyColumn(byte [] family, byte [] qualifier) {
567
568    return containsEmptyColumn(family, 0, family.length, qualifier, 0, qualifier.length);
569  }
570
571  /**
572   * Checks if the specified column contains an empty value (a zero-length byte array).
573   *
574   * @param family family name
575   * @param foffset family offset
576   * @param flength family length
577   * @param qualifier column qualifier
578   * @param qoffset qualifier offset
579   * @param qlength qualifier length
580   *
581   * @return whether or not a latest value exists and is empty
582   */
583  public boolean containsEmptyColumn(byte [] family, int foffset, int flength,
584      byte [] qualifier, int qoffset, int qlength) {
585    Cell kv = getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength);
586
587    return (kv != null) && (kv.getValueLength() == 0);
588  }
589
590  /**
591   * Checks for existence of a value for the specified column (empty or not).
592   *
593   * @param family family name
594   * @param qualifier column qualifier
595   *
596   * @return true if at least one value exists in the result, false if not
597   */
598  public boolean containsColumn(byte [] family, byte [] qualifier) {
599    Cell kv = getColumnLatestCell(family, qualifier);
600    return kv != null;
601  }
602
603  /**
604   * Checks for existence of a value for the specified column (empty or not).
605   *
606   * @param family family name
607   * @param foffset family offset
608   * @param flength family length
609   * @param qualifier column qualifier
610   * @param qoffset qualifier offset
611   * @param qlength qualifier length
612   *
613   * @return true if at least one value exists in the result, false if not
614   */
615  public boolean containsColumn(byte [] family, int foffset, int flength,
616      byte [] qualifier, int qoffset, int qlength) {
617
618    return getColumnLatestCell(family, foffset, flength, qualifier, qoffset, qlength) != null;
619  }
620
621  /**
622   * Map of families to all versions of its qualifiers and values.
623   * <p>
624   * Returns a three level Map of the form:
625   * <code>Map&amp;family,Map&lt;qualifier,Map&lt;timestamp,value&gt;&gt;&gt;</code>
626   * <p>
627   * Note: All other map returning methods make use of this map internally.
628   * @return map from families to qualifiers to versions
629   */
630  public NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> getMap() {
631    if (this.familyMap != null) {
632      return this.familyMap;
633    }
634    if(isEmpty()) {
635      return null;
636    }
637    this.familyMap = new TreeMap<>(Bytes.BYTES_COMPARATOR);
638    for(Cell kv : this.cells) {
639      byte [] family = CellUtil.cloneFamily(kv);
640      NavigableMap<byte[], NavigableMap<Long, byte[]>> columnMap = familyMap.get(family);
641      if(columnMap == null) {
642        columnMap = new TreeMap<>(Bytes.BYTES_COMPARATOR);
643        familyMap.put(family, columnMap);
644      }
645      byte [] qualifier = CellUtil.cloneQualifier(kv);
646      NavigableMap<Long, byte[]> versionMap = columnMap.get(qualifier);
647      if(versionMap == null) {
648        versionMap = new TreeMap<>(new Comparator<Long>() {
649          @Override
650          public int compare(Long l1, Long l2) {
651            return l2.compareTo(l1);
652          }
653        });
654        columnMap.put(qualifier, versionMap);
655      }
656      Long timestamp = kv.getTimestamp();
657      byte [] value = CellUtil.cloneValue(kv);
658
659      versionMap.put(timestamp, value);
660    }
661    return this.familyMap;
662  }
663
664  /**
665   * Map of families to their most recent qualifiers and values.
666   * <p>
667   * Returns a two level Map of the form: <code>Map&amp;family,Map&lt;qualifier,value&gt;&gt;</code>
668   * <p>
669   * The most recent version of each qualifier will be used.
670   * @return map from families to qualifiers and value
671   */
672  public NavigableMap<byte[], NavigableMap<byte[], byte[]>> getNoVersionMap() {
673    if(this.familyMap == null) {
674      getMap();
675    }
676    if(isEmpty()) {
677      return null;
678    }
679    NavigableMap<byte[], NavigableMap<byte[], byte[]>> returnMap = new TreeMap<>(Bytes.BYTES_COMPARATOR);
680    for(Map.Entry<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>>
681      familyEntry : familyMap.entrySet()) {
682      NavigableMap<byte[], byte[]> qualifierMap = new TreeMap<>(Bytes.BYTES_COMPARATOR);
683      for(Map.Entry<byte[], NavigableMap<Long, byte[]>> qualifierEntry :
684        familyEntry.getValue().entrySet()) {
685        byte [] value =
686          qualifierEntry.getValue().get(qualifierEntry.getValue().firstKey());
687        qualifierMap.put(qualifierEntry.getKey(), value);
688      }
689      returnMap.put(familyEntry.getKey(), qualifierMap);
690    }
691    return returnMap;
692  }
693
694  /**
695   * Map of qualifiers to values.
696   * <p>
697   * Returns a Map of the form: <code>Map&lt;qualifier,value&gt;</code>
698   * @param family column family to get
699   * @return map of qualifiers to values
700   */
701  public NavigableMap<byte[], byte[]> getFamilyMap(byte [] family) {
702    if(this.familyMap == null) {
703      getMap();
704    }
705    if(isEmpty()) {
706      return null;
707    }
708    NavigableMap<byte[], byte[]> returnMap = new TreeMap<>(Bytes.BYTES_COMPARATOR);
709    NavigableMap<byte[], NavigableMap<Long, byte[]>> qualifierMap =
710      familyMap.get(family);
711    if(qualifierMap == null) {
712      return returnMap;
713    }
714    for(Map.Entry<byte[], NavigableMap<Long, byte[]>> entry :
715      qualifierMap.entrySet()) {
716      byte [] value =
717        entry.getValue().get(entry.getValue().firstKey());
718      returnMap.put(entry.getKey(), value);
719    }
720    return returnMap;
721  }
722
723  /**
724   * Returns the value of the first column in the Result.
725   * @return value of the first column
726   */
727  public byte [] value() {
728    if (isEmpty()) {
729      return null;
730    }
731    return CellUtil.cloneValue(cells[0]);
732  }
733
734  /**
735   * Check if the underlying Cell [] is empty or not
736   * @return true if empty
737   */
738  public boolean isEmpty() {
739    return this.cells == null || this.cells.length == 0;
740  }
741
742  /**
743   * @return the size of the underlying Cell []
744   */
745  public int size() {
746    return this.cells == null? 0: this.cells.length;
747  }
748
749  /**
750   * @return String
751   */
752  @Override
753  public String toString() {
754    StringBuilder sb = new StringBuilder();
755    sb.append("keyvalues=");
756    if(isEmpty()) {
757      sb.append("NONE");
758      return sb.toString();
759    }
760    sb.append("{");
761    boolean moreThanOne = false;
762    for(Cell kv : this.cells) {
763      if(moreThanOne) {
764        sb.append(", ");
765      } else {
766        moreThanOne = true;
767      }
768      sb.append(kv.toString());
769    }
770    sb.append("}");
771    return sb.toString();
772  }
773
774  /**
775   * Does a deep comparison of two Results, down to the byte arrays.
776   * @param res1 first result to compare
777   * @param res2 second result to compare
778   * @throws Exception Every difference is throwing an exception
779   */
780  public static void compareResults(Result res1, Result res2)
781      throws Exception {
782    if (res2 == null) {
783      throw new Exception("There wasn't enough rows, we stopped at "
784          + Bytes.toStringBinary(res1.getRow()));
785    }
786    if (res1.size() != res2.size()) {
787      throw new Exception("This row doesn't have the same number of KVs: "
788          + res1.toString() + " compared to " + res2.toString());
789    }
790    Cell[] ourKVs = res1.rawCells();
791    Cell[] replicatedKVs = res2.rawCells();
792    for (int i = 0; i < res1.size(); i++) {
793      if (!ourKVs[i].equals(replicatedKVs[i]) ||
794          !CellUtil.matchingValue(ourKVs[i], replicatedKVs[i])) {
795        throw new Exception("This result was different: "
796            + res1.toString() + " compared to " + res2.toString());
797      }
798    }
799  }
800
801  /**
802   * Forms a single result from the partial results in the partialResults list. This method is
803   * useful for reconstructing partial results on the client side.
804   * @param partialResults list of partial results
805   * @return The complete result that is formed by combining all of the partial results together
806   * @throws IOException A complete result cannot be formed because the results in the partial list
807   *           come from different rows
808   */
809  public static Result createCompleteResult(Iterable<Result> partialResults)
810      throws IOException {
811    if (partialResults == null) {
812      return Result.create(Collections.emptyList(), null, false);
813    }
814    List<Cell> cells = new ArrayList<>();
815    boolean stale = false;
816    byte[] prevRow = null;
817    byte[] currentRow = null;
818    for (Iterator<Result> iter = partialResults.iterator(); iter.hasNext();) {
819      Result r = iter.next();
820      currentRow = r.getRow();
821      if (prevRow != null && !Bytes.equals(prevRow, currentRow)) {
822        throw new IOException(
823            "Cannot form complete result. Rows of partial results do not match." +
824                " Partial Results: " + partialResults);
825      }
826      // Ensure that all Results except the last one are marked as partials. The last result
827      // may not be marked as a partial because Results are only marked as partials when
828      // the scan on the server side must be stopped due to reaching the maxResultSize.
829      // Visualizing it makes it easier to understand:
830      // maxResultSize: 2 cells
831      // (-x-) represents cell number x in a row
832      // Example: row1: -1- -2- -3- -4- -5- (5 cells total)
833      // How row1 will be returned by the server as partial Results:
834      // Result1: -1- -2- (2 cells, size limit reached, mark as partial)
835      // Result2: -3- -4- (2 cells, size limit reached, mark as partial)
836      // Result3: -5- (1 cell, size limit NOT reached, NOT marked as partial)
837      if (iter.hasNext() && !r.mayHaveMoreCellsInRow()) {
838        throw new IOException("Cannot form complete result. Result is missing partial flag. " +
839            "Partial Results: " + partialResults);
840      }
841      prevRow = currentRow;
842      stale = stale || r.isStale();
843      for (Cell c : r.rawCells()) {
844        cells.add(c);
845      }
846    }
847
848    return Result.create(cells, null, stale);
849  }
850
851  /**
852   * Get total size of raw cells
853   * @param result
854   * @return Total size.
855   */
856  public static long getTotalSizeOfCells(Result result) {
857    long size = 0;
858    if (result.isEmpty()) {
859      return size;
860    }
861    for (Cell c : result.rawCells()) {
862      size += c.heapSize();
863    }
864    return size;
865  }
866
867  /**
868   * Copy another Result into this one. Needed for the old Mapred framework
869   * @throws UnsupportedOperationException if invoked on instance of EMPTY_RESULT
870   * (which is supposed to be immutable).
871   * @param other
872   */
873  public void copyFrom(Result other) {
874    checkReadonly();
875    this.row = null;
876    this.familyMap = null;
877    this.cells = other.cells;
878  }
879
880  @Override
881  public CellScanner cellScanner() {
882    // Reset
883    this.cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
884    return this;
885  }
886
887  @Override
888  public Cell current() {
889    if (cells == null
890            || cellScannerIndex == INITIAL_CELLSCANNER_INDEX
891            || cellScannerIndex >= cells.length)
892      return null;
893    return this.cells[cellScannerIndex];
894  }
895
896  @Override
897  public boolean advance() {
898    if (cells == null) return false;
899    cellScannerIndex++;
900    if (cellScannerIndex < this.cells.length) {
901      return true;
902    } else if (cellScannerIndex == this.cells.length) {
903      return false;
904    }
905    throw new NoSuchElementException("Cannot advance beyond the last cell");
906  }
907
908  public Boolean getExists() {
909    return exists;
910  }
911
912  public void setExists(Boolean exists) {
913    checkReadonly();
914    this.exists = exists;
915  }
916
917  /**
918   * Whether or not the results are coming from possibly stale data. Stale results
919   * might be returned if {@link Consistency} is not STRONG for the query.
920   * @return Whether or not the results are coming from possibly stale data.
921   */
922  public boolean isStale() {
923    return stale;
924  }
925
926  /**
927   * For scanning large rows, the RS may choose to return the cells chunk by chunk to prevent OOM
928   * or timeout. This flag is used to tell you if the current Result is the last one of the current
929   * row. False means this Result is the last one. True means there MAY be more cells belonging to
930   * the current row.
931   * If you don't use {@link Scan#setAllowPartialResults(boolean)} or {@link Scan#setBatch(int)},
932   * this method will always return false because the Result must contains all cells in one Row.
933   */
934  public boolean mayHaveMoreCellsInRow() {
935    return mayHaveMoreCellsInRow;
936  }
937
938  /**
939   * Set load information about the region to the information about the result
940   * @param loadStats statistics about the current region from which this was returned
941   */
942  @InterfaceAudience.Private
943  public void setStatistics(RegionLoadStats loadStats) {
944    this.stats = loadStats;
945  }
946
947  /**
948   * @return the associated statistics about the region from which this was returned. Can be
949   * <tt>null</tt> if stats are disabled.
950   */
951  public RegionLoadStats getStats() {
952    return stats;
953  }
954
955  /**
956   * All methods modifying state of Result object must call this method
957   * to ensure that special purpose immutable Results can't be accidentally modified.
958   */
959  private void checkReadonly() {
960    if (readonly == true) {
961      throw new UnsupportedOperationException("Attempting to modify readonly EMPTY_RESULT!");
962    }
963  }
964
965  /**
966   * Return true if this Result is a cursor to tell users where the server has scanned.
967   * In this Result the only meaningful method is {@link #getCursor()}.
968   *
969   * {@code
970   *  while (r = scanner.next() && r != null) {
971   *    if(r.isCursor()){
972   *    // scanning is not end, it is a cursor, save its row key and close scanner if you want, or
973   *    // just continue the loop to call next().
974   *    } else {
975   *    // just like before
976   *    }
977   *  }
978   *  // scanning is end
979   *
980   * }
981   * {@link Scan#setNeedCursorResult(boolean)}
982   * {@link Cursor}
983   * {@link #getCursor()}
984   */
985  public boolean isCursor() {
986    return cursor != null ;
987  }
988
989  /**
990   * Return the cursor if this Result is a cursor result.
991   * {@link Scan#setNeedCursorResult(boolean)}
992   * {@link Cursor}
993   * {@link #isCursor()}
994   */
995  public Cursor getCursor(){
996    return cursor;
997  }
998}