HBASE-21061 Fix inconsistent synchronization in RpcServer

move variables that we don't need synchronized access to out of the critical block.

Signed-off-by: Mike Drob <mdrob@apache.org>
This commit is contained in:
Sean Busbey 2018-08-25 21:28:03 -05:00
parent d07cab18a6
commit 3e45e0202b
1 changed files with 84 additions and 74 deletions

View File

@ -1640,7 +1640,7 @@ public class RpcServer implements RpcServerInterface, ConfigurationObserver {
* @throws IOException
* @throws InterruptedException
*/
public synchronized int readAndProcess() throws IOException, InterruptedException {
public int readAndProcess() throws IOException, InterruptedException {
// If we have not read the connection setup preamble, look to see if that is on the wire.
if (!connectionPreambleRead) {
int count = readPreamble();
@ -1668,6 +1668,16 @@ public class RpcServer implements RpcServerInterface, ConfigurationObserver {
}
}
final boolean useWrap = this.useWrap;
final BlockingService service = this.service;
final boolean headerAndPreambleRead = connectionHeaderRead && connectionPreambleRead;
final boolean canUseRequestTooBig = headerAndPreambleRead &&
VersionInfoUtil.hasMinimumVersion(connectionHeader.getVersionInfo(),
RequestTooBigException.MAJOR_VERSION, RequestTooBigException.MINOR_VERSION);
// we're guarding against data being modified concurrently
// while trying to keep other instance members out of the block
synchronized(this) {
// We have read a length and we have read the preamble. It is either the connection header
// or it is a request.
if (data == null) {
@ -1691,7 +1701,7 @@ public class RpcServer implements RpcServerInterface, ConfigurationObserver {
+ "\" on server to override this limit (not recommended)";
LOG.warn(msg);
if (connectionHeaderRead && connectionPreambleRead) {
if (headerAndPreambleRead) {
incRpcCount();
// Construct InputStream for the non-blocking SocketChannel
// We need the InputStream because we want to read only the request header
@ -1714,13 +1724,12 @@ public class RpcServer implements RpcServerInterface, ConfigurationObserver {
RequestHeader header = (RequestHeader) builder.build();
// Notify the client about the offending request
Call reqTooBig = new Call(header.getCallId(), this.service, null, null, null,
Call reqTooBig = new Call(header.getCallId(), service, null, null, null,
null, this, responder, 0, null, this.addr,0);
metrics.exception(REQUEST_TOO_BIG_EXCEPTION);
// Make sure the client recognizes the underlying exception
// Otherwise, throw a DoNotRetryIOException.
if (VersionInfoUtil.hasMinimumVersion(connectionHeader.getVersionInfo(),
RequestTooBigException.MAJOR_VERSION, RequestTooBigException.MINOR_VERSION)) {
if (canUseRequestTooBig) {
setupResponse(null, reqTooBig, REQUEST_TOO_BIG_EXCEPTION, msg);
} else {
setupResponse(null, reqTooBig, new DoNotRetryIOException(), msg);
@ -1748,6 +1757,7 @@ public class RpcServer implements RpcServerInterface, ConfigurationObserver {
if (count >= 0 && data.remaining() == 0) { // count==0 if dataLength == 0
process();
}
}
return count;
}