1 package org.apache.hadoop.hbase.ipc;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.net.InetSocketAddress;
20 import java.nio.channels.ClosedChannelException;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.hadoop.hbase.CallDroppedException;
25 import org.apache.hadoop.hbase.CellScanner;
26 import org.apache.hadoop.hbase.HBaseInterfaceAudience;
27 import org.apache.hadoop.hbase.classification.InterfaceAudience;
28 import org.apache.hadoop.hbase.classification.InterfaceStability;
29 import org.apache.hadoop.hbase.exceptions.TimeoutIOException;
30 import org.apache.hadoop.hbase.ipc.RpcServer.Call;
31 import org.apache.hadoop.hbase.monitoring.MonitoredRPCHandler;
32 import org.apache.hadoop.hbase.util.Pair;
33 import org.apache.hadoop.security.UserGroupInformation;
34 import org.apache.hadoop.util.StringUtils;
35 import org.apache.htrace.Trace;
36 import org.apache.htrace.TraceScope;
37
38 import com.google.protobuf.Message;
39
40
41
42
43
44
45 @InterfaceAudience.LimitedPrivate({HBaseInterfaceAudience.COPROC, HBaseInterfaceAudience.PHOENIX})
46 @InterfaceStability.Evolving
47 public class CallRunner {
48 private static final Log LOG = LogFactory.getLog(CallRunner.class);
49
50 private static final CallDroppedException CALL_DROPPED_EXCEPTION
51 = new CallDroppedException();
52
53 private Call call;
54 private RpcServerInterface rpcServer;
55 private MonitoredRPCHandler status;
56 private volatile boolean sucessful;
57
58
59
60
61
62
63
64 CallRunner(final RpcServerInterface rpcServer, final Call call) {
65 this.call = call;
66 this.rpcServer = rpcServer;
67
68 if (call != null && rpcServer != null) {
69 this.rpcServer.addCallSize(call.getSize());
70 }
71 }
72
73 public Call getCall() {
74 return call;
75 }
76
77 public void setStatus(MonitoredRPCHandler status) {
78 this.status = status;
79 }
80
81
82
83
84 private void cleanup() {
85 this.call = null;
86 this.rpcServer = null;
87 }
88
89 public void run() {
90 try {
91 if (!call.connection.channel.isOpen()) {
92 if (RpcServer.LOG.isDebugEnabled()) {
93 RpcServer.LOG.debug(Thread.currentThread().getName() + ": skipped " + call);
94 }
95 return;
96 }
97 call.startTime = System.currentTimeMillis();
98 if (call.startTime > call.deadline) {
99 RpcServer.LOG.warn("Drop timeout call: " + call);
100 return;
101 }
102 this.status.setStatus("Setting up call");
103 this.status.setConnection(call.connection.getHostAddress(), call.connection.getRemotePort());
104 if (RpcServer.LOG.isTraceEnabled()) {
105 UserGroupInformation remoteUser = call.connection.ugi;
106 RpcServer.LOG.trace(call.toShortString() + " executing as " +
107 ((remoteUser == null) ? "NULL principal" : remoteUser.getUserName()));
108 }
109 Throwable errorThrowable = null;
110 String error = null;
111 Pair<Message, CellScanner> resultPair = null;
112 RpcServer.CurCall.set(call);
113 TraceScope traceScope = null;
114 try {
115 if (!this.rpcServer.isStarted()) {
116 InetSocketAddress address = rpcServer.getListenerAddress();
117 throw new ServerNotRunningYetException("Server " +
118 (address != null ? address : "(channel closed)") + " is not running yet");
119 }
120 if (call.tinfo != null) {
121 traceScope = Trace.startSpan(call.toTraceString(), call.tinfo);
122 }
123
124 resultPair = this.rpcServer.call(call.service, call.md, call.param, call.cellScanner,
125 call.timestamp, this.status, call.startTime, call.timeout);
126 } catch (TimeoutIOException e){
127 RpcServer.LOG.warn("Can not complete this request in time, drop it: " + call);
128 return;
129 } catch (Throwable e) {
130 RpcServer.LOG.debug(Thread.currentThread().getName() + ": " + call.toShortString(), e);
131 errorThrowable = e;
132 error = StringUtils.stringifyException(e);
133 if (e instanceof Error) {
134 throw (Error)e;
135 }
136 } finally {
137 if (traceScope != null) {
138 traceScope.close();
139 }
140 RpcServer.CurCall.set(null);
141 if (resultPair != null) {
142 this.rpcServer.addCallSize(call.getSize() * -1);
143 sucessful = true;
144 }
145 }
146
147 Message param = resultPair != null ? resultPair.getFirst() : null;
148 CellScanner cells = resultPair != null ? resultPair.getSecond() : null;
149 call.setResponse(param, cells, errorThrowable, error);
150 call.sendResponseIfReady();
151 this.status.markComplete("Sent response");
152 this.status.pause("Waiting for a call");
153 } catch (OutOfMemoryError e) {
154 if (this.rpcServer.getErrorHandler() != null) {
155 if (this.rpcServer.getErrorHandler().checkOOME(e)) {
156 RpcServer.LOG.info(Thread.currentThread().getName() + ": exiting on OutOfMemoryError");
157 return;
158 }
159 } else {
160
161 throw e;
162 }
163 } catch (ClosedChannelException cce) {
164 InetSocketAddress address = rpcServer.getListenerAddress();
165 RpcServer.LOG.warn(Thread.currentThread().getName() + ": caught a ClosedChannelException, " +
166 "this means that the server " + (address != null ? address : "(channel closed)") +
167 " was processing a request but the client went away. The error message was: " +
168 cce.getMessage());
169 } catch (Exception e) {
170 RpcServer.LOG.warn(Thread.currentThread().getName()
171 + ": caught: " + StringUtils.stringifyException(e));
172 } finally {
173 if (!sucessful) {
174 this.rpcServer.addCallSize(call.getSize() * -1);
175 }
176 cleanup();
177 }
178 }
179
180
181
182
183 public void drop() {
184 try {
185 if (!call.connection.channel.isOpen()) {
186 if (RpcServer.LOG.isDebugEnabled()) {
187 RpcServer.LOG.debug(Thread.currentThread().getName() + ": skipped " + call);
188 }
189 return;
190 }
191
192
193 InetSocketAddress address = rpcServer.getListenerAddress();
194 call.setResponse(null, null, CALL_DROPPED_EXCEPTION, "Call dropped, server "
195 + (address != null ? address : "(channel closed)") + " is overloaded, please retry.");
196 call.sendResponseIfReady();
197 } catch (ClosedChannelException cce) {
198 InetSocketAddress address = rpcServer.getListenerAddress();
199 RpcServer.LOG.warn(Thread.currentThread().getName() + ": caught a ClosedChannelException, " +
200 "this means that the server " + (address != null ? address : "(channel closed)") +
201 " was processing a request but the client went away. The error message was: " +
202 cce.getMessage());
203 } catch (Exception e) {
204 RpcServer.LOG.warn(Thread.currentThread().getName()
205 + ": caught: " + StringUtils.stringifyException(e));
206 } finally {
207 if (!sucessful) {
208 this.rpcServer.addCallSize(call.getSize() * -1);
209 }
210 cleanup();
211 }
212 }
213 }