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 -> 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&family,Map<qualifier,Map<timestamp,value>>></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&family,Map<qualifier,value>></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<qualifier,value></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}