|
@@ -72,6 +72,7 @@ import org.apache.hadoop.conf.Configuration.IntegerRanges;
|
|
import org.apache.hadoop.fs.CommonConfigurationKeys;
|
|
import org.apache.hadoop.fs.CommonConfigurationKeys;
|
|
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
|
|
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
|
|
import org.apache.hadoop.io.BytesWritable;
|
|
import org.apache.hadoop.io.BytesWritable;
|
|
|
|
+import org.apache.hadoop.io.DataOutputBuffer;
|
|
import org.apache.hadoop.io.IntWritable;
|
|
import org.apache.hadoop.io.IntWritable;
|
|
import org.apache.hadoop.io.Writable;
|
|
import org.apache.hadoop.io.Writable;
|
|
import org.apache.hadoop.io.WritableUtils;
|
|
import org.apache.hadoop.io.WritableUtils;
|
|
@@ -106,6 +107,7 @@ import org.apache.hadoop.util.StringUtils;
|
|
import org.apache.hadoop.util.Time;
|
|
import org.apache.hadoop.util.Time;
|
|
|
|
|
|
import com.google.common.annotations.VisibleForTesting;
|
|
import com.google.common.annotations.VisibleForTesting;
|
|
|
|
+import com.google.protobuf.CodedOutputStream;
|
|
|
|
|
|
/** An abstract IPC service. IPC calls take a single {@link Writable} as a
|
|
/** An abstract IPC service. IPC calls take a single {@link Writable} as a
|
|
* parameter, and return a {@link Writable} as their value. A service runs on
|
|
* parameter, and return a {@link Writable} as their value. A service runs on
|
|
@@ -199,7 +201,8 @@ public abstract class Server {
|
|
// 6 : Made RPC Request header explicit
|
|
// 6 : Made RPC Request header explicit
|
|
// 7 : Changed Ipc Connection Header to use Protocol buffers
|
|
// 7 : Changed Ipc Connection Header to use Protocol buffers
|
|
// 8 : SASL server always sends a final response
|
|
// 8 : SASL server always sends a final response
|
|
- public static final byte CURRENT_VERSION = 8;
|
|
|
|
|
|
+ // 9 : Changes to protocol for HADOOP-8990
|
|
|
|
+ public static final byte CURRENT_VERSION = 9;
|
|
|
|
|
|
/**
|
|
/**
|
|
* Initial and max size of response buffer
|
|
* Initial and max size of response buffer
|
|
@@ -1519,10 +1522,15 @@ public abstract class Server {
|
|
" cannot communicate with client version " + clientVersion;
|
|
" cannot communicate with client version " + clientVersion;
|
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
|
|
|
|
- if (clientVersion >= 3) {
|
|
|
|
|
|
+ if (clientVersion >= 9) {
|
|
|
|
+ // Versions >>9 understand the normal response
|
|
Call fakeCall = new Call(-1, null, this);
|
|
Call fakeCall = new Call(-1, null, this);
|
|
- // Versions 3 and greater can interpret this exception
|
|
|
|
- // response in the same manner
|
|
|
|
|
|
+ setupResponse(buffer, fakeCall, RpcStatusProto.FATAL,
|
|
|
|
+ null, VersionMismatch.class.getName(), errMsg);
|
|
|
|
+ responder.doRespond(fakeCall);
|
|
|
|
+ } else if (clientVersion >= 3) {
|
|
|
|
+ Call fakeCall = new Call(-1, null, this);
|
|
|
|
+ // Versions 3 to 8 use older response
|
|
setupResponseOldVersionFatal(buffer, fakeCall,
|
|
setupResponseOldVersionFatal(buffer, fakeCall,
|
|
null, VersionMismatch.class.getName(), errMsg);
|
|
null, VersionMismatch.class.getName(), errMsg);
|
|
|
|
|
|
@@ -2020,17 +2028,34 @@ public abstract class Server {
|
|
throws IOException {
|
|
throws IOException {
|
|
responseBuf.reset();
|
|
responseBuf.reset();
|
|
DataOutputStream out = new DataOutputStream(responseBuf);
|
|
DataOutputStream out = new DataOutputStream(responseBuf);
|
|
- RpcResponseHeaderProto.Builder response =
|
|
|
|
|
|
+ RpcResponseHeaderProto.Builder headerBuilder =
|
|
RpcResponseHeaderProto.newBuilder();
|
|
RpcResponseHeaderProto.newBuilder();
|
|
- response.setCallId(call.callId);
|
|
|
|
- response.setStatus(status);
|
|
|
|
- response.setServerIpcVersionNum(Server.CURRENT_VERSION);
|
|
|
|
-
|
|
|
|
|
|
+ headerBuilder.setCallId(call.callId);
|
|
|
|
+ headerBuilder.setStatus(status);
|
|
|
|
+ headerBuilder.setServerIpcVersionNum(Server.CURRENT_VERSION);
|
|
|
|
|
|
if (status == RpcStatusProto.SUCCESS) {
|
|
if (status == RpcStatusProto.SUCCESS) {
|
|
|
|
+ RpcResponseHeaderProto header = headerBuilder.build();
|
|
|
|
+ final int headerLen = header.getSerializedSize();
|
|
|
|
+ int fullLength = CodedOutputStream.computeRawVarint32Size(headerLen) +
|
|
|
|
+ headerLen;
|
|
try {
|
|
try {
|
|
- response.build().writeDelimitedTo(out);
|
|
|
|
- rv.write(out);
|
|
|
|
|
|
+ if (rv instanceof ProtobufRpcEngine.RpcWrapper) {
|
|
|
|
+ ProtobufRpcEngine.RpcWrapper resWrapper =
|
|
|
|
+ (ProtobufRpcEngine.RpcWrapper) rv;
|
|
|
|
+ fullLength += resWrapper.getLength();
|
|
|
|
+ out.writeInt(fullLength);
|
|
|
|
+ header.writeDelimitedTo(out);
|
|
|
|
+ rv.write(out);
|
|
|
|
+ } else { // Have to serialize to buffer to get len
|
|
|
|
+ final DataOutputBuffer buf = new DataOutputBuffer();
|
|
|
|
+ rv.write(buf);
|
|
|
|
+ byte[] data = buf.getData();
|
|
|
|
+ fullLength += buf.getLength();
|
|
|
|
+ out.writeInt(fullLength);
|
|
|
|
+ header.writeDelimitedTo(out);
|
|
|
|
+ out.write(data, 0, buf.getLength());
|
|
|
|
+ }
|
|
} catch (Throwable t) {
|
|
} catch (Throwable t) {
|
|
LOG.warn("Error serializing call response for call " + call, t);
|
|
LOG.warn("Error serializing call response for call " + call, t);
|
|
// Call back to same function - this is OK since the
|
|
// Call back to same function - this is OK since the
|
|
@@ -2042,9 +2067,14 @@ public abstract class Server {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
} else { // Rpc Failure
|
|
} else { // Rpc Failure
|
|
- response.setExceptionClassName(errorClass);
|
|
|
|
- response.setErrorMsg(error);
|
|
|
|
- response.build().writeDelimitedTo(out);
|
|
|
|
|
|
+ headerBuilder.setExceptionClassName(errorClass);
|
|
|
|
+ headerBuilder.setErrorMsg(error);
|
|
|
|
+ RpcResponseHeaderProto header = headerBuilder.build();
|
|
|
|
+ int headerLen = header.getSerializedSize();
|
|
|
|
+ final int fullLength =
|
|
|
|
+ CodedOutputStream.computeRawVarint32Size(headerLen) + headerLen;
|
|
|
|
+ out.writeInt(fullLength);
|
|
|
|
+ header.writeDelimitedTo(out);
|
|
}
|
|
}
|
|
if (call.connection.useWrap) {
|
|
if (call.connection.useWrap) {
|
|
wrapWithSasl(responseBuf, call);
|
|
wrapWithSasl(responseBuf, call);
|