EPOLL Cached ECONNREFUSED Exception
Motivation: ECONNREFUSED can be a common type of exception when attempting to finish the connection process. Generating a new exception each time can be costly and quickly bloat memory usage. Modifications: - Expose ECONNREFUSED from JNI and cache this exception in Socket.finishConnect Result: ECONNREFUSED during finish connect doesn't create a new exception each time.
This commit is contained in:
parent
44b942e507
commit
df033e150c
@ -100,6 +100,10 @@ static jint netty_unix_errors_errnoEINPROGRESS(JNIEnv* env, jclass clazz) {
|
||||
return EINPROGRESS;
|
||||
}
|
||||
|
||||
static jint netty_unix_errors_errorECONNREFUSED(JNIEnv* env, jclass clazz) {
|
||||
return ECONNREFUSED;
|
||||
}
|
||||
|
||||
static jstring netty_unix_errors_strError(JNIEnv* env, jclass clazz, jint error) {
|
||||
return (*env)->NewStringUTF(env, strerror(error));
|
||||
}
|
||||
@ -114,6 +118,7 @@ static const JNINativeMethod statically_referenced_fixed_method_table[] = {
|
||||
{ "errnoEAGAIN", "()I", (void *) netty_unix_errors_errnoEAGAIN },
|
||||
{ "errnoEWOULDBLOCK", "()I", (void *) netty_unix_errors_errnoEWOULDBLOCK },
|
||||
{ "errnoEINPROGRESS", "()I", (void *) netty_unix_errors_errnoEINPROGRESS },
|
||||
{ "errorECONNREFUSED", "()I", (void *) netty_unix_errors_errorECONNREFUSED },
|
||||
{ "strError", "(I)Ljava/lang/String;", (void *) netty_unix_errors_strError }
|
||||
};
|
||||
static const jint statically_referenced_fixed_method_table_size = sizeof(statically_referenced_fixed_method_table) / sizeof(statically_referenced_fixed_method_table[0]);
|
||||
|
@ -28,6 +28,7 @@ import static io.netty.channel.unix.ErrorsStaticallyReferencedJniMethods.errnoEI
|
||||
import static io.netty.channel.unix.ErrorsStaticallyReferencedJniMethods.errnoENOTCONN;
|
||||
import static io.netty.channel.unix.ErrorsStaticallyReferencedJniMethods.errnoEPIPE;
|
||||
import static io.netty.channel.unix.ErrorsStaticallyReferencedJniMethods.errnoEWOULDBLOCK;
|
||||
import static io.netty.channel.unix.ErrorsStaticallyReferencedJniMethods.errorECONNREFUSED;
|
||||
import static io.netty.channel.unix.ErrorsStaticallyReferencedJniMethods.strError;
|
||||
|
||||
/**
|
||||
@ -43,6 +44,7 @@ public final class Errors {
|
||||
public static final int ERRNO_EAGAIN_NEGATIVE = -errnoEAGAIN();
|
||||
public static final int ERRNO_EWOULDBLOCK_NEGATIVE = -errnoEWOULDBLOCK();
|
||||
public static final int ERRNO_EINPROGRESS_NEGATIVE = -errnoEINPROGRESS();
|
||||
public static final int ERROR_ECONNREFUSED_NEGATIVE = -errorECONNREFUSED();
|
||||
|
||||
/**
|
||||
* Holds the mappings for errno codes to String messages.
|
||||
@ -69,6 +71,19 @@ public final class Errors {
|
||||
}
|
||||
}
|
||||
|
||||
static final class NativeConnectException extends ConnectException {
|
||||
private static final long serialVersionUID = -5532328671712318161L;
|
||||
private final int expectedErr;
|
||||
NativeConnectException(String method, int expectedErr) {
|
||||
super(method);
|
||||
this.expectedErr = expectedErr;
|
||||
}
|
||||
|
||||
int expectedErr() {
|
||||
return expectedErr;
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
for (int i = 0; i < ERRORS.length; i++) {
|
||||
// This is ok as strerror returns 'Unknown error i' when the message is not known.
|
||||
@ -76,8 +91,12 @@ public final class Errors {
|
||||
}
|
||||
}
|
||||
|
||||
static ConnectException newConnectException(String method, int err) {
|
||||
return new ConnectException(method + "() failed: " + ERRORS[-err]);
|
||||
static void throwConnectException(String method, NativeConnectException refusedCause, int err)
|
||||
throws ConnectException {
|
||||
if (err == refusedCause.expectedErr()) {
|
||||
throw refusedCause;
|
||||
}
|
||||
throw new ConnectException(method + "() failed: " + ERRORS[-err]);
|
||||
}
|
||||
|
||||
public static NativeIoException newConnectionResetException(String method, int errnoNegative) {
|
||||
|
@ -37,5 +37,6 @@ final class ErrorsStaticallyReferencedJniMethods {
|
||||
static native int errnoEAGAIN();
|
||||
static native int errnoEWOULDBLOCK();
|
||||
static native int errnoEINPROGRESS();
|
||||
static native int errorECONNREFUSED();
|
||||
static native String strError(int err);
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ package io.netty.channel.unix;
|
||||
|
||||
import io.netty.channel.ChannelException;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.ThrowableUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Inet6Address;
|
||||
@ -31,36 +30,43 @@ import static io.netty.channel.unix.Errors.ERRNO_EAGAIN_NEGATIVE;
|
||||
import static io.netty.channel.unix.Errors.ERRNO_EINPROGRESS_NEGATIVE;
|
||||
import static io.netty.channel.unix.Errors.ERRNO_EWOULDBLOCK_NEGATIVE;
|
||||
import static io.netty.channel.unix.Errors.ioResult;
|
||||
import static io.netty.channel.unix.Errors.newConnectException;
|
||||
import static io.netty.channel.unix.Errors.throwConnectException;
|
||||
import static io.netty.channel.unix.Errors.newIOException;
|
||||
import static io.netty.channel.unix.NativeInetAddress.address;
|
||||
import static io.netty.channel.unix.NativeInetAddress.ipv4MappedIpv6Address;
|
||||
import static io.netty.util.internal.ThrowableUtil.unknownStackTrace;
|
||||
|
||||
/**
|
||||
* Provides a JNI bridge to native socket operations.
|
||||
* <strong>Internal usage only!</strong>
|
||||
*/
|
||||
public final class Socket extends FileDescriptor {
|
||||
private static final ClosedChannelException SHUTDOWN_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace(
|
||||
private static final ClosedChannelException SHUTDOWN_CLOSED_CHANNEL_EXCEPTION = unknownStackTrace(
|
||||
new ClosedChannelException(), Socket.class, "shutdown(...)");
|
||||
private static final ClosedChannelException SEND_TO_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace(
|
||||
private static final ClosedChannelException SEND_TO_CLOSED_CHANNEL_EXCEPTION = unknownStackTrace(
|
||||
new ClosedChannelException(), Socket.class, "sendTo(...)");
|
||||
private static final ClosedChannelException SEND_TO_ADDRESS_CLOSED_CHANNEL_EXCEPTION =
|
||||
ThrowableUtil.unknownStackTrace(new ClosedChannelException(), Socket.class, "sendToAddress(...)");
|
||||
unknownStackTrace(new ClosedChannelException(), Socket.class, "sendToAddress(...)");
|
||||
private static final ClosedChannelException SEND_TO_ADDRESSES_CLOSED_CHANNEL_EXCEPTION =
|
||||
ThrowableUtil.unknownStackTrace(new ClosedChannelException(), Socket.class, "sendToAddresses(...)");
|
||||
private static final Errors.NativeIoException SEND_TO_CONNECTION_RESET_EXCEPTION = ThrowableUtil.unknownStackTrace(
|
||||
unknownStackTrace(new ClosedChannelException(), Socket.class, "sendToAddresses(...)");
|
||||
private static final Errors.NativeIoException SEND_TO_CONNECTION_RESET_EXCEPTION = unknownStackTrace(
|
||||
Errors.newConnectionResetException("syscall:sendto(...)", Errors.ERRNO_EPIPE_NEGATIVE),
|
||||
Socket.class, "sendTo(...)");
|
||||
private static final Errors.NativeIoException SEND_TO_ADDRESS_CONNECTION_RESET_EXCEPTION =
|
||||
ThrowableUtil.unknownStackTrace(Errors.newConnectionResetException("syscall:sendto(...)",
|
||||
unknownStackTrace(Errors.newConnectionResetException("syscall:sendto(...)",
|
||||
Errors.ERRNO_EPIPE_NEGATIVE), Socket.class, "sendToAddress(...)");
|
||||
private static final Errors.NativeIoException CONNECTION_RESET_EXCEPTION_SENDMSG = ThrowableUtil.unknownStackTrace(
|
||||
private static final Errors.NativeIoException CONNECTION_RESET_EXCEPTION_SENDMSG = unknownStackTrace(
|
||||
Errors.newConnectionResetException("syscall:sendmsg(...)",
|
||||
Errors.ERRNO_EPIPE_NEGATIVE), Socket.class, "sendToAddresses(...)");
|
||||
private static final Errors.NativeIoException CONNECTION_NOT_CONNECTED_SHUTDOWN_EXCEPTION =
|
||||
ThrowableUtil.unknownStackTrace(Errors.newConnectionResetException("syscall:shutdown(...)",
|
||||
unknownStackTrace(Errors.newConnectionResetException("syscall:shutdown(...)",
|
||||
Errors.ERRNO_ENOTCONN_NEGATIVE), Socket.class, "shutdown(...)");
|
||||
private static final Errors.NativeConnectException FINISH_CONNECT_REFUSED_EXCEPTION =
|
||||
unknownStackTrace(new Errors.NativeConnectException("syscall:getsockopt(...)",
|
||||
Errors.ERROR_ECONNREFUSED_NEGATIVE), Socket.class, "finishConnect(...)");
|
||||
private static final Errors.NativeConnectException CONNECT_REFUSED_EXCEPTION =
|
||||
unknownStackTrace(new Errors.NativeConnectException("syscall:connect(...)",
|
||||
Errors.ERROR_ECONNREFUSED_NEGATIVE), Socket.class, "connect(...)");
|
||||
public Socket(int fd) {
|
||||
super(fd);
|
||||
}
|
||||
@ -199,7 +205,7 @@ public final class Socket extends FileDescriptor {
|
||||
// connect not complete yet need to wait for EPOLLOUT event
|
||||
return false;
|
||||
}
|
||||
throw newConnectException("connect", res);
|
||||
throwConnectException("connect", CONNECT_REFUSED_EXCEPTION, res);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -211,7 +217,7 @@ public final class Socket extends FileDescriptor {
|
||||
// connect still in progress
|
||||
return false;
|
||||
}
|
||||
throw newConnectException("finishConnect", res);
|
||||
throwConnectException("finishConnect", FINISH_CONNECT_REFUSED_EXCEPTION, res);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user