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