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