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