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