View Javadoc

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