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