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.conf.Configuration;
27 import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
28 import org.apache.hadoop.hbase.DoNotRetryIOException;
29 import org.apache.hadoop.hbase.HRegionInfo;
30 import org.apache.hadoop.hbase.HRegionLocation;
31 import org.apache.hadoop.hbase.NotServingRegionException;
32 import org.apache.hadoop.hbase.RemoteExceptionHandler;
33 import org.apache.hadoop.hbase.UnknownScannerException;
34 import org.apache.hadoop.hbase.regionserver.RegionServerStoppedException;
35 import org.apache.hadoop.ipc.RemoteException;
36 import org.apache.hadoop.net.DNS;
37
38
39
40
41
42 public class ScannerCallable extends ServerCallable<Result[]> {
43 public static final String LOG_SCANNER_LATENCY_CUTOFF
44 = "hbase.client.log.scanner.latency.cutoff";
45 public static final String LOG_SCANNER_ACTIVITY = "hbase.client.log.scanner.activity";
46 private static final Log LOG = LogFactory.getLog(ScannerCallable.class);
47 private long scannerId = -1L;
48 private boolean instantiated = false;
49 private boolean closed = false;
50 private Scan scan;
51 private int caching = 1;
52 private ScanMetrics scanMetrics;
53 private boolean logScannerActivity = false;
54 private int logCutOffLatency = 1000;
55
56
57 private boolean isRegionServerRemote = true;
58
59
60
61
62
63
64
65
66 public ScannerCallable (HConnection connection, byte [] tableName, Scan scan,
67 ScanMetrics scanMetrics) {
68 super(connection, tableName, scan.getStartRow());
69 this.scan = scan;
70 this.scanMetrics = scanMetrics;
71 Configuration conf = connection.getConfiguration();
72 logScannerActivity = conf.getBoolean(LOG_SCANNER_ACTIVITY, false);
73 logCutOffLatency = conf.getInt(LOG_SCANNER_LATENCY_CUTOFF, 1000);
74 }
75
76
77
78
79
80 @Override
81 public void connect(boolean reload) throws IOException {
82 if (!instantiated || reload) {
83 super.connect(reload);
84 checkIfRegionServerIsRemote();
85 instantiated = true;
86 }
87
88
89
90
91 if (reload && this.scanMetrics != null) {
92 this.scanMetrics.countOfRPCRetries.inc();
93 if (isRegionServerRemote) {
94 this.scanMetrics.countOfRemoteRPCRetries.inc();
95 }
96 }
97 }
98
99
100
101
102
103
104 private void checkIfRegionServerIsRemote() throws UnknownHostException {
105 String myAddress = DNS.getDefaultHost("default", "default");
106 if (this.location.getHostname().equalsIgnoreCase(myAddress)) {
107 isRegionServerRemote = false;
108 } else {
109 isRegionServerRemote = true;
110 }
111 }
112
113
114
115
116 public Result [] call() throws IOException {
117 if (scannerId != -1L && closed) {
118 close();
119 } else if (scannerId == -1L && !closed) {
120 this.scannerId = openScanner();
121 } else {
122 Result [] rrs = null;
123 try {
124 incRPCcallsMetrics();
125 long timestamp = System.currentTimeMillis();
126 rrs = server.next(scannerId, caching);
127 if (logScannerActivity) {
128 long now = System.currentTimeMillis();
129 if (now - timestamp > logCutOffLatency) {
130 int rows = rrs == null ? 0 : rrs.length;
131 LOG.info("Took " + (now-timestamp) + "ms to fetch "
132 + rows + " rows from scanner=" + scannerId);
133 }
134 }
135 updateResultsMetrics(rrs);
136 } catch (IOException e) {
137 if (logScannerActivity) {
138 LOG.info("Got exception in fetching from scanner="
139 + scannerId, e);
140 }
141 IOException ioe = null;
142 if (e instanceof RemoteException) {
143 ioe = RemoteExceptionHandler.decodeRemoteException((RemoteException)e);
144 }
145 if (ioe == null) throw new IOException(e);
146 if (logScannerActivity && (ioe instanceof UnknownScannerException)) {
147 try {
148 HRegionLocation location =
149 connection.relocateRegion(tableName, scan.getStartRow());
150 LOG.info("Scanner=" + scannerId
151 + " expired, current region location is " + location.toString()
152 + " ip:" + location.getServerAddress().getBindAddress());
153 } catch (Throwable t) {
154 LOG.info("Failed to relocate region", t);
155 }
156 }
157 if (ioe instanceof NotServingRegionException) {
158
159
160
161 if (this.scanMetrics != null) {
162 this.scanMetrics.countOfNSRE.inc();
163 }
164 throw new DoNotRetryIOException("Reset scanner", ioe);
165 } else if (ioe instanceof RegionServerStoppedException) {
166
167
168
169 throw new DoNotRetryIOException("Reset scanner", ioe);
170 } else {
171
172 throw ioe;
173 }
174 }
175 return rrs;
176 }
177 return null;
178 }
179
180 private void incRPCcallsMetrics() {
181 if (this.scanMetrics == null) {
182 return;
183 }
184 this.scanMetrics.countOfRPCcalls.inc();
185 if (isRegionServerRemote) {
186 this.scanMetrics.countOfRemoteRPCcalls.inc();
187 }
188 }
189
190 private void updateResultsMetrics(Result[] rrs) {
191 if (this.scanMetrics == null || rrs == null) {
192 return;
193 }
194 for (Result rr : rrs) {
195 this.scanMetrics.countOfBytesInResults.inc(rr.getBytes().getLength());
196 if (isRegionServerRemote) {
197 this.scanMetrics.countOfBytesInRemoteResults.inc(
198 rr.getBytes().getLength());
199 }
200 }
201 }
202
203 private void close() {
204 if (this.scannerId == -1L) {
205 return;
206 }
207 try {
208 incRPCcallsMetrics();
209 this.server.close(this.scannerId);
210 } catch (IOException e) {
211 LOG.warn("Ignore, probably already closed", e);
212 }
213 this.scannerId = -1L;
214 }
215
216 protected long openScanner() throws IOException {
217 incRPCcallsMetrics();
218 long id = this.server.openScanner(this.location.getRegionInfo().getRegionName(),
219 this.scan);
220 if (logScannerActivity) {
221 LOG.info("Open scanner=" + id + " for scan=" + scan.toString()
222 + " on region " + this.location.toString() + " ip:"
223 + this.location.getServerAddress().getBindAddress());
224 }
225 return id;
226 }
227
228 protected Scan getScan() {
229 return scan;
230 }
231
232
233
234
235 public void setClose() {
236 this.closed = true;
237 }
238
239
240
241
242 public HRegionInfo getHRegionInfo() {
243 if (!instantiated) {
244 return null;
245 }
246 return location.getRegionInfo();
247 }
248
249
250
251
252
253 public int getCaching() {
254 return caching;
255 }
256
257
258
259
260
261 public void setCaching(int caching) {
262 this.caching = caching;
263 }
264 }