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