1 /* 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 package org.apache.hadoop.hbase.client; 21 22 import java.io.IOException; 23 import java.util.ArrayList; 24 import java.util.HashMap; 25 import java.util.List; 26 import java.util.Map; 27 import java.util.NavigableSet; 28 import java.util.TreeMap; 29 import java.util.TreeSet; 30 31 import org.apache.commons.logging.Log; 32 import org.apache.commons.logging.LogFactory; 33 import org.apache.hadoop.hbase.classification.InterfaceAudience; 34 import org.apache.hadoop.hbase.classification.InterfaceStability; 35 import org.apache.hadoop.hbase.HConstants; 36 import org.apache.hadoop.hbase.filter.Filter; 37 import org.apache.hadoop.hbase.filter.IncompatibleFilterException; 38 import org.apache.hadoop.hbase.io.TimeRange; 39 import org.apache.hadoop.hbase.util.Bytes; 40 41 /** 42 * Used to perform Scan operations. 43 * <p> 44 * All operations are identical to {@link Get} with the exception of 45 * instantiation. Rather than specifying a single row, an optional startRow 46 * and stopRow may be defined. If rows are not specified, the Scanner will 47 * iterate over all rows. 48 * <p> 49 * To scan everything for each row, instantiate a Scan object. 50 * <p> 51 * To modify scanner caching for just this scan, use {@link #setCaching(int) setCaching}. 52 * If caching is NOT set, we will use the caching value of the hosting {@link HTable}. See 53 * {@link HTable#setScannerCaching(int)}. In addition to row caching, it is possible to specify a 54 * maximum result size, using {@link #setMaxResultSize(long)}. When both are used, 55 * single server requests are limited by either number of rows or maximum result size, whichever 56 * limit comes first. 57 * <p> 58 * To further define the scope of what to get when scanning, perform additional 59 * methods as outlined below. 60 * <p> 61 * To get all columns from specific families, execute {@link #addFamily(byte[]) addFamily} 62 * for each family to retrieve. 63 * <p> 64 * To get specific columns, execute {@link #addColumn(byte[], byte[]) addColumn} 65 * for each column to retrieve. 66 * <p> 67 * To only retrieve columns within a specific range of version timestamps, 68 * execute {@link #setTimeRange(long, long) setTimeRange}. 69 * <p> 70 * To only retrieve columns with a specific timestamp, execute 71 * {@link #setTimeStamp(long) setTimestamp}. 72 * <p> 73 * To limit the number of versions of each column to be returned, execute 74 * {@link #setMaxVersions(int) setMaxVersions}. 75 * <p> 76 * To limit the maximum number of values returned for each call to next(), 77 * execute {@link #setBatch(int) setBatch}. 78 * <p> 79 * To add a filter, execute {@link #setFilter(org.apache.hadoop.hbase.filter.Filter) setFilter}. 80 * <p> 81 * Expert: To explicitly disable server-side block caching for this scan, 82 * execute {@link #setCacheBlocks(boolean)}. 83 * <p><em>Note:</em> Usage alters Scan instances. Internally, attributes are updated as the Scan 84 * runs and if enabled, metrics accumulate in the Scan instance. Be aware this is the case when 85 * you go to clone a Scan instance or if you go to reuse a created Scan instance; safer is create 86 * a Scan instance per usage. 87 */ 88 @InterfaceAudience.Public 89 @InterfaceStability.Stable 90 public class Scan extends Query { 91 private static final Log LOG = LogFactory.getLog(Scan.class); 92 93 private static final String RAW_ATTR = "_raw_"; 94 95 /** 96 * EXPERT ONLY. 97 * An integer (not long) indicating to the scanner logic how many times we attempt to retrieve the 98 * next KV before we schedule a reseek. 99 * The right value depends on the size of the average KV. A reseek is more efficient when 100 * it can skip 5-10 KVs or 512B-1KB, or when the next KV is likely found in another HFile block. 101 * Setting this only has any effect when columns were added with 102 * {@link #addColumn(byte[], byte[])} 103 * <pre>{@code 104 * Scan s = new Scan(...); 105 * s.addColumn(...); 106 * s.setAttribute(Scan.HINT_LOOKAHEAD, Bytes.toBytes(2)); 107 * }</pre> 108 * Default is 0 (always reseek). 109 * @deprecated without replacement 110 * This is now a no-op, SEEKs and SKIPs are optimizated automatically. 111 */ 112 @Deprecated 113 public static final String HINT_LOOKAHEAD = "_look_ahead_"; 114 115 private byte [] startRow = HConstants.EMPTY_START_ROW; 116 private byte [] stopRow = HConstants.EMPTY_END_ROW; 117 private int maxVersions = 1; 118 private int batch = -1; 119 120 private int storeLimit = -1; 121 private int storeOffset = 0; 122 private boolean getScan; 123 124 // If application wants to collect scan metrics, it needs to 125 // call scan.setAttribute(SCAN_ATTRIBUTES_ENABLE, Bytes.toBytes(Boolean.TRUE)) 126 static public final String SCAN_ATTRIBUTES_METRICS_ENABLE = "scan.attributes.metrics.enable"; 127 static public final String SCAN_ATTRIBUTES_METRICS_DATA = "scan.attributes.metrics.data"; 128 129 // If an application wants to use multiple scans over different tables each scan must 130 // define this attribute with the appropriate table name by calling 131 // scan.setAttribute(Scan.SCAN_ATTRIBUTES_TABLE_NAME, Bytes.toBytes(tableName)) 132 static public final String SCAN_ATTRIBUTES_TABLE_NAME = "scan.attributes.table.name"; 133 134 /* 135 * -1 means no caching 136 */ 137 private int caching = -1; 138 private long maxResultSize = -1; 139 private boolean cacheBlocks = true; 140 private boolean reversed = false; 141 private TimeRange tr = new TimeRange(); 142 private Map<byte [], NavigableSet<byte []>> familyMap = 143 new TreeMap<byte [], NavigableSet<byte []>>(Bytes.BYTES_COMPARATOR); 144 private Boolean loadColumnFamiliesOnDemand = null; 145 146 /** 147 * Set it true for small scan to get better performance 148 * 149 * Small scan should use pread and big scan can use seek + read 150 * 151 * seek + read is fast but can cause two problem (1) resource contention (2) 152 * cause too much network io 153 * 154 * [89-fb] Using pread for non-compaction read request 155 * https://issues.apache.org/jira/browse/HBASE-7266 156 * 157 * On the other hand, if setting it true, we would do 158 * openScanner,next,closeScanner in one RPC call. It means the better 159 * performance for small scan. [HBASE-9488]. 160 * 161 * Generally, if the scan range is within one data block(64KB), it could be 162 * considered as a small scan. 163 */ 164 private boolean small = false; 165 166 /** 167 * Create a Scan operation across all rows. 168 */ 169 public Scan() {} 170 171 public Scan(byte [] startRow, Filter filter) { 172 this(startRow); 173 this.filter = filter; 174 } 175 176 /** 177 * Create a Scan operation starting at the specified row. 178 * <p> 179 * If the specified row does not exist, the Scanner will start from the 180 * next closest row after the specified row. 181 * @param startRow row to start scanner at or after 182 */ 183 public Scan(byte [] startRow) { 184 this.startRow = startRow; 185 } 186 187 /** 188 * Create a Scan operation for the range of rows specified. 189 * @param startRow row to start scanner at or after (inclusive) 190 * @param stopRow row to stop scanner before (exclusive) 191 */ 192 public Scan(byte [] startRow, byte [] stopRow) { 193 this.startRow = startRow; 194 this.stopRow = stopRow; 195 //if the startRow and stopRow both are empty, it is not a Get 196 this.getScan = isStartRowAndEqualsStopRow(); 197 } 198 199 /** 200 * Creates a new instance of this class while copying all values. 201 * 202 * @param scan The scan instance to copy from. 203 * @throws IOException When copying the values fails. 204 */ 205 public Scan(Scan scan) throws IOException { 206 startRow = scan.getStartRow(); 207 stopRow = scan.getStopRow(); 208 maxVersions = scan.getMaxVersions(); 209 batch = scan.getBatch(); 210 storeLimit = scan.getMaxResultsPerColumnFamily(); 211 storeOffset = scan.getRowOffsetPerColumnFamily(); 212 caching = scan.getCaching(); 213 maxResultSize = scan.getMaxResultSize(); 214 cacheBlocks = scan.getCacheBlocks(); 215 getScan = scan.isGetScan(); 216 filter = scan.getFilter(); // clone? 217 loadColumnFamiliesOnDemand = scan.getLoadColumnFamiliesOnDemandValue(); 218 TimeRange ctr = scan.getTimeRange(); 219 tr = new TimeRange(ctr.getMin(), ctr.getMax()); 220 reversed = scan.isReversed(); 221 small = scan.isSmall(); 222 Map<byte[], NavigableSet<byte[]>> fams = scan.getFamilyMap(); 223 for (Map.Entry<byte[],NavigableSet<byte[]>> entry : fams.entrySet()) { 224 byte [] fam = entry.getKey(); 225 NavigableSet<byte[]> cols = entry.getValue(); 226 if (cols != null && cols.size() > 0) { 227 for (byte[] col : cols) { 228 addColumn(fam, col); 229 } 230 } else { 231 addFamily(fam); 232 } 233 } 234 for (Map.Entry<String, byte[]> attr : scan.getAttributesMap().entrySet()) { 235 setAttribute(attr.getKey(), attr.getValue()); 236 } 237 } 238 239 /** 240 * Builds a scan object with the same specs as get. 241 * @param get get to model scan after 242 */ 243 public Scan(Get get) { 244 this.startRow = get.getRow(); 245 this.stopRow = get.getRow(); 246 this.filter = get.getFilter(); 247 this.cacheBlocks = get.getCacheBlocks(); 248 this.maxVersions = get.getMaxVersions(); 249 this.storeLimit = get.getMaxResultsPerColumnFamily(); 250 this.storeOffset = get.getRowOffsetPerColumnFamily(); 251 this.tr = get.getTimeRange(); 252 this.familyMap = get.getFamilyMap(); 253 this.getScan = true; 254 for (Map.Entry<String, byte[]> attr : get.getAttributesMap().entrySet()) { 255 setAttribute(attr.getKey(), attr.getValue()); 256 } 257 } 258 259 public boolean isGetScan() { 260 return this.getScan || isStartRowAndEqualsStopRow(); 261 } 262 263 private boolean isStartRowAndEqualsStopRow() { 264 return this.startRow != null && this.startRow.length > 0 && 265 Bytes.equals(this.startRow, this.stopRow); 266 } 267 /** 268 * Get all columns from the specified family. 269 * <p> 270 * Overrides previous calls to addColumn for this family. 271 * @param family family name 272 * @return this 273 */ 274 public Scan addFamily(byte [] family) { 275 familyMap.remove(family); 276 familyMap.put(family, null); 277 return this; 278 } 279 280 /** 281 * Get the column from the specified family with the specified qualifier. 282 * <p> 283 * Overrides previous calls to addFamily for this family. 284 * @param family family name 285 * @param qualifier column qualifier 286 * @return this 287 */ 288 public Scan addColumn(byte [] family, byte [] qualifier) { 289 NavigableSet<byte []> set = familyMap.get(family); 290 if(set == null) { 291 set = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR); 292 } 293 if (qualifier == null) { 294 qualifier = HConstants.EMPTY_BYTE_ARRAY; 295 } 296 set.add(qualifier); 297 familyMap.put(family, set); 298 return this; 299 } 300 301 /** 302 * Get versions of columns only within the specified timestamp range, 303 * [minStamp, maxStamp). Note, default maximum versions to return is 1. If 304 * your time range spans more than one version and you want all versions 305 * returned, up the number of versions beyond the defaut. 306 * @param minStamp minimum timestamp value, inclusive 307 * @param maxStamp maximum timestamp value, exclusive 308 * @throws IOException if invalid time range 309 * @see #setMaxVersions() 310 * @see #setMaxVersions(int) 311 * @return this 312 */ 313 public Scan setTimeRange(long minStamp, long maxStamp) 314 throws IOException { 315 tr = new TimeRange(minStamp, maxStamp); 316 return this; 317 } 318 319 /** 320 * Get versions of columns with the specified timestamp. Note, default maximum 321 * versions to return is 1. If your time range spans more than one version 322 * and you want all versions returned, up the number of versions beyond the 323 * defaut. 324 * @param timestamp version timestamp 325 * @see #setMaxVersions() 326 * @see #setMaxVersions(int) 327 * @return this 328 */ 329 public Scan setTimeStamp(long timestamp) 330 throws IOException { 331 try { 332 tr = new TimeRange(timestamp, timestamp+1); 333 } catch(IOException e) { 334 // This should never happen, unless integer overflow or something extremely wrong... 335 LOG.error("TimeRange failed, likely caused by integer overflow. ", e); 336 throw e; 337 } 338 return this; 339 } 340 341 /** 342 * Set the start row of the scan. 343 * @param startRow row to start scan on (inclusive) 344 * Note: In order to make startRow exclusive add a trailing 0 byte 345 * @return this 346 */ 347 public Scan setStartRow(byte [] startRow) { 348 this.startRow = startRow; 349 return this; 350 } 351 352 /** 353 * Set the stop row. 354 * @param stopRow row to end at (exclusive) 355 * Note: In order to make stopRow inclusive add a trailing 0 byte 356 * @return this 357 */ 358 public Scan setStopRow(byte [] stopRow) { 359 this.stopRow = stopRow; 360 return this; 361 } 362 363 /** 364 * Get all available versions. 365 * @return this 366 */ 367 public Scan setMaxVersions() { 368 this.maxVersions = Integer.MAX_VALUE; 369 return this; 370 } 371 372 /** 373 * Get up to the specified number of versions of each column. 374 * @param maxVersions maximum versions for each column 375 * @return this 376 */ 377 public Scan setMaxVersions(int maxVersions) { 378 this.maxVersions = maxVersions; 379 return this; 380 } 381 382 /** 383 * Set the maximum number of values to return for each call to next() 384 * @param batch the maximum number of values 385 */ 386 public void setBatch(int batch) { 387 if (this.hasFilter() && this.filter.hasFilterRow()) { 388 throw new IncompatibleFilterException( 389 "Cannot set batch on a scan using a filter" + 390 " that returns true for filter.hasFilterRow"); 391 } 392 this.batch = batch; 393 } 394 395 /** 396 * Set the maximum number of values to return per row per Column Family 397 * @param limit the maximum number of values returned / row / CF 398 */ 399 public void setMaxResultsPerColumnFamily(int limit) { 400 this.storeLimit = limit; 401 } 402 403 /** 404 * Set offset for the row per Column Family. 405 * @param offset is the number of kvs that will be skipped. 406 */ 407 public void setRowOffsetPerColumnFamily(int offset) { 408 this.storeOffset = offset; 409 } 410 411 /** 412 * Set the number of rows for caching that will be passed to scanners. 413 * If not set, the default setting from {@link HTable#getScannerCaching()} will apply. 414 * Higher caching values will enable faster scanners but will use more memory. 415 * @param caching the number of rows for caching 416 */ 417 public void setCaching(int caching) { 418 this.caching = caching; 419 } 420 421 /** 422 * @return the maximum result size in bytes. See {@link #setMaxResultSize(long)} 423 */ 424 public long getMaxResultSize() { 425 return maxResultSize; 426 } 427 428 /** 429 * Set the maximum result size. The default is -1; this means that no specific 430 * maximum result size will be set for this scan, and the global configured 431 * value will be used instead. (Defaults to unlimited). 432 * 433 * @param maxResultSize The maximum result size in bytes. 434 */ 435 public void setMaxResultSize(long maxResultSize) { 436 this.maxResultSize = maxResultSize; 437 } 438 439 @Override 440 public Scan setFilter(Filter filter) { 441 super.setFilter(filter); 442 return this; 443 } 444 445 /** 446 * Setting the familyMap 447 * @param familyMap map of family to qualifier 448 * @return this 449 */ 450 public Scan setFamilyMap(Map<byte [], NavigableSet<byte []>> familyMap) { 451 this.familyMap = familyMap; 452 return this; 453 } 454 455 /** 456 * Getting the familyMap 457 * @return familyMap 458 */ 459 public Map<byte [], NavigableSet<byte []>> getFamilyMap() { 460 return this.familyMap; 461 } 462 463 /** 464 * @return the number of families in familyMap 465 */ 466 public int numFamilies() { 467 if(hasFamilies()) { 468 return this.familyMap.size(); 469 } 470 return 0; 471 } 472 473 /** 474 * @return true if familyMap is non empty, false otherwise 475 */ 476 public boolean hasFamilies() { 477 return !this.familyMap.isEmpty(); 478 } 479 480 /** 481 * @return the keys of the familyMap 482 */ 483 public byte[][] getFamilies() { 484 if(hasFamilies()) { 485 return this.familyMap.keySet().toArray(new byte[0][0]); 486 } 487 return null; 488 } 489 490 /** 491 * @return the startrow 492 */ 493 public byte [] getStartRow() { 494 return this.startRow; 495 } 496 497 /** 498 * @return the stoprow 499 */ 500 public byte [] getStopRow() { 501 return this.stopRow; 502 } 503 504 /** 505 * @return the max number of versions to fetch 506 */ 507 public int getMaxVersions() { 508 return this.maxVersions; 509 } 510 511 /** 512 * @return maximum number of values to return for a single call to next() 513 */ 514 public int getBatch() { 515 return this.batch; 516 } 517 518 /** 519 * @return maximum number of values to return per row per CF 520 */ 521 public int getMaxResultsPerColumnFamily() { 522 return this.storeLimit; 523 } 524 525 /** 526 * Method for retrieving the scan's offset per row per column 527 * family (#kvs to be skipped) 528 * @return row offset 529 */ 530 public int getRowOffsetPerColumnFamily() { 531 return this.storeOffset; 532 } 533 534 /** 535 * @return caching the number of rows fetched when calling next on a scanner 536 */ 537 public int getCaching() { 538 return this.caching; 539 } 540 541 /** 542 * @return TimeRange 543 */ 544 public TimeRange getTimeRange() { 545 return this.tr; 546 } 547 548 /** 549 * @return RowFilter 550 */ 551 public Filter getFilter() { 552 return filter; 553 } 554 555 /** 556 * @return true is a filter has been specified, false if not 557 */ 558 public boolean hasFilter() { 559 return filter != null; 560 } 561 562 /** 563 * Set whether blocks should be cached for this Scan. 564 * <p> 565 * This is true by default. When true, default settings of the table and 566 * family are used (this will never override caching blocks if the block 567 * cache is disabled for that family or entirely). 568 * 569 * @param cacheBlocks if false, default settings are overridden and blocks 570 * will not be cached 571 */ 572 public void setCacheBlocks(boolean cacheBlocks) { 573 this.cacheBlocks = cacheBlocks; 574 } 575 576 /** 577 * Get whether blocks should be cached for this Scan. 578 * @return true if default caching should be used, false if blocks should not 579 * be cached 580 */ 581 public boolean getCacheBlocks() { 582 return cacheBlocks; 583 } 584 585 /** 586 * Set whether this scan is a reversed one 587 * <p> 588 * This is false by default which means forward(normal) scan. 589 * 590 * @param reversed if true, scan will be backward order 591 * @return this 592 */ 593 public Scan setReversed(boolean reversed) { 594 this.reversed = reversed; 595 return this; 596 } 597 598 /** 599 * Get whether this scan is a reversed one. 600 * @return true if backward scan, false if forward(default) scan 601 */ 602 public boolean isReversed() { 603 return reversed; 604 } 605 606 /** 607 * Set the value indicating whether loading CFs on demand should be allowed (cluster 608 * default is false). On-demand CF loading doesn't load column families until necessary, e.g. 609 * if you filter on one column, the other column family data will be loaded only for the rows 610 * that are included in result, not all rows like in normal case. 611 * With column-specific filters, like SingleColumnValueFilter w/filterIfMissing == true, 612 * this can deliver huge perf gains when there's a cf with lots of data; however, it can 613 * also lead to some inconsistent results, as follows: 614 * - if someone does a concurrent update to both column families in question you may get a row 615 * that never existed, e.g. for { rowKey = 5, { cat_videos => 1 }, { video => "my cat" } } 616 * someone puts rowKey 5 with { cat_videos => 0 }, { video => "my dog" }, concurrent scan 617 * filtering on "cat_videos == 1" can get { rowKey = 5, { cat_videos => 1 }, 618 * { video => "my dog" } }. 619 * - if there's a concurrent split and you have more than 2 column families, some rows may be 620 * missing some column families. 621 */ 622 public void setLoadColumnFamiliesOnDemand(boolean value) { 623 this.loadColumnFamiliesOnDemand = value; 624 } 625 626 /** 627 * Get the raw loadColumnFamiliesOnDemand setting; if it's not set, can be null. 628 */ 629 public Boolean getLoadColumnFamiliesOnDemandValue() { 630 return this.loadColumnFamiliesOnDemand; 631 } 632 633 /** 634 * Get the logical value indicating whether on-demand CF loading should be allowed. 635 */ 636 public boolean doLoadColumnFamiliesOnDemand() { 637 return (this.loadColumnFamiliesOnDemand != null) 638 && this.loadColumnFamiliesOnDemand.booleanValue(); 639 } 640 641 /** 642 * Compile the table and column family (i.e. schema) information 643 * into a String. Useful for parsing and aggregation by debugging, 644 * logging, and administration tools. 645 * @return Map 646 */ 647 @Override 648 public Map<String, Object> getFingerprint() { 649 Map<String, Object> map = new HashMap<String, Object>(); 650 List<String> families = new ArrayList<String>(); 651 if(this.familyMap.size() == 0) { 652 map.put("families", "ALL"); 653 return map; 654 } else { 655 map.put("families", families); 656 } 657 for (Map.Entry<byte [], NavigableSet<byte[]>> entry : 658 this.familyMap.entrySet()) { 659 families.add(Bytes.toStringBinary(entry.getKey())); 660 } 661 return map; 662 } 663 664 /** 665 * Compile the details beyond the scope of getFingerprint (row, columns, 666 * timestamps, etc.) into a Map along with the fingerprinted information. 667 * Useful for debugging, logging, and administration tools. 668 * @param maxCols a limit on the number of columns output prior to truncation 669 * @return Map 670 */ 671 @Override 672 public Map<String, Object> toMap(int maxCols) { 673 // start with the fingerpring map and build on top of it 674 Map<String, Object> map = getFingerprint(); 675 // map from families to column list replaces fingerprint's list of families 676 Map<String, List<String>> familyColumns = 677 new HashMap<String, List<String>>(); 678 map.put("families", familyColumns); 679 // add scalar information first 680 map.put("startRow", Bytes.toStringBinary(this.startRow)); 681 map.put("stopRow", Bytes.toStringBinary(this.stopRow)); 682 map.put("maxVersions", this.maxVersions); 683 map.put("batch", this.batch); 684 map.put("caching", this.caching); 685 map.put("maxResultSize", this.maxResultSize); 686 map.put("cacheBlocks", this.cacheBlocks); 687 map.put("loadColumnFamiliesOnDemand", this.loadColumnFamiliesOnDemand); 688 List<Long> timeRange = new ArrayList<Long>(); 689 timeRange.add(this.tr.getMin()); 690 timeRange.add(this.tr.getMax()); 691 map.put("timeRange", timeRange); 692 int colCount = 0; 693 // iterate through affected families and list out up to maxCols columns 694 for (Map.Entry<byte [], NavigableSet<byte[]>> entry : 695 this.familyMap.entrySet()) { 696 List<String> columns = new ArrayList<String>(); 697 familyColumns.put(Bytes.toStringBinary(entry.getKey()), columns); 698 if(entry.getValue() == null) { 699 colCount++; 700 --maxCols; 701 columns.add("ALL"); 702 } else { 703 colCount += entry.getValue().size(); 704 if (maxCols <= 0) { 705 continue; 706 } 707 for (byte [] column : entry.getValue()) { 708 if (--maxCols <= 0) { 709 continue; 710 } 711 columns.add(Bytes.toStringBinary(column)); 712 } 713 } 714 } 715 map.put("totalColumns", colCount); 716 if (this.filter != null) { 717 map.put("filter", this.filter.toString()); 718 } 719 // add the id if set 720 if (getId() != null) { 721 map.put("id", getId()); 722 } 723 return map; 724 } 725 726 /** 727 * Enable/disable "raw" mode for this scan. 728 * If "raw" is enabled the scan will return all 729 * delete marker and deleted rows that have not 730 * been collected, yet. 731 * This is mostly useful for Scan on column families 732 * that have KEEP_DELETED_ROWS enabled. 733 * It is an error to specify any column when "raw" is set. 734 * @param raw True/False to enable/disable "raw" mode. 735 */ 736 public void setRaw(boolean raw) { 737 setAttribute(RAW_ATTR, Bytes.toBytes(raw)); 738 } 739 740 /** 741 * @return True if this Scan is in "raw" mode. 742 */ 743 public boolean isRaw() { 744 byte[] attr = getAttribute(RAW_ATTR); 745 return attr == null ? false : Bytes.toBoolean(attr); 746 } 747 748 /** 749 * Set whether this scan is a small scan 750 * <p> 751 * Small scan should use pread and big scan can use seek + read 752 * 753 * seek + read is fast but can cause two problem (1) resource contention (2) 754 * cause too much network io 755 * 756 * [89-fb] Using pread for non-compaction read request 757 * https://issues.apache.org/jira/browse/HBASE-7266 758 * 759 * On the other hand, if setting it true, we would do 760 * openScanner,next,closeScanner in one RPC call. It means the better 761 * performance for small scan. [HBASE-9488]. 762 * 763 * Generally, if the scan range is within one data block(64KB), it could be 764 * considered as a small scan. 765 * 766 * @param small 767 */ 768 public void setSmall(boolean small) { 769 this.small = small; 770 } 771 772 /** 773 * Get whether this scan is a small scan 774 * @return true if small scan 775 */ 776 public boolean isSmall() { 777 return small; 778 } 779 }