HADOOP-13465. Design Server.Call to be extensible for unified call queue. Contributed by Daryn Sharp.
(cherry picked from commit 76cd81f4b6
)
This commit is contained in:
parent
4d709be8c9
commit
caef03d742
|
@ -353,8 +353,7 @@ public abstract class Server {
|
||||||
*/
|
*/
|
||||||
public static InetAddress getRemoteIp() {
|
public static InetAddress getRemoteIp() {
|
||||||
Call call = CurCall.get();
|
Call call = CurCall.get();
|
||||||
return (call != null && call.connection != null) ? call.connection
|
return (call != null ) ? call.getHostInetAddress() : null;
|
||||||
.getHostInetAddress() : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -379,8 +378,7 @@ public abstract class Server {
|
||||||
*/
|
*/
|
||||||
public static UserGroupInformation getRemoteUser() {
|
public static UserGroupInformation getRemoteUser() {
|
||||||
Call call = CurCall.get();
|
Call call = CurCall.get();
|
||||||
return (call != null && call.connection != null) ? call.connection.user
|
return (call != null) ? call.getRemoteUser() : null;
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return true if the invocation was through an RPC.
|
/** Return true if the invocation was through an RPC.
|
||||||
|
@ -482,7 +480,7 @@ public abstract class Server {
|
||||||
if ((rpcMetrics.getProcessingSampleCount() > minSampleSize) &&
|
if ((rpcMetrics.getProcessingSampleCount() > minSampleSize) &&
|
||||||
(processingTime > threeSigma)) {
|
(processingTime > threeSigma)) {
|
||||||
if(LOG.isWarnEnabled()) {
|
if(LOG.isWarnEnabled()) {
|
||||||
String client = CurCall.get().connection.toString();
|
String client = CurCall.get().toString();
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
"Slow RPC : " + methodName + " took " + processingTime +
|
"Slow RPC : " + methodName + " took " + processingTime +
|
||||||
" milliseconds to process from client " + client);
|
" milliseconds to process from client " + client);
|
||||||
|
@ -656,48 +654,41 @@ public abstract class Server {
|
||||||
CommonConfigurationKeys.IPC_BACKOFF_ENABLE_DEFAULT);
|
CommonConfigurationKeys.IPC_BACKOFF_ENABLE_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A call queued for handling. */
|
/** A generic call queued for handling. */
|
||||||
public static class Call implements Schedulable {
|
public static class Call implements Schedulable,
|
||||||
private final int callId; // the client's call id
|
PrivilegedExceptionAction<Void> {
|
||||||
private final int retryCount; // the retry count of the call
|
final int callId; // the client's call id
|
||||||
private final Writable rpcRequest; // Serialized Rpc request from client
|
final int retryCount; // the retry count of the call
|
||||||
private final Connection connection; // connection to client
|
long timestamp; // time received when response is null
|
||||||
private long timestamp; // time received when response is null
|
// time served when response is not null
|
||||||
// time served when response is not null
|
|
||||||
private ByteBuffer rpcResponse; // the response for this call
|
|
||||||
private AtomicInteger responseWaitCount = new AtomicInteger(1);
|
private AtomicInteger responseWaitCount = new AtomicInteger(1);
|
||||||
private final RPC.RpcKind rpcKind;
|
final RPC.RpcKind rpcKind;
|
||||||
private final byte[] clientId;
|
final byte[] clientId;
|
||||||
private final TraceScope traceScope; // the HTrace scope on the server side
|
private final TraceScope traceScope; // the HTrace scope on the server side
|
||||||
private final CallerContext callerContext; // the call context
|
private final CallerContext callerContext; // the call context
|
||||||
private int priorityLevel;
|
private int priorityLevel;
|
||||||
// the priority level assigned by scheduler, 0 by default
|
// the priority level assigned by scheduler, 0 by default
|
||||||
|
|
||||||
private Call(Call call) {
|
Call(Call call) {
|
||||||
this(call.callId, call.retryCount, call.rpcRequest, call.connection,
|
this(call.callId, call.retryCount, call.rpcKind, call.clientId,
|
||||||
call.rpcKind, call.clientId, call.traceScope, call.callerContext);
|
call.traceScope, call.callerContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Call(int id, int retryCount, Writable param,
|
Call(int id, int retryCount, RPC.RpcKind kind, byte[] clientId) {
|
||||||
Connection connection) {
|
this(id, retryCount, kind, clientId, null, null);
|
||||||
this(id, retryCount, param, connection, RPC.RpcKind.RPC_BUILTIN,
|
|
||||||
RpcConstants.DUMMY_CLIENT_ID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Call(int id, int retryCount, Writable param, Connection connection,
|
@VisibleForTesting // primarily TestNamenodeRetryCache
|
||||||
|
public Call(int id, int retryCount, Void ignore1, Void ignore2,
|
||||||
RPC.RpcKind kind, byte[] clientId) {
|
RPC.RpcKind kind, byte[] clientId) {
|
||||||
this(id, retryCount, param, connection, kind, clientId, null, null);
|
this(id, retryCount, kind, clientId, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Call(int id, int retryCount, Writable param, Connection connection,
|
Call(int id, int retryCount, RPC.RpcKind kind, byte[] clientId,
|
||||||
RPC.RpcKind kind, byte[] clientId, TraceScope traceScope,
|
TraceScope traceScope, CallerContext callerContext) {
|
||||||
CallerContext callerContext) {
|
|
||||||
this.callId = id;
|
this.callId = id;
|
||||||
this.retryCount = retryCount;
|
this.retryCount = retryCount;
|
||||||
this.rpcRequest = param;
|
|
||||||
this.connection = connection;
|
|
||||||
this.timestamp = Time.now();
|
this.timestamp = Time.now();
|
||||||
this.rpcResponse = null;
|
|
||||||
this.rpcKind = kind;
|
this.rpcKind = kind;
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.traceScope = traceScope;
|
this.traceScope = traceScope;
|
||||||
|
@ -706,12 +697,22 @@ public abstract class Server {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return rpcRequest + " from " + connection + " Call#" + callId + " Retry#"
|
return "Call#" + callId + " Retry#" + retryCount;
|
||||||
+ retryCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResponse(ByteBuffer response) {
|
public Void run() throws Exception {
|
||||||
this.rpcResponse = response;
|
return null;
|
||||||
|
}
|
||||||
|
// should eventually be abstract but need to avoid breaking tests
|
||||||
|
public UserGroupInformation getRemoteUser() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public InetAddress getHostInetAddress() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public String getHostAddress() {
|
||||||
|
InetAddress addr = getHostInetAddress();
|
||||||
|
return (addr != null) ? addr.getHostAddress() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -723,34 +724,36 @@ public abstract class Server {
|
||||||
*/
|
*/
|
||||||
@InterfaceStability.Unstable
|
@InterfaceStability.Unstable
|
||||||
@InterfaceAudience.LimitedPrivate({"HDFS"})
|
@InterfaceAudience.LimitedPrivate({"HDFS"})
|
||||||
public void postponeResponse() {
|
public final void postponeResponse() {
|
||||||
int count = responseWaitCount.incrementAndGet();
|
int count = responseWaitCount.incrementAndGet();
|
||||||
assert count > 0 : "response has already been sent";
|
assert count > 0 : "response has already been sent";
|
||||||
}
|
}
|
||||||
|
|
||||||
@InterfaceStability.Unstable
|
@InterfaceStability.Unstable
|
||||||
@InterfaceAudience.LimitedPrivate({"HDFS"})
|
@InterfaceAudience.LimitedPrivate({"HDFS"})
|
||||||
public void sendResponse() throws IOException {
|
public final void sendResponse() throws IOException {
|
||||||
int count = responseWaitCount.decrementAndGet();
|
int count = responseWaitCount.decrementAndGet();
|
||||||
assert count >= 0 : "response has already been sent";
|
assert count >= 0 : "response has already been sent";
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
connection.sendResponse(this);
|
doResponse(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@InterfaceStability.Unstable
|
@InterfaceStability.Unstable
|
||||||
@InterfaceAudience.LimitedPrivate({"HDFS"})
|
@InterfaceAudience.LimitedPrivate({"HDFS"})
|
||||||
public void abortResponse(Throwable t) throws IOException {
|
public final void abortResponse(Throwable t) throws IOException {
|
||||||
// don't send response if the call was already sent or aborted.
|
// don't send response if the call was already sent or aborted.
|
||||||
if (responseWaitCount.getAndSet(-1) > 0) {
|
if (responseWaitCount.getAndSet(-1) > 0) {
|
||||||
connection.abortResponse(this, t);
|
doResponse(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void doResponse(Throwable t) throws IOException {}
|
||||||
|
|
||||||
// For Schedulable
|
// For Schedulable
|
||||||
@Override
|
@Override
|
||||||
public UserGroupInformation getUserGroupInformation() {
|
public UserGroupInformation getUserGroupInformation() {
|
||||||
return connection.user;
|
return getRemoteUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -763,6 +766,114 @@ public abstract class Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A RPC extended call queued for handling. */
|
||||||
|
private class RpcCall extends Call {
|
||||||
|
final Connection connection; // connection to client
|
||||||
|
final Writable rpcRequest; // Serialized Rpc request from client
|
||||||
|
ByteBuffer rpcResponse; // the response for this call
|
||||||
|
|
||||||
|
RpcCall(RpcCall call) {
|
||||||
|
super(call);
|
||||||
|
this.connection = call.connection;
|
||||||
|
this.rpcRequest = call.rpcRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpcCall(Connection connection, int id) {
|
||||||
|
this(connection, id, RpcConstants.INVALID_RETRY_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
RpcCall(Connection connection, int id, int retryCount) {
|
||||||
|
this(connection, id, retryCount, null,
|
||||||
|
RPC.RpcKind.RPC_BUILTIN, RpcConstants.DUMMY_CLIENT_ID,
|
||||||
|
null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
RpcCall(Connection connection, int id, int retryCount,
|
||||||
|
Writable param, RPC.RpcKind kind, byte[] clientId,
|
||||||
|
TraceScope traceScope, CallerContext context) {
|
||||||
|
super(id, retryCount, kind, clientId, traceScope, context);
|
||||||
|
this.connection = connection;
|
||||||
|
this.rpcRequest = param;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserGroupInformation getRemoteUser() {
|
||||||
|
return connection.user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetAddress getHostInetAddress() {
|
||||||
|
return connection.getHostInetAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void run() throws Exception {
|
||||||
|
if (!connection.channel.isOpen()) {
|
||||||
|
Server.LOG.info(Thread.currentThread().getName() + ": skipped " + this);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String errorClass = null;
|
||||||
|
String error = null;
|
||||||
|
RpcStatusProto returnStatus = RpcStatusProto.SUCCESS;
|
||||||
|
RpcErrorCodeProto detailedErr = null;
|
||||||
|
Writable value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
value = call(
|
||||||
|
rpcKind, connection.protocolName, rpcRequest, timestamp);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (e instanceof UndeclaredThrowableException) {
|
||||||
|
e = e.getCause();
|
||||||
|
}
|
||||||
|
logException(Server.LOG, e, this);
|
||||||
|
if (e instanceof RpcServerException) {
|
||||||
|
RpcServerException rse = ((RpcServerException)e);
|
||||||
|
returnStatus = rse.getRpcStatusProto();
|
||||||
|
detailedErr = rse.getRpcErrorCodeProto();
|
||||||
|
} else {
|
||||||
|
returnStatus = RpcStatusProto.ERROR;
|
||||||
|
detailedErr = RpcErrorCodeProto.ERROR_APPLICATION;
|
||||||
|
}
|
||||||
|
errorClass = e.getClass().getName();
|
||||||
|
error = StringUtils.stringifyException(e);
|
||||||
|
// Remove redundant error class name from the beginning of the
|
||||||
|
// stack trace
|
||||||
|
String exceptionHdr = errorClass + ": ";
|
||||||
|
if (error.startsWith(exceptionHdr)) {
|
||||||
|
error = error.substring(exceptionHdr.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setupResponse(this, returnStatus, detailedErr,
|
||||||
|
value, errorClass, error);
|
||||||
|
sendResponse();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setResponse(ByteBuffer response) throws IOException {
|
||||||
|
this.rpcResponse = response;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void doResponse(Throwable t) throws IOException {
|
||||||
|
RpcCall call = this;
|
||||||
|
if (t != null) {
|
||||||
|
// clone the call to prevent a race with another thread stomping
|
||||||
|
// on the response while being sent. the original call is
|
||||||
|
// effectively discarded since the wait count won't hit zero
|
||||||
|
call = new RpcCall(this);
|
||||||
|
setupResponse(call,
|
||||||
|
RpcStatusProto.FATAL, RpcErrorCodeProto.ERROR_RPC_SERVER,
|
||||||
|
null, t.getClass().getName(), StringUtils.stringifyException(t));
|
||||||
|
}
|
||||||
|
connection.sendResponse(call);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " " + rpcRequest + " from " + connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Listens on the socket. Creates jobs for the handler threads*/
|
/** Listens on the socket. Creates jobs for the handler threads*/
|
||||||
private class Listener extends Thread {
|
private class Listener extends Thread {
|
||||||
|
|
||||||
|
@ -1093,22 +1204,22 @@ public abstract class Server {
|
||||||
if(LOG.isDebugEnabled()) {
|
if(LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Checking for old call responses.");
|
LOG.debug("Checking for old call responses.");
|
||||||
}
|
}
|
||||||
ArrayList<Call> calls;
|
ArrayList<RpcCall> calls;
|
||||||
|
|
||||||
// get the list of channels from list of keys.
|
// get the list of channels from list of keys.
|
||||||
synchronized (writeSelector.keys()) {
|
synchronized (writeSelector.keys()) {
|
||||||
calls = new ArrayList<Call>(writeSelector.keys().size());
|
calls = new ArrayList<RpcCall>(writeSelector.keys().size());
|
||||||
iter = writeSelector.keys().iterator();
|
iter = writeSelector.keys().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
SelectionKey key = iter.next();
|
SelectionKey key = iter.next();
|
||||||
Call call = (Call)key.attachment();
|
RpcCall call = (RpcCall)key.attachment();
|
||||||
if (call != null && key.channel() == call.connection.channel) {
|
if (call != null && key.channel() == call.connection.channel) {
|
||||||
calls.add(call);
|
calls.add(call);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Call call : calls) {
|
for (RpcCall call : calls) {
|
||||||
doPurge(call, now);
|
doPurge(call, now);
|
||||||
}
|
}
|
||||||
} catch (OutOfMemoryError e) {
|
} catch (OutOfMemoryError e) {
|
||||||
|
@ -1126,7 +1237,7 @@ public abstract class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doAsyncWrite(SelectionKey key) throws IOException {
|
private void doAsyncWrite(SelectionKey key) throws IOException {
|
||||||
Call call = (Call)key.attachment();
|
RpcCall call = (RpcCall)key.attachment();
|
||||||
if (call == null) {
|
if (call == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1154,10 +1265,10 @@ public abstract class Server {
|
||||||
// Remove calls that have been pending in the responseQueue
|
// Remove calls that have been pending in the responseQueue
|
||||||
// for a long time.
|
// for a long time.
|
||||||
//
|
//
|
||||||
private void doPurge(Call call, long now) {
|
private void doPurge(RpcCall call, long now) {
|
||||||
LinkedList<Call> responseQueue = call.connection.responseQueue;
|
LinkedList<RpcCall> responseQueue = call.connection.responseQueue;
|
||||||
synchronized (responseQueue) {
|
synchronized (responseQueue) {
|
||||||
Iterator<Call> iter = responseQueue.listIterator(0);
|
Iterator<RpcCall> iter = responseQueue.listIterator(0);
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
call = iter.next();
|
call = iter.next();
|
||||||
if (now > call.timestamp + PURGE_INTERVAL) {
|
if (now > call.timestamp + PURGE_INTERVAL) {
|
||||||
|
@ -1171,12 +1282,12 @@ public abstract class Server {
|
||||||
// Processes one response. Returns true if there are no more pending
|
// Processes one response. Returns true if there are no more pending
|
||||||
// data for this channel.
|
// data for this channel.
|
||||||
//
|
//
|
||||||
private boolean processResponse(LinkedList<Call> responseQueue,
|
private boolean processResponse(LinkedList<RpcCall> responseQueue,
|
||||||
boolean inHandler) throws IOException {
|
boolean inHandler) throws IOException {
|
||||||
boolean error = true;
|
boolean error = true;
|
||||||
boolean done = false; // there is more data for this channel.
|
boolean done = false; // there is more data for this channel.
|
||||||
int numElements = 0;
|
int numElements = 0;
|
||||||
Call call = null;
|
RpcCall call = null;
|
||||||
try {
|
try {
|
||||||
synchronized (responseQueue) {
|
synchronized (responseQueue) {
|
||||||
//
|
//
|
||||||
|
@ -1259,7 +1370,7 @@ public abstract class Server {
|
||||||
//
|
//
|
||||||
// Enqueue a response from the application.
|
// Enqueue a response from the application.
|
||||||
//
|
//
|
||||||
void doRespond(Call call) throws IOException {
|
void doRespond(RpcCall call) throws IOException {
|
||||||
synchronized (call.connection.responseQueue) {
|
synchronized (call.connection.responseQueue) {
|
||||||
// must only wrap before adding to the responseQueue to prevent
|
// must only wrap before adding to the responseQueue to prevent
|
||||||
// postponed responses from being encrypted and sent out of order.
|
// postponed responses from being encrypted and sent out of order.
|
||||||
|
@ -1357,7 +1468,7 @@ public abstract class Server {
|
||||||
private SocketChannel channel;
|
private SocketChannel channel;
|
||||||
private ByteBuffer data;
|
private ByteBuffer data;
|
||||||
private ByteBuffer dataLengthBuffer;
|
private ByteBuffer dataLengthBuffer;
|
||||||
private LinkedList<Call> responseQueue;
|
private LinkedList<RpcCall> responseQueue;
|
||||||
// number of outstanding rpcs
|
// number of outstanding rpcs
|
||||||
private AtomicInteger rpcCount = new AtomicInteger();
|
private AtomicInteger rpcCount = new AtomicInteger();
|
||||||
private long lastContact;
|
private long lastContact;
|
||||||
|
@ -1384,8 +1495,8 @@ public abstract class Server {
|
||||||
public UserGroupInformation attemptingUser = null; // user name before auth
|
public UserGroupInformation attemptingUser = null; // user name before auth
|
||||||
|
|
||||||
// Fake 'call' for failed authorization response
|
// Fake 'call' for failed authorization response
|
||||||
private final Call authFailedCall = new Call(AUTHORIZATION_FAILED_CALL_ID,
|
private final RpcCall authFailedCall =
|
||||||
RpcConstants.INVALID_RETRY_COUNT, null, this);
|
new RpcCall(this, AUTHORIZATION_FAILED_CALL_ID);
|
||||||
|
|
||||||
private boolean sentNegotiate = false;
|
private boolean sentNegotiate = false;
|
||||||
private boolean useWrap = false;
|
private boolean useWrap = false;
|
||||||
|
@ -1405,7 +1516,7 @@ public abstract class Server {
|
||||||
this.hostAddress = addr.getHostAddress();
|
this.hostAddress = addr.getHostAddress();
|
||||||
}
|
}
|
||||||
this.remotePort = socket.getPort();
|
this.remotePort = socket.getPort();
|
||||||
this.responseQueue = new LinkedList<Call>();
|
this.responseQueue = new LinkedList<RpcCall>();
|
||||||
if (socketSendBufferSize != 0) {
|
if (socketSendBufferSize != 0) {
|
||||||
try {
|
try {
|
||||||
socket.setSendBufferSize(socketSendBufferSize);
|
socket.setSendBufferSize(socketSendBufferSize);
|
||||||
|
@ -1666,8 +1777,7 @@ public abstract class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doSaslReply(Message message) throws IOException {
|
private void doSaslReply(Message message) throws IOException {
|
||||||
final Call saslCall = new Call(AuthProtocol.SASL.callId,
|
final RpcCall saslCall = new RpcCall(this, AuthProtocol.SASL.callId);
|
||||||
RpcConstants.INVALID_RETRY_COUNT, null, this);
|
|
||||||
setupResponse(saslCall,
|
setupResponse(saslCall,
|
||||||
RpcStatusProto.SUCCESS, null,
|
RpcStatusProto.SUCCESS, null,
|
||||||
RpcWritable.wrap(message), null, null);
|
RpcWritable.wrap(message), null, null);
|
||||||
|
@ -1853,23 +1963,20 @@ public abstract class Server {
|
||||||
|
|
||||||
if (clientVersion >= 9) {
|
if (clientVersion >= 9) {
|
||||||
// Versions >>9 understand the normal response
|
// Versions >>9 understand the normal response
|
||||||
Call fakeCall = new Call(-1, RpcConstants.INVALID_RETRY_COUNT, null,
|
RpcCall fakeCall = new RpcCall(this, -1);
|
||||||
this);
|
|
||||||
setupResponse(fakeCall,
|
setupResponse(fakeCall,
|
||||||
RpcStatusProto.FATAL, RpcErrorCodeProto.FATAL_VERSION_MISMATCH,
|
RpcStatusProto.FATAL, RpcErrorCodeProto.FATAL_VERSION_MISMATCH,
|
||||||
null, VersionMismatch.class.getName(), errMsg);
|
null, VersionMismatch.class.getName(), errMsg);
|
||||||
fakeCall.sendResponse();
|
fakeCall.sendResponse();
|
||||||
} else if (clientVersion >= 3) {
|
} else if (clientVersion >= 3) {
|
||||||
Call fakeCall = new Call(-1, RpcConstants.INVALID_RETRY_COUNT, null,
|
RpcCall fakeCall = new RpcCall(this, -1);
|
||||||
this);
|
|
||||||
// Versions 3 to 8 use older response
|
// Versions 3 to 8 use older response
|
||||||
setupResponseOldVersionFatal(buffer, fakeCall,
|
setupResponseOldVersionFatal(buffer, fakeCall,
|
||||||
null, VersionMismatch.class.getName(), errMsg);
|
null, VersionMismatch.class.getName(), errMsg);
|
||||||
|
|
||||||
fakeCall.sendResponse();
|
fakeCall.sendResponse();
|
||||||
} else if (clientVersion == 2) { // Hadoop 0.18.3
|
} else if (clientVersion == 2) { // Hadoop 0.18.3
|
||||||
Call fakeCall = new Call(0, RpcConstants.INVALID_RETRY_COUNT, null,
|
RpcCall fakeCall = new RpcCall(this, 0);
|
||||||
this);
|
|
||||||
DataOutputStream out = new DataOutputStream(buffer);
|
DataOutputStream out = new DataOutputStream(buffer);
|
||||||
out.writeInt(0); // call ID
|
out.writeInt(0); // call ID
|
||||||
out.writeBoolean(true); // error
|
out.writeBoolean(true); // error
|
||||||
|
@ -1881,7 +1988,7 @@ public abstract class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupHttpRequestOnIpcPortResponse() throws IOException {
|
private void setupHttpRequestOnIpcPortResponse() throws IOException {
|
||||||
Call fakeCall = new Call(0, RpcConstants.INVALID_RETRY_COUNT, null, this);
|
RpcCall fakeCall = new RpcCall(this, 0);
|
||||||
fakeCall.setResponse(ByteBuffer.wrap(
|
fakeCall.setResponse(ByteBuffer.wrap(
|
||||||
RECEIVED_HTTP_REQ_RESPONSE.getBytes(StandardCharsets.UTF_8)));
|
RECEIVED_HTTP_REQ_RESPONSE.getBytes(StandardCharsets.UTF_8)));
|
||||||
fakeCall.sendResponse();
|
fakeCall.sendResponse();
|
||||||
|
@ -2018,7 +2125,7 @@ public abstract class Server {
|
||||||
}
|
}
|
||||||
} catch (WrappedRpcServerException wrse) { // inform client of error
|
} catch (WrappedRpcServerException wrse) { // inform client of error
|
||||||
Throwable ioe = wrse.getCause();
|
Throwable ioe = wrse.getCause();
|
||||||
final Call call = new Call(callId, retry, null, this);
|
final RpcCall call = new RpcCall(this, callId, retry);
|
||||||
setupResponse(call,
|
setupResponse(call,
|
||||||
RpcStatusProto.FATAL, wrse.getRpcErrorCodeProto(), null,
|
RpcStatusProto.FATAL, wrse.getRpcErrorCodeProto(), null,
|
||||||
ioe.getClass().getName(), ioe.getMessage());
|
ioe.getClass().getName(), ioe.getMessage());
|
||||||
|
@ -2115,8 +2222,9 @@ public abstract class Server {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
Call call = new Call(header.getCallId(), header.getRetryCount(),
|
RpcCall call = new RpcCall(this, header.getCallId(),
|
||||||
rpcRequest, this, ProtoUtil.convert(header.getRpcKind()),
|
header.getRetryCount(), rpcRequest,
|
||||||
|
ProtoUtil.convert(header.getRpcKind()),
|
||||||
header.getClientId().toByteArray(), traceScope, callerContext);
|
header.getClientId().toByteArray(), traceScope, callerContext);
|
||||||
|
|
||||||
// Save the priority level assignment by the scheduler
|
// Save the priority level assignment by the scheduler
|
||||||
|
@ -2239,21 +2347,10 @@ public abstract class Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendResponse(Call call) throws IOException {
|
private void sendResponse(RpcCall call) throws IOException {
|
||||||
responder.doRespond(call);
|
responder.doRespond(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void abortResponse(Call call, Throwable t) throws IOException {
|
|
||||||
// clone the call to prevent a race with the other thread stomping
|
|
||||||
// on the response while being sent. the original call is
|
|
||||||
// effectively discarded since the wait count won't hit zero
|
|
||||||
call = new Call(call);
|
|
||||||
setupResponse(call,
|
|
||||||
RpcStatusProto.FATAL, RpcErrorCodeProto.ERROR_RPC_SERVER,
|
|
||||||
null, t.getClass().getName(), StringUtils.stringifyException(t));
|
|
||||||
call.sendResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get service class for connection
|
* Get service class for connection
|
||||||
* @return the serviceClass
|
* @return the serviceClass
|
||||||
|
@ -2304,16 +2401,6 @@ public abstract class Server {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug(Thread.currentThread().getName() + ": " + call + " for RpcKind " + call.rpcKind);
|
LOG.debug(Thread.currentThread().getName() + ": " + call + " for RpcKind " + call.rpcKind);
|
||||||
}
|
}
|
||||||
if (!call.connection.channel.isOpen()) {
|
|
||||||
LOG.info(Thread.currentThread().getName() + ": skipped " + call);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String errorClass = null;
|
|
||||||
String error = null;
|
|
||||||
RpcStatusProto returnStatus = RpcStatusProto.SUCCESS;
|
|
||||||
RpcErrorCodeProto detailedErr = null;
|
|
||||||
Writable value = null;
|
|
||||||
|
|
||||||
CurCall.set(call);
|
CurCall.set(call);
|
||||||
if (call.traceScope != null) {
|
if (call.traceScope != null) {
|
||||||
call.traceScope.reattach();
|
call.traceScope.reattach();
|
||||||
|
@ -2322,53 +2409,11 @@ public abstract class Server {
|
||||||
}
|
}
|
||||||
// always update the current call context
|
// always update the current call context
|
||||||
CallerContext.setCurrent(call.callerContext);
|
CallerContext.setCurrent(call.callerContext);
|
||||||
|
UserGroupInformation remoteUser = call.getRemoteUser();
|
||||||
try {
|
if (remoteUser != null) {
|
||||||
// Make the call as the user via Subject.doAs, thus associating
|
remoteUser.doAs(call);
|
||||||
// the call with the Subject
|
} else {
|
||||||
if (call.connection.user == null) {
|
call.run();
|
||||||
value = call(call.rpcKind, call.connection.protocolName, call.rpcRequest,
|
|
||||||
call.timestamp);
|
|
||||||
} else {
|
|
||||||
value =
|
|
||||||
call.connection.user.doAs
|
|
||||||
(new PrivilegedExceptionAction<Writable>() {
|
|
||||||
@Override
|
|
||||||
public Writable run() throws Exception {
|
|
||||||
// make the call
|
|
||||||
return call(call.rpcKind, call.connection.protocolName,
|
|
||||||
call.rpcRequest, call.timestamp);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
if (e instanceof UndeclaredThrowableException) {
|
|
||||||
e = e.getCause();
|
|
||||||
}
|
|
||||||
logException(LOG, e, call);
|
|
||||||
if (e instanceof RpcServerException) {
|
|
||||||
RpcServerException rse = ((RpcServerException)e);
|
|
||||||
returnStatus = rse.getRpcStatusProto();
|
|
||||||
detailedErr = rse.getRpcErrorCodeProto();
|
|
||||||
} else {
|
|
||||||
returnStatus = RpcStatusProto.ERROR;
|
|
||||||
detailedErr = RpcErrorCodeProto.ERROR_APPLICATION;
|
|
||||||
}
|
|
||||||
errorClass = e.getClass().getName();
|
|
||||||
error = StringUtils.stringifyException(e);
|
|
||||||
// Remove redundant error class name from the beginning of the stack trace
|
|
||||||
String exceptionHdr = errorClass + ": ";
|
|
||||||
if (error.startsWith(exceptionHdr)) {
|
|
||||||
error = error.substring(exceptionHdr.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CurCall.set(null);
|
|
||||||
synchronized (call.connection.responseQueue) {
|
|
||||||
setupResponse(call, returnStatus, detailedErr,
|
|
||||||
value, errorClass, error);
|
|
||||||
call.sendResponse();
|
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
if (running) { // unexpected -- log it
|
if (running) { // unexpected -- log it
|
||||||
|
@ -2385,6 +2430,7 @@ public abstract class Server {
|
||||||
StringUtils.stringifyException(e));
|
StringUtils.stringifyException(e));
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
CurCall.set(null);
|
||||||
IOUtils.cleanup(LOG, traceScope);
|
IOUtils.cleanup(LOG, traceScope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2586,7 +2632,7 @@ public abstract class Server {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void setupResponse(
|
private void setupResponse(
|
||||||
Call call, RpcStatusProto status, RpcErrorCodeProto erCode,
|
RpcCall call, RpcStatusProto status, RpcErrorCodeProto erCode,
|
||||||
Writable rv, String errorClass, String error)
|
Writable rv, String errorClass, String error)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
RpcResponseHeaderProto.Builder headerBuilder =
|
RpcResponseHeaderProto.Builder headerBuilder =
|
||||||
|
@ -2620,7 +2666,7 @@ public abstract class Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupResponse(Call call,
|
private void setupResponse(RpcCall call,
|
||||||
RpcResponseHeaderProto header, Writable rv) throws IOException {
|
RpcResponseHeaderProto header, Writable rv) throws IOException {
|
||||||
ResponseBuffer buf = responseBuffer.get().reset();
|
ResponseBuffer buf = responseBuffer.get().reset();
|
||||||
try {
|
try {
|
||||||
|
@ -2654,7 +2700,7 @@ public abstract class Server {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void setupResponseOldVersionFatal(ByteArrayOutputStream response,
|
private void setupResponseOldVersionFatal(ByteArrayOutputStream response,
|
||||||
Call call,
|
RpcCall call,
|
||||||
Writable rv, String errorClass, String error)
|
Writable rv, String errorClass, String error)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final int OLD_VERSION_FATAL_STATUS = -1;
|
final int OLD_VERSION_FATAL_STATUS = -1;
|
||||||
|
@ -2667,7 +2713,7 @@ public abstract class Server {
|
||||||
call.setResponse(ByteBuffer.wrap(response.toByteArray()));
|
call.setResponse(ByteBuffer.wrap(response.toByteArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void wrapWithSasl(Call call) throws IOException {
|
private void wrapWithSasl(RpcCall call) throws IOException {
|
||||||
if (call.connection.saslServer != null) {
|
if (call.connection.saslServer != null) {
|
||||||
byte[] token = call.rpcResponse.array();
|
byte[] token = call.rpcResponse.array();
|
||||||
// synchronization may be needed since there can be multiple Handler
|
// synchronization may be needed since there can be multiple Handler
|
||||||
|
|
Loading…
Reference in New Issue