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