Author: markt
Date: Thu Aug 16 08:55:55 2018
New Revision: 1838163
URL: http://svn.apache.org/viewvc?rev=1838163&view=rev
Log:
Rename methods and expand comments to make the code easier to follow.
Add some TODOs where it appears further work is required.
Modified:
tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
tomcat/trunk/java/org/apache/tomcat/util/net/SocketWrapperBase.java
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1838163&r1=1838162&r2=1838163&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Thu Aug 16
08:55:55 2018
@@ -2576,9 +2576,9 @@ public class AprEndpoint extends Abstrac
@Override
- protected void writeByteBufferBlocking(ByteBuffer from) throws
IOException {
+ protected void writeBlockingDirect(ByteBuffer from) throws IOException
{
if (from.isDirect()) {
- super.writeByteBufferBlocking(from);
+ super.writeBlockingDirect(from);
} else {
// The socket write buffer capacity is socket.appWriteBufSize
ByteBuffer writeBuffer = socketBufferHandler.getWriteBuffer();
@@ -2598,9 +2598,9 @@ public class AprEndpoint extends Abstrac
@Override
- protected boolean writeByteBufferNonBlocking(ByteBuffer from) throws
IOException {
+ protected boolean writeNonBlockingDirect(ByteBuffer from) throws
IOException {
if (from.isDirect()) {
- return super.writeByteBufferNonBlocking(from);
+ return super.writeNonBlockingDirect(from);
} else {
// The socket write buffer capacity is socket.appWriteBufSize
ByteBuffer writeBuffer = socketBufferHandler.getWriteBuffer();
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SocketWrapperBase.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SocketWrapperBase.java?rev=1838163&r1=1838162&r2=1838163&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SocketWrapperBase.java
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SocketWrapperBase.java Thu Aug
16 08:55:55 2018
@@ -358,9 +358,24 @@ public abstract class SocketWrapperBase<
public abstract void close() throws IOException;
public abstract boolean isClosed();
+
/**
- * Writes the provided data to the socket, buffering any remaining data if
- * used in non-blocking mode.
+ * Writes the provided data to the socket write buffer. If the socket write
+ * buffer fills during the write, the content of the socket write buffer is
+ * written to the network and this method starts to fill the socket write
+ * buffer again. Depending on the size of the data to write, there may be
+ * multiple writes to the network.
+ * <p>
+ * Non-blocking writes must return immediately and the byte array holding
+ * the data to be written must be immediately available for re-use. It may
+ * not be possible to write sufficient data to the network to allow this to
+ * happen. In this case data that cannot be written to the network and
+ * cannot be held by the socket buffer is stored in the non-blocking write
+ * buffer.
+ * <p>
+ * Note: There is an implementation assumption that, before switching from
+ * non-blocking writes to blocking writes, any data remaining in the
+ * non-blocking write buffer will have been written to the network.
*
* @param block <code>true</code> if a blocking write should be used,
* otherwise a non-blocking write will be used
@@ -375,10 +390,18 @@ public abstract class SocketWrapperBase<
return;
}
- // While the implementations for blocking and non-blocking writes are
- // very similar they have been split into separate methods to allow
- // sub-classes to override them individually. NIO2, for example,
- // overrides the non-blocking write but not the blocking write.
+ /*
+ * While the implementations for blocking and non-blocking writes are
+ * very similar they have been split into separate methods:
+ * - To allow sub-classes to override them individually. NIO2, for
+ * example, overrides the non-blocking write but not the blocking
+ * write.
+ * - To enable a marginally more efficient implemented for blocking
+ * writes which do not require the additional checks related to the
+ * use of the non-blocking write buffer
+ * TODO: Explore re-factoring options to remove the split into
+ * separate methods
+ */
if (block) {
writeBlocking(buf, off, len);
} else {
@@ -388,8 +411,22 @@ public abstract class SocketWrapperBase<
/**
- * Writes the provided data to the socket, buffering any remaining data if
- * used in non-blocking mode.
+ * Writes the provided data to the socket write buffer. If the socket write
+ * buffer fills during the write, the content of the socket write buffer is
+ * written to the network and this method starts to fill the socket write
+ * buffer again. Depending on the size of the data to write, there may be
+ * multiple writes to the network.
+ * <p>
+ * Non-blocking writes must return immediately and the ByteBuffer holding
+ * the data to be written must be immediately available for re-use. It may
+ * not be possible to write sufficient data to the network to allow this to
+ * happen. In this case data that cannot be written to the network and
+ * cannot be held by the socket buffer is stored in the non-blocking write
+ * buffer.
+ * <p>
+ * Note: There is an implementation assumption that, before switching from
+ * non-blocking writes to blocking writes, any data remaining in the
+ * non-blocking write buffer will have been written to the network.
*
* @param block <code>true</code> if a blocking write should be used,
* otherwise a non-blocking write will be used
@@ -402,10 +439,18 @@ public abstract class SocketWrapperBase<
return;
}
- // While the implementations for blocking and non-blocking writes are
- // very similar they have been split into separate methods to allow
- // sub-classes to override them individually. NIO2, for example,
- // overrides the non-blocking write but not the blocking write.
+ /*
+ * While the implementations for blocking and non-blocking writes are
+ * very similar they have been split into separate methods:
+ * - To allow sub-classes to override them individually. NIO2, for
+ * example, overrides the non-blocking write but not the blocking
+ * write.
+ * - To enable a marginally more efficient implemented for blocking
+ * writes which do not require the additional checks related to the
+ * use of the non-blocking write buffer
+ * TODO: Explore re-factoring options to remove the split into
+ * separate methods
+ */
if (block) {
writeBlocking(from);
} else {
@@ -415,9 +460,13 @@ public abstract class SocketWrapperBase<
/**
- * Transfers the data to the socket write buffer (writing that data to the
- * socket if the buffer fills up using a blocking write) until all the data
- * has been transferred and space remains in the socket write buffer.
+ * Writes the provided data to the socket write buffer. If the socket write
+ * buffer fills during the write, the content of the socket write buffer is
+ * written to the network using a blocking write. Once that blocking write
+ * is complete, this method starts to fill the socket write buffer again.
+ * Depending on the size of the data to write, there may be multiple writes
+ * to the network. On completion of this method there will always be space
+ * remaining in the socket write buffer.
*
* @param buf The byte array containing the data to be written
* @param off The offset within the byte array of the data to be written
@@ -426,13 +475,6 @@ public abstract class SocketWrapperBase<
* @throws IOException If an IO error occurs during the write
*/
protected void writeBlocking(byte[] buf, int off, int len) throws
IOException {
- // Note: There is an implementation assumption that if the switch from
- // non-blocking to blocking has been made then any pending
- // non-blocking writes were flushed at the time the switch
- // occurred.
-
- // Keep writing until all the data has been transferred to the socket
- // write buffer and space remains in that buffer
socketBufferHandler.configureWriteBufferForWrite();
int thisTime = transfer(buf, off, len,
socketBufferHandler.getWriteBuffer());
while (socketBufferHandler.getWriteBuffer().remaining() == 0) {
@@ -446,38 +488,50 @@ public abstract class SocketWrapperBase<
/**
- * Write the data to the socket (writing that data to the socket using a
- * blocking write) until all the data has been transferred and space
remains
- * in the socket write buffer. If it is possible use the provided buffer
- * directly and do not transfer to the socket write buffer.
+ * Writes the provided data to the socket write buffer. If the socket write
+ * buffer fills during the write, the content of the socket write buffer is
+ * written to the network using a blocking write. Once that blocking write
+ * is complete, this method starts to fill the socket write buffer again.
+ * Depending on the size of the data to write, there may be multiple writes
+ * to the network. On completion of this method there will always be space
+ * remaining in the socket write buffer.
*
* @param from The ByteBuffer containing the data to be written
*
* @throws IOException If an IO error occurs during the write
*/
protected void writeBlocking(ByteBuffer from) throws IOException {
- // Note: There is an implementation assumption that if the switch from
- // non-blocking to blocking has been made then any pending
- // non-blocking writes were flushed at the time the switch
- // occurred.
-
- // If it is possible write the data to the socket directly from the
- // provided buffer otherwise transfer it to the socket write buffer
if (socketBufferHandler.isWriteBufferEmpty()) {
- writeByteBufferBlocking(from);
+ // Socket write buffer is empty. Write the provided buffer directly
+ // to the network.
+ // TODO Shouldn't smaller writes be buffered anyway?
+ writeBlockingDirect(from);
} else {
+ // Socket write buffer has some data.
socketBufferHandler.configureWriteBufferForWrite();
+ // Put as much data as possible into the write buffer
transfer(from, socketBufferHandler.getWriteBuffer());
+ // If the buffer is now full, write it to the network and then
write
+ // the remaining data directly to the network.
if (!socketBufferHandler.isWriteBufferWritable()) {
doWrite(true);
- writeByteBufferBlocking(from);
+ writeBlockingDirect(from);
}
}
}
- protected void writeByteBufferBlocking(ByteBuffer from) throws IOException
{
+ /**
+ * Writes directly to the network, bypassing the socket write buffer.
+ *
+ * @param from The ByteBuffer containing the data to be written
+ *
+ * @throws IOException If an IO error occurs during the write
+ */
+ protected void writeBlockingDirect(ByteBuffer from) throws IOException {
// The socket write buffer capacity is socket.appWriteBufSize
+ // TODO This only matters when using TLS. For non-TLS connections it
+ // should be possible to write the ByteBuffer in a single write
int limit = socketBufferHandler.getWriteBuffer().capacity();
int fromLimit = from.limit();
while (from.remaining() >= limit) {
@@ -498,6 +552,11 @@ public abstract class SocketWrapperBase<
* socket if the buffer fills up using a non-blocking write) until either
* all the data has been transferred and space remains in the socket write
* buffer or a non-blocking write leaves data in the socket write buffer.
+ * After an incomplete write, any data remaining to be transferred to the
+ * socket write buffer will be copied to the socket write buffer. If the
+ * remaining data is too big for the socket write buffer, the socket write
+ * buffer will be filled and the additional data written to the
non-blocking
+ * write buffer.
*
* @param buf The byte array containing the data to be written
* @param off The offset within the byte array of the data to be written
@@ -534,17 +593,23 @@ public abstract class SocketWrapperBase<
/**
- * Writes the data to the socket (writing that data to the socket using a
- * non-blocking write) until either all the data has been transferred and
- * space remains in the socket write buffer or a non-blocking write leaves
- * data in the socket write buffer. If it is possible use the provided
- * buffer directly and do not transfer to the socket write buffer.
+ * Transfers the data to the socket write buffer (writing that data to the
+ * socket if the buffer fills up using a non-blocking write) until either
+ * all the data has been transferred and space remains in the socket write
+ * buffer or a non-blocking write leaves data in the socket write buffer.
+ * After an incomplete write, any data remaining to be transferred to the
+ * socket write buffer will be copied to the socket write buffer. If the
+ * remaining data is too big for the socket write buffer, the socket write
+ * buffer will be filled and the additional data written to the
non-blocking
+ * write buffer.
*
* @param from The ByteBuffer containing the data to be written
*
* @throws IOException If an IO error occurs during the write
*/
- protected void writeNonBlocking(ByteBuffer from) throws IOException {
+ protected void writeNonBlocking(ByteBuffer from)
+ throws IOException {
+
if (nonBlockingWriteBuffer.isEmpty() &&
socketBufferHandler.isWriteBufferWritable()) {
writeNonBlockingInternal(from);
}
@@ -556,16 +621,21 @@ public abstract class SocketWrapperBase<
}
+ /*
+ * Separate method so it can be re-used by the socket write buffer to write
+ * data to the network
+ */
boolean writeNonBlockingInternal(ByteBuffer from) throws IOException {
+ // TODO Explore refactoring this method back into writeNonBlocking
if (socketBufferHandler.isWriteBufferEmpty()) {
- return writeByteBufferNonBlocking(from);
+ return writeNonBlockingDirect(from);
} else {
socketBufferHandler.configureWriteBufferForWrite();
transfer(from, socketBufferHandler.getWriteBuffer());
if (!socketBufferHandler.isWriteBufferWritable()) {
doWrite(false);
if (socketBufferHandler.isWriteBufferWritable()) {
- return writeByteBufferNonBlocking(from);
+ return writeNonBlockingDirect(from);
}
}
}
@@ -574,8 +644,10 @@ public abstract class SocketWrapperBase<
}
- protected boolean writeByteBufferNonBlocking(ByteBuffer from) throws
IOException {
+ protected boolean writeNonBlockingDirect(ByteBuffer from) throws
IOException {
// The socket write buffer capacity is socket.appWriteBufSize
+ // TODO This only matters when using TLS. For non-TLS connections it
+ // should be possible to write the ByteBuffer in a single write
int limit = socketBufferHandler.getWriteBuffer().capacity();
int fromLimit = from.limit();
while (from.remaining() >= limit) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]