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