提交 0e232e1d 编写于 作者: I igerasim

8164147: Improve streaming socket output

Reviewed-by: chegar, igerasim
上级 c5df4fc8
/* /*
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -155,11 +155,12 @@ class SocketInputStream extends FileInputStream ...@@ -155,11 +155,12 @@ class SocketInputStream extends FileInputStream
} }
// bounds check // bounds check
if (length <= 0 || off < 0 || off + length > b.length) { if (length <= 0 || off < 0 || length > b.length - off) {
if (length == 0) { if (length == 0) {
return 0; return 0;
} }
throw new ArrayIndexOutOfBoundsException(); throw new ArrayIndexOutOfBoundsException("length == " + length
+ " off == " + off + " buffer length == " + b.length);
} }
boolean gotReset = false; boolean gotReset = false;
......
/* /*
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -97,11 +97,13 @@ class SocketOutputStream extends FileOutputStream ...@@ -97,11 +97,13 @@ class SocketOutputStream extends FileOutputStream
*/ */
private void socketWrite(byte b[], int off, int len) throws IOException { private void socketWrite(byte b[], int off, int len) throws IOException {
if (len <= 0 || off < 0 || off + len > b.length) {
if (len <= 0 || off < 0 || len > b.length - off) {
if (len == 0) { if (len == 0) {
return; return;
} }
throw new ArrayIndexOutOfBoundsException(); throw new ArrayIndexOutOfBoundsException("len == " + len
+ " off == " + off + " buffer length == " + b.length);
} }
FileDescriptor fd = impl.acquireFD(); FileDescriptor fd = impl.acquireFD();
......
...@@ -103,31 +103,35 @@ Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this, ...@@ -103,31 +103,35 @@ Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this,
int llen = chunkLen; int llen = chunkLen;
(*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP); (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
while(llen > 0) { if ((*env)->ExceptionCheck(env)) {
int n = NET_Send(fd, bufP + loff, llen, 0); break;
if (n > 0) { } else {
llen -= n; while(llen > 0) {
loff += n; int n = NET_Send(fd, bufP + loff, llen, 0);
continue; if (n > 0) {
} llen -= n;
if (n == JVM_IO_INTR) { loff += n;
JNU_ThrowByName(env, "java/io/InterruptedIOException", 0); continue;
} else { }
if (errno == ECONNRESET) { if (n == JVM_IO_INTR) {
JNU_ThrowByName(env, "sun/net/ConnectionResetException", JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
"Connection reset");
} else { } else {
NET_ThrowByNameWithLastError(env, "java/net/SocketException", if (errno == ECONNRESET) {
"Write failed"); JNU_ThrowByName(env, "sun/net/ConnectionResetException",
"Connection reset");
} else {
NET_ThrowByNameWithLastError(env, "java/net/SocketException",
"Write failed");
}
} }
if (bufP != BUF) {
free(bufP);
}
return;
} }
if (bufP != BUF) { len -= chunkLen;
free(bufP); off += chunkLen;
}
return;
} }
len -= chunkLen;
off += chunkLen;
} }
if (bufP != BUF) { if (bufP != BUF) {
......
/* /*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -100,66 +100,69 @@ Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this, ...@@ -100,66 +100,69 @@ Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this,
int retry = 0; int retry = 0;
(*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP); (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
if ((*env)->ExceptionCheck(env)) {
while(llen > 0) { break;
int n = send(fd, bufP + loff, llen, 0); } else {
if (n > 0) { while(llen > 0) {
llen -= n; int n = send(fd, bufP + loff, llen, 0);
loff += n; if (n > 0) {
continue; llen -= n;
} loff += n;
/*
* Due to a bug in Windows Sockets (observed on NT and Windows
* 2000) it may be necessary to retry the send. The issue is that
* on blocking sockets send/WSASend is supposed to block if there
* is insufficient buffer space available. If there are a large
* number of threads blocked on write due to congestion then it's
* possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
* The workaround we use is to retry the send. If we have a
* large buffer to send (>2k) then we retry with a maximum of
* 2k buffer. If we hit the issue with <=2k buffer then we backoff
* for 1 second and retry again. We repeat this up to a reasonable
* limit before bailing out and throwing an exception. In load
* conditions we've observed that the send will succeed after 2-3
* attempts but this depends on network buffers associated with
* other sockets draining.
*/
if (WSAGetLastError() == WSAENOBUFS) {
if (llen > MAX_BUFFER_LEN) {
buflen = MAX_BUFFER_LEN;
chunkLen = MAX_BUFFER_LEN;
llen = MAX_BUFFER_LEN;
continue; continue;
} }
if (retry >= 30) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", /*
"No buffer space available - exhausted attempts to queue buffer"); * Due to a bug in Windows Sockets (observed on NT and Windows
if (bufP != BUF) { * 2000) it may be necessary to retry the send. The issue is that
free(bufP); * on blocking sockets send/WSASend is supposed to block if there
* is insufficient buffer space available. If there are a large
* number of threads blocked on write due to congestion then it's
* possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
* The workaround we use is to retry the send. If we have a
* large buffer to send (>2k) then we retry with a maximum of
* 2k buffer. If we hit the issue with <=2k buffer then we backoff
* for 1 second and retry again. We repeat this up to a reasonable
* limit before bailing out and throwing an exception. In load
* conditions we've observed that the send will succeed after 2-3
* attempts but this depends on network buffers associated with
* other sockets draining.
*/
if (WSAGetLastError() == WSAENOBUFS) {
if (llen > MAX_BUFFER_LEN) {
buflen = MAX_BUFFER_LEN;
chunkLen = MAX_BUFFER_LEN;
llen = MAX_BUFFER_LEN;
continue;
}
if (retry >= 30) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
"No buffer space available - exhausted attempts to queue buffer");
if (bufP != BUF) {
free(bufP);
}
return;
} }
return; Sleep(1000);
retry++;
continue;
} }
Sleep(1000);
retry++;
continue;
}
/* /*
* Send failed - can be caused by close or write error. * Send failed - can be caused by close or write error.
*/ */
if (WSAGetLastError() == WSAENOTSOCK) { if (WSAGetLastError() == WSAENOTSOCK) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
} else { } else {
NET_ThrowCurrent(env, "socket write error"); NET_ThrowCurrent(env, "socket write error");
} }
if (bufP != BUF) { if (bufP != BUF) {
free(bufP); free(bufP);
}
return;
} }
return; len -= chunkLen;
off += chunkLen;
} }
len -= chunkLen;
off += chunkLen;
} }
if (bufP != BUF) { if (bufP != BUF) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册