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.net.UnknownHostException;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.hadoop.classification.InterfaceAudience;
27 import org.apache.hadoop.conf.Configuration;
28 import org.apache.hadoop.hbase.Cell;
29 import org.apache.hadoop.hbase.CellScanner;
30 import org.apache.hadoop.hbase.DoNotRetryIOException;
31 import org.apache.hadoop.hbase.HRegionInfo;
32 import org.apache.hadoop.hbase.HRegionLocation;
33 import org.apache.hadoop.hbase.KeyValueUtil;
34 import org.apache.hadoop.hbase.NotServingRegionException;
35 import org.apache.hadoop.hbase.RemoteExceptionHandler;
36 import org.apache.hadoop.hbase.TableName;
37 import org.apache.hadoop.hbase.UnknownScannerException;
38 import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
39 import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
40 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
41 import org.apache.hadoop.hbase.protobuf.RequestConverter;
42 import org.apache.hadoop.hbase.protobuf.ResponseConverter;
43 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest;
44 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanResponse;
45 import org.apache.hadoop.hbase.regionserver.RegionServerStoppedException;
46 import org.apache.hadoop.ipc.RemoteException;
47 import org.apache.hadoop.net.DNS;
48
49 import com.google.protobuf.ServiceException;
50 import com.google.protobuf.TextFormat;
51
52
53
54
55
56
57 @InterfaceAudience.Private
58 public class ScannerCallable extends RegionServerCallable<Result[]> {
59 public static final String LOG_SCANNER_LATENCY_CUTOFF
60 = "hbase.client.log.scanner.latency.cutoff";
61 public static final String LOG_SCANNER_ACTIVITY = "hbase.client.log.scanner.activity";
62
63 public static final Log LOG = LogFactory.getLog(ScannerCallable.class);
64 private long scannerId = -1L;
65 private boolean instantiated = false;
66 private boolean closed = false;
67 private Scan scan;
68 private int caching = 1;
69 private ScanMetrics scanMetrics;
70 private boolean logScannerActivity = false;
71 private int logCutOffLatency = 1000;
72 private static String myAddress;
73 static {
74 try {
75 myAddress = DNS.getDefaultHost("default", "default");
76 } catch (UnknownHostException uhe) {
77 LOG.error("cannot determine my address", uhe);
78 }
79 }
80
81
82 private boolean isRegionServerRemote = true;
83 private long nextCallSeq = 0;
84
85
86
87
88
89
90
91
92 public ScannerCallable (HConnection connection, TableName tableName, Scan scan,
93 ScanMetrics scanMetrics) {
94 super(connection, tableName, scan.getStartRow());
95 this.scan = scan;
96 this.scanMetrics = scanMetrics;
97 Configuration conf = connection.getConfiguration();
98 logScannerActivity = conf.getBoolean(LOG_SCANNER_ACTIVITY, false);
99 logCutOffLatency = conf.getInt(LOG_SCANNER_LATENCY_CUTOFF, 1000);
100 }
101
102
103
104
105 @Deprecated
106 public ScannerCallable (HConnection connection, final byte [] tableName, Scan scan,
107 ScanMetrics scanMetrics) {
108 this(connection, TableName.valueOf(tableName), scan, scanMetrics);
109 }
110
111
112
113
114
115 @Override
116 public void prepare(boolean reload) throws IOException {
117 if (!instantiated || reload) {
118 super.prepare(reload);
119 checkIfRegionServerIsRemote();
120 instantiated = true;
121 }
122
123
124
125
126 if (reload && this.scanMetrics != null) {
127 this.scanMetrics.countOfRPCRetries.incrementAndGet();
128 if (isRegionServerRemote) {
129 this.scanMetrics.countOfRemoteRPCRetries.incrementAndGet();
130 }
131 }
132 }
133
134
135
136
137
138 private void checkIfRegionServerIsRemote() {
139 if (getLocation().getHostname().equalsIgnoreCase(myAddress)) {
140 isRegionServerRemote = false;
141 } else {
142 isRegionServerRemote = true;
143 }
144 }
145
146
147
148
149 @SuppressWarnings("deprecation")
150 public Result [] call() throws IOException {
151 if (closed) {
152 if (scannerId != -1) {
153 close();
154 }
155 } else {
156 if (scannerId == -1L) {
157 this.scannerId = openScanner();
158 } else {
159 Result [] rrs = null;
160 ScanRequest request = null;
161 try {
162 incRPCcallsMetrics();
163 request = RequestConverter.buildScanRequest(scannerId, caching, false, nextCallSeq);
164 ScanResponse response = null;
165 PayloadCarryingRpcController controller = new PayloadCarryingRpcController();
166 try {
167 controller.setPriority(getTableName());
168 response = getStub().scan(controller, request);
169
170
171
172
173
174
175
176
177
178 nextCallSeq++;
179 long timestamp = System.currentTimeMillis();
180
181 CellScanner cellScanner = controller.cellScanner();
182 rrs = ResponseConverter.getResults(cellScanner, response);
183 if (logScannerActivity) {
184 long now = System.currentTimeMillis();
185 if (now - timestamp > logCutOffLatency) {
186 int rows = rrs == null ? 0 : rrs.length;
187 LOG.info("Took " + (now-timestamp) + "ms to fetch "
188 + rows + " rows from scanner=" + scannerId);
189 }
190 }
191 if (response.hasMoreResults()
192 && !response.getMoreResults()) {
193 scannerId = -1L;
194 closed = true;
195 return null;
196 }
197 } catch (ServiceException se) {
198 throw ProtobufUtil.getRemoteException(se);
199 }
200 updateResultsMetrics(rrs);
201 } catch (IOException e) {
202 if (logScannerActivity) {
203 LOG.info("Got exception making request " + TextFormat.shortDebugString(request)
204 + " to " + getLocation(), e);
205 }
206 IOException ioe = e;
207 if (e instanceof RemoteException) {
208 ioe = RemoteExceptionHandler.decodeRemoteException((RemoteException)e);
209 }
210 if (logScannerActivity && (ioe instanceof UnknownScannerException)) {
211 try {
212 HRegionLocation location =
213 getConnection().relocateRegion(getTableName(), scan.getStartRow());
214 LOG.info("Scanner=" + scannerId
215 + " expired, current region location is " + location.toString());
216 } catch (Throwable t) {
217 LOG.info("Failed to relocate region", t);
218 }
219 }
220
221
222
223
224
225
226 if (ioe instanceof NotServingRegionException) {
227
228
229
230 if (this.scanMetrics != null) {
231 this.scanMetrics.countOfNSRE.incrementAndGet();
232 }
233 throw new DoNotRetryIOException("Resetting the scanner -- see exception cause", ioe);
234 } else if (ioe instanceof RegionServerStoppedException) {
235
236
237 throw new DoNotRetryIOException("Resetting the scanner -- see exception cause", ioe);
238 } else {
239
240 throw ioe;
241 }
242 }
243 return rrs;
244 }
245 }
246 return null;
247 }
248
249 private void incRPCcallsMetrics() {
250 if (this.scanMetrics == null) {
251 return;
252 }
253 this.scanMetrics.countOfRPCcalls.incrementAndGet();
254 if (isRegionServerRemote) {
255 this.scanMetrics.countOfRemoteRPCcalls.incrementAndGet();
256 }
257 }
258
259 private void updateResultsMetrics(Result[] rrs) {
260 if (this.scanMetrics == null || rrs == null || rrs.length == 0) {
261 return;
262 }
263 long resultSize = 0;
264 for (Result rr : rrs) {
265 for (Cell kv : rr.rawCells()) {
266
267 resultSize += KeyValueUtil.ensureKeyValue(kv).getLength();
268 }
269 }
270 this.scanMetrics.countOfBytesInResults.addAndGet(resultSize);
271 if (isRegionServerRemote) {
272 this.scanMetrics.countOfBytesInRemoteResults.addAndGet(resultSize);
273 }
274 }
275
276 private void close() {
277 if (this.scannerId == -1L) {
278 return;
279 }
280 try {
281 incRPCcallsMetrics();
282 ScanRequest request =
283 RequestConverter.buildScanRequest(this.scannerId, 0, true);
284 try {
285 getStub().scan(null, request);
286 } catch (ServiceException se) {
287 throw ProtobufUtil.getRemoteException(se);
288 }
289 } catch (IOException e) {
290 LOG.warn("Ignore, probably already closed", e);
291 }
292 this.scannerId = -1L;
293 }
294
295 protected long openScanner() throws IOException {
296 incRPCcallsMetrics();
297 ScanRequest request =
298 RequestConverter.buildScanRequest(
299 getLocation().getRegionInfo().getRegionName(),
300 this.scan, 0, false);
301 try {
302 ScanResponse response = getStub().scan(null, request);
303 long id = response.getScannerId();
304 if (logScannerActivity) {
305 LOG.info("Open scanner=" + id + " for scan=" + scan.toString()
306 + " on region " + getLocation().toString());
307 }
308 return id;
309 } catch (ServiceException se) {
310 throw ProtobufUtil.getRemoteException(se);
311 }
312 }
313
314 protected Scan getScan() {
315 return scan;
316 }
317
318
319
320
321 public void setClose() {
322 this.closed = true;
323 }
324
325
326
327
328 public HRegionInfo getHRegionInfo() {
329 if (!instantiated) {
330 return null;
331 }
332 return getLocation().getRegionInfo();
333 }
334
335
336
337
338
339 public int getCaching() {
340 return caching;
341 }
342
343
344
345
346
347 public void setCaching(int caching) {
348 this.caching = caching;
349 }
350 }