1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.client;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.LinkedList;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.classification.InterfaceAudience;
28 import org.apache.hadoop.classification.InterfaceStability;
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.hbase.Cell;
31 import org.apache.hadoop.hbase.HConstants;
32 import org.apache.hadoop.hbase.HRegionInfo;
33 import org.apache.hadoop.hbase.KeyValueUtil;
34 import org.apache.hadoop.hbase.TableName;
35 import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
36 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
37 import org.apache.hadoop.hbase.protobuf.RequestConverter;
38 import org.apache.hadoop.hbase.protobuf.ResponseConverter;
39 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest;
40 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanResponse;
41 import org.apache.hadoop.hbase.util.Bytes;
42
43 import com.google.protobuf.ServiceException;
44
45
46
47
48
49
50
51
52 @InterfaceAudience.Public
53 @InterfaceStability.Evolving
54 public class ClientSmallScanner extends ClientScanner {
55 private final Log LOG = LogFactory.getLog(this.getClass());
56 private RegionServerCallable<Result[]> smallScanCallable = null;
57
58
59 private byte[] skipRowOfFirstResult = null;
60
61
62
63
64
65
66
67
68
69
70
71 public ClientSmallScanner(final Configuration conf, final Scan scan,
72 final TableName tableName) throws IOException {
73 this(conf, scan, tableName, HConnectionManager.getConnection(conf));
74 }
75
76
77
78
79
80
81
82
83
84
85
86 public ClientSmallScanner(final Configuration conf, final Scan scan,
87 final TableName tableName, HConnection connection) throws IOException {
88 this(conf, scan, tableName, connection, new RpcRetryingCallerFactory(conf));
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102 public ClientSmallScanner(final Configuration conf, final Scan scan,
103 final TableName tableName, HConnection connection,
104 RpcRetryingCallerFactory rpcFactory) throws IOException {
105 super(conf, scan, tableName, connection, rpcFactory);
106 }
107
108 @Override
109 protected void initializeScannerInConstruction() throws IOException {
110
111
112 }
113
114
115
116
117
118
119
120
121
122
123 private boolean nextScanner(int nbRows, final boolean done,
124 boolean currentRegionDone) throws IOException {
125
126 byte[] localStartKey;
127 int cacheNum = nbRows;
128 skipRowOfFirstResult = null;
129
130 if (this.currentRegion != null && currentRegionDone) {
131 byte[] endKey = this.currentRegion.getEndKey();
132 if (endKey == null || Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY)
133 || checkScanStopRow(endKey) || done) {
134 close();
135 if (LOG.isDebugEnabled()) {
136 LOG.debug("Finished with small scan at " + this.currentRegion);
137 }
138 return false;
139 }
140 localStartKey = endKey;
141 if (LOG.isDebugEnabled()) {
142 LOG.debug("Finished with region " + this.currentRegion);
143 }
144 } else if (this.lastResult != null) {
145 localStartKey = this.lastResult.getRow();
146 skipRowOfFirstResult = this.lastResult.getRow();
147 cacheNum++;
148 } else {
149 localStartKey = this.scan.getStartRow();
150 }
151
152 if (LOG.isTraceEnabled()) {
153 LOG.trace("Advancing internal small scanner to startKey at '"
154 + Bytes.toStringBinary(localStartKey) + "'");
155 }
156 smallScanCallable = getSmallScanCallable(localStartKey, cacheNum);
157 if (this.scanMetrics != null && skipRowOfFirstResult == null) {
158 this.scanMetrics.countOfRegions.incrementAndGet();
159 }
160 return true;
161 }
162
163 private RegionServerCallable<Result[]> getSmallScanCallable(
164 byte[] localStartKey, final int cacheNum) {
165 this.scan.setStartRow(localStartKey);
166 RegionServerCallable<Result[]> callable = new RegionServerCallable<Result[]>(
167 getConnection(), getTable(), scan.getStartRow()) {
168 public Result[] call() throws IOException {
169 ScanRequest request = RequestConverter.buildScanRequest(getLocation()
170 .getRegionInfo().getRegionName(), scan, cacheNum, true);
171 ScanResponse response = null;
172 PayloadCarryingRpcController controller = new PayloadCarryingRpcController();
173 try {
174 controller.setPriority(getTableName());
175 response = getStub().scan(controller, request);
176 return ResponseConverter.getResults(controller.cellScanner(),
177 response);
178 } catch (ServiceException se) {
179 throw ProtobufUtil.getRemoteException(se);
180 }
181 }
182 };
183 return callable;
184 }
185
186 @Override
187 public Result next() throws IOException {
188
189
190 if (cache.size() == 0 && this.closed) {
191 return null;
192 }
193 if (cache.size() == 0) {
194 Result[] values = null;
195 long remainingResultSize = maxScannerResultSize;
196 int countdown = this.caching;
197 boolean currentRegionDone = false;
198
199 while (remainingResultSize > 0 && countdown > 0
200 && nextScanner(countdown, values == null, currentRegionDone)) {
201
202
203
204 values = this.caller.callWithRetries(smallScanCallable);
205 this.currentRegion = smallScanCallable.getHRegionInfo();
206 long currentTime = System.currentTimeMillis();
207 if (this.scanMetrics != null) {
208 this.scanMetrics.sumOfMillisSecBetweenNexts.addAndGet(currentTime
209 - lastNext);
210 }
211 lastNext = currentTime;
212 if (values != null && values.length > 0) {
213 for (int i = 0; i < values.length; i++) {
214 Result rs = values[i];
215 if (i == 0 && this.skipRowOfFirstResult != null
216 && Bytes.equals(skipRowOfFirstResult, rs.getRow())) {
217
218 continue;
219 }
220 cache.add(rs);
221 for (Cell kv : rs.rawCells()) {
222 remainingResultSize -= KeyValueUtil.ensureKeyValue(kv).heapSize();
223 }
224 countdown--;
225 this.lastResult = rs;
226 }
227 }
228 currentRegionDone = countdown > 0;
229 }
230 }
231
232 if (cache.size() > 0) {
233 return cache.poll();
234 }
235
236
237 writeScanMetrics();
238 return null;
239 }
240
241 @Override
242 public void close() {
243 if (!scanMetricsPublished) writeScanMetrics();
244 closed = true;
245 }
246 }