You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2015/01/15 10:21:24 UTC

svn commit: r1652004 - in /tomcat/trunk/java/org/apache: coyote/http11/ tomcat/util/net/

Author: markt
Date: Thu Jan 15 09:21:24 2015
New Revision: 1652004

URL: http://svn.apache.org/r1652004
Log:
Fix first set of issues found with NIO2 and new SocketBufferHandler

Modified:
    tomcat/trunk/java/org/apache/coyote/http11/InternalNio2InputBuffer.java
    tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java
    tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java
    tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java
    tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
    tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java
    tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java

Modified: tomcat/trunk/java/org/apache/coyote/http11/InternalNio2InputBuffer.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/InternalNio2InputBuffer.java?rev=1652004&r1=1652003&r2=1652004&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/InternalNio2InputBuffer.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/InternalNio2InputBuffer.java Thu Jan 15 09:21:24 2015
@@ -118,8 +118,7 @@ public class InternalNio2InputBuffer ext
          * Read bytes into the specified chunk.
          */
         @Override
-        public int doRead(ByteChunk chunk, Request req )
-            throws IOException {
+        public int doRead(ByteChunk chunk, Request req ) throws IOException {
 
             if (pos >= lastValid) {
                 if (!fill(true)) //read body, must be blocking, as the thread is inside the app

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java?rev=1652004&r1=1652003&r2=1652004&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java Thu Jan 15 09:21:24 2015
@@ -52,21 +52,13 @@ public class Nio2Channel implements Asyn
             throws IOException {
         this.sc = channel;
         this.socket = socket;
-        bufHandler.getReadBuffer().clear();
-        bufHandler.getWriteBuffer().clear();
+        bufHandler.reset();
     }
 
     public SocketWrapperBase<Nio2Channel> getSocket() {
         return socket;
     }
 
-    public int getBufferSize() {
-        if ( bufHandler == null ) return 0;
-        int size = 0;
-        size += bufHandler.getReadBuffer()!=null?bufHandler.getReadBuffer().capacity():0;
-        size += bufHandler.getWriteBuffer()!=null?bufHandler.getWriteBuffer().capacity():0;
-        return size;
-    }
 
     /**
      * Closes this channel.

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java?rev=1652004&r1=1652003&r2=1652004&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java Thu Jan 15 09:21:24 2015
@@ -726,8 +726,7 @@ public class Nio2Endpoint extends Abstra
         private boolean upgradeInit = false;
 
         private final CompletionHandler<Integer, SocketWrapperBase<Nio2Channel>> readCompletionHandler;
-        private boolean flipped = false;
-        private volatile boolean readPending = false;
+        private final Semaphore readPending = new Semaphore(1);
         private volatile boolean readInterest = true;
 
         private final CompletionHandler<Integer, ByteBuffer> writeCompletionHandler;
@@ -751,7 +750,7 @@ public class Nio2Endpoint extends Abstra
                         if (nBytes.intValue() < 0) {
                             failed(new EOFException(), attachment);
                         } else {
-                            readPending = false;
+                            readPending.release();
                             if (readInterest && !Nio2Endpoint.isInline()) {
                                 readInterest = false;
                                 notify = true;
@@ -771,7 +770,7 @@ public class Nio2Endpoint extends Abstra
                         ioe = new IOException(exc);
                     }
                     Nio2SocketWrapper.this.setError(ioe);
-                    readPending = false;
+                    readPending.release();
                     if (exc instanceof AsynchronousCloseException) {
                         // If already closed, don't call onError and close again
                         return;
@@ -947,30 +946,21 @@ public class Nio2Endpoint extends Abstra
         @Override
         public boolean isReady() throws IOException {
             synchronized (readCompletionHandler) {
-                if (readPending) {
+                if (!readPending.tryAcquire()) {
                     readInterest = true;
                     return false;
                 }
-                ByteBuffer readBuffer = getSocket().getBufHandler().getReadBuffer();
-                if (!flipped) {
-                    readBuffer.flip();
-                    flipped = true;
-                }
-                if (readBuffer.remaining() > 0) {
+
+                socketBufferHandler.configureReadBufferForRead();
+                if (!socketBufferHandler.isReadBufferEmpty()) {
                     return true;
                 }
 
-                readBuffer.clear();
-                flipped = false;
                 int nRead = fillReadBuffer(false);
 
                 boolean isReady = nRead > 0;
-                if (isReady) {
-                    if (!flipped) {
-                        readBuffer.flip();
-                        flipped = true;
-                    }
-                } else {
+
+                if (!isReady) {
                     readInterest = true;
                 }
                 return isReady;
@@ -988,27 +978,33 @@ public class Nio2Endpoint extends Abstra
                 log.debug("Socket: [" + this + "], block: [" + block + "], length: [" + len + "]");
             }
 
-            synchronized (readCompletionHandler) {
-                if (readPending) {
+            if (block) {
+                try {
+                    readPending.acquire();
+                } catch (InterruptedException e) {
+                    throw new IOException(e);
+                }
+            } else {
+                if (!readPending.tryAcquire()) {
                     if (log.isDebugEnabled()) {
                         log.debug("Socket: [" + this + "], Read: [0]");
                     }
                     return 0;
                 }
+            }
 
-                ByteBuffer readBuffer = getSocket().getBufHandler().getReadBuffer();
+            synchronized (readCompletionHandler) {
+                socketBufferHandler.configureReadBufferForRead();
+
+                int remaining = socketBufferHandler.getReadBuffer().remaining();
 
-                if (!flipped) {
-                    readBuffer.flip();
-                    flipped = true;
-                }
-                int remaining = readBuffer.remaining();
                 // Is there enough data in the read buffer to satisfy this request?
                 if (remaining >= len) {
-                    readBuffer.get(b, off, len);
+                    socketBufferHandler.getReadBuffer().get(b, off, len);
                     if (log.isDebugEnabled()) {
                         log.debug("Socket: [" + this + "], Read from buffer: [" + len + "]");
                     }
+                    readPending.release();
                     return len;
                 }
 
@@ -1016,39 +1012,29 @@ public class Nio2Endpoint extends Abstra
                 int leftToWrite = len;
                 int newOffset = off;
                 if (remaining > 0) {
-                    readBuffer.get(b, off, remaining);
+                    socketBufferHandler.getReadBuffer().get(b, off, remaining);
                     leftToWrite -= remaining;
                     newOffset += remaining;
                 }
 
-                // Fill the read buffer as best we can
-                readBuffer.clear();
-                flipped = false;
-                int nRead = fillReadBuffer(block);
+                // Fill the read buffer as best we can. Only do a blocking read if
+                // the current read is blocking AND there wasn't any data left over
+                // in the read buffer.
+                int nRead = fillReadBuffer(block && remaining == 0);
 
-                // Full as much of the remaining byte array as possible with the data
-                // that was just read
+                // Fill as much of the remaining byte array as possible with the
+                // data that was just read
                 if (nRead > 0) {
-                    if (!flipped) {
-                        readBuffer.flip();
-                        flipped = true;
-                    }
+                    socketBufferHandler.configureReadBufferForRead();
                     if (nRead > leftToWrite) {
-                        readBuffer.get(b, newOffset, leftToWrite);
+                        socketBufferHandler.getReadBuffer().get(b, newOffset, leftToWrite);
                         leftToWrite = 0;
                     } else {
-                        readBuffer.get(b, newOffset, nRead);
+                        socketBufferHandler.getReadBuffer().get(b, newOffset, nRead);
                         leftToWrite -= nRead;
                     }
-                } else if (nRead == 0) {
-                    if (block) {
-                        if (!flipped) {
-                            readBuffer.flip();
-                            flipped = true;
-                        }
-                    } else {
-                        readInterest = true;
-                    }
+                } else if (nRead == 0 && !block) {
+                    readInterest = true;
                 } else if (nRead == -1) {
                     throw new EOFException();
                 }
@@ -1056,7 +1042,6 @@ public class Nio2Endpoint extends Abstra
                 if (log.isDebugEnabled()) {
                     log.debug("Socket: [" + this + "], Read: [" + (len - leftToWrite) + "]");
                 }
-
                 return len - leftToWrite;
             }
         }
@@ -1065,7 +1050,8 @@ public class Nio2Endpoint extends Abstra
         @Override
         public void unRead(ByteBuffer returnedInput) {
             if (returnedInput != null) {
-                getSocket().getBufHandler().getReadBuffer().put(returnedInput);
+                socketBufferHandler.configureReadBufferForWrite();
+                socketBufferHandler.getReadBuffer().put(returnedInput);
             }
         }
 
@@ -1079,17 +1065,17 @@ public class Nio2Endpoint extends Abstra
         }
 
 
+        /* Callers of this method must:
+         * - have acquired the readPending semaphore
+         * - have acquired a lock on readCompletionHandler
+         */
         private int fillReadBuffer(boolean block) throws IOException {
-            ByteBuffer readBuffer = getSocket().getBufHandler().getReadBuffer();
+            socketBufferHandler.configureReadBufferForWrite();
             int nRead = 0;
             if (block) {
-                readPending = true;
-                readBuffer.clear();
-                flipped = false;
                 try {
-                    nRead = getSocket().read(readBuffer)
-                            .get(getTimeout(), TimeUnit.MILLISECONDS).intValue();
-                    readPending = false;
+                    nRead = getSocket().read(socketBufferHandler.getReadBuffer()).get(
+                            getTimeout(), TimeUnit.MILLISECONDS).intValue();
                 } catch (ExecutionException e) {
                     if (e.getCause() instanceof IOException) {
                         throw (IOException) e.getCause();
@@ -1103,15 +1089,12 @@ public class Nio2Endpoint extends Abstra
                     throw ex;
                 }
             } else {
-                readPending = true;
-                readBuffer.clear();
-                flipped = false;
                 Nio2Endpoint.startInline();
-                getSocket().read(readBuffer, getTimeout(), TimeUnit.MILLISECONDS,
+                getSocket().read(socketBufferHandler.getReadBuffer(), getTimeout(), TimeUnit.MILLISECONDS,
                         this, readCompletionHandler);
                 Nio2Endpoint.endInline();
-                if (!readPending) {
-                    nRead = readBuffer.position();
+                if (readPending.availablePermits() == 1) {
+                    nRead = socketBufferHandler.getReadBuffer().position();
                 }
             }
             return nRead;
@@ -1230,7 +1213,9 @@ public class Nio2Endpoint extends Abstra
                                 writeCompletionHandler);
                     } else {
                         // Nothing was written
-                        writePending.release();
+                        if (!hasPermit) {
+                            writePending.release();
+                        }
                     }
                 }
                 return hasDataToWrite();
@@ -1250,7 +1235,7 @@ public class Nio2Endpoint extends Abstra
         @Override
         public boolean isReadPending() {
             synchronized (readCompletionHandler) {
-                return readPending;
+                return readPending.availablePermits() == 0;
             }
         }
 
@@ -1258,11 +1243,13 @@ public class Nio2Endpoint extends Abstra
         @Override
         public void registerReadInterest() {
             synchronized (readCompletionHandler) {
-                if (readPending) {
-                    readInterest = true;
-                } else {
+                if (readPending.tryAcquire()) {
+                    readPending.release();
+
                     // If no read is pending, notify
                     getEndpoint().processSocket(this, SocketStatus.OPEN_READ, true);
+                } else {
+                    readInterest = true;
                 }
             }
         }
@@ -1352,10 +1339,9 @@ public class Nio2Endpoint extends Abstra
         if (socket == null || socket.getSocket() == null) {
             return;
         }
-        ByteBuffer byteBuffer = socket.getSocket().getBufHandler().getReadBuffer();
-        byteBuffer.clear();
-        socket.getSocket().read(byteBuffer, socket.getTimeout(),
-               TimeUnit.MILLISECONDS, socket, awaitBytes);
+        socket.getSocket().getBufHandler().configureReadBufferForWrite();
+        socket.getSocket().read(socket.getSocket().getBufHandler().getReadBuffer(),
+                socket.getTimeout(), TimeUnit.MILLISECONDS, socket, awaitBytes);
     }
 
     public enum SendfileState {
@@ -1449,8 +1435,8 @@ public class Nio2Endpoint extends Abstra
                 return SendfileState.ERROR;
             }
         }
+        socket.getSocket().getBufHandler().configureReadBufferForWrite();
         ByteBuffer buffer = socket.getSocket().getBufHandler().getWriteBuffer();
-        buffer.clear();
         int nRead = -1;
         try {
             nRead = data.fchannel.read(buffer);
@@ -1459,10 +1445,10 @@ public class Nio2Endpoint extends Abstra
         }
 
         if (nRead >= 0) {
-            buffer.flip();
             data.socket = socket;
             data.buffer = buffer;
             data.length -= nRead;
+            socket.getSocket().getBufHandler().configureReadBufferForRead();
             socket.getSocket().write(buffer, socket.getTimeout(), TimeUnit.MILLISECONDS,
                     data, sendfile);
             if (data.doneInline) {

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java?rev=1652004&r1=1652003&r2=1652004&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java Thu Jan 15 09:21:24 2015
@@ -64,13 +64,6 @@ public class NioChannel implements ByteC
         this.sendFile = false;
     }
 
-    public int getBufferSize() {
-        if ( bufHandler == null ) return 0;
-        int size = 0;
-        size += bufHandler.getReadBuffer().capacity();
-        size += bufHandler.getWriteBuffer().capacity();
-        return size;
-    }
 
     /**
      * Returns true if the network buffer has been flushed out and is empty.

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java?rev=1652004&r1=1652003&r2=1652004&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Thu Jan 15 09:21:24 2015
@@ -1438,8 +1438,10 @@ public class NioEndpoint extends Abstrac
                 newOffset += remaining;
             }
 
-            // Fill the read buffer as best we can
-            int nRead = fillReadBuffer(block);
+            // Fill the read buffer as best we can. Only do a blocking read if
+            // the current read is blocking AND there wasn't any data left over
+            // in the read buffer.
+            int nRead = fillReadBuffer(block && remaining == 0);
 
             // Full as much of the remaining byte array as possible with the
             // data that was just read

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java?rev=1652004&r1=1652003&r2=1652004&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java Thu Jan 15 09:21:24 2015
@@ -126,13 +126,6 @@ public class SecureNio2Channel extends N
         handshakeStatus = sslEngine.getHandshakeStatus();
     }
 
-    @Override
-    public int getBufferSize() {
-        int size = super.getBufferSize();
-        size += netInBuffer!=null?netInBuffer.capacity():0;
-        size += netOutBuffer!=null?netOutBuffer.capacity():0;
-        return size;
-    }
 
     private class FutureFlush implements Future<Boolean> {
         private Future<Integer> integer;
@@ -308,17 +301,14 @@ public class SecureNio2Channel extends N
         //validate the network buffers are empty
         if (netInBuffer.position() > 0 && netInBuffer.position() < netInBuffer.limit()) throw new IOException(sm.getString("channel.nio.ssl.netInputNotEmpty"));
         if (netOutBuffer.position() > 0 && netOutBuffer.position() < netOutBuffer.limit()) throw new IOException(sm.getString("channel.nio.ssl.netOutputNotEmpty"));
-        ByteBuffer readBuffer = getBufHandler().getReadBuffer();
-        ByteBuffer writeBuffer = getBufHandler().getWriteBuffer();
-        if (readBuffer.position() > 0 && readBuffer.position() < readBuffer.limit()) throw new IOException(sm.getString("channel.nio.ssl.appInputNotEmpty"));
-        if (writeBuffer.position() > 0 && writeBuffer.position() < writeBuffer.limit()) throw new IOException(sm.getString("channel.nio.ssl.appOutputNotEmpty"));
+        if (!getBufHandler().isReadBufferEmpty()) throw new IOException(sm.getString("channel.nio.ssl.appInputNotEmpty"));
+        if (!getBufHandler().isWriteBufferEmpty()) throw new IOException(sm.getString("channel.nio.ssl.appOutputNotEmpty"));
 
         netOutBuffer.position(0);
         netOutBuffer.limit(0);
         netInBuffer.position(0);
         netInBuffer.limit(0);
-        readBuffer.clear();
-        writeBuffer.clear();
+        getBufHandler().reset();
 
         handshakeComplete = false;
         //initiate handshake
@@ -366,6 +356,7 @@ public class SecureNio2Channel extends N
         //so we can clear it here.
         netOutBuffer.clear();
         //perform the wrap
+        bufHandler.configureWriteBufferForRead();
         SSLEngineResult result = sslEngine.wrap(bufHandler.getWriteBuffer(), netOutBuffer);
         //prepare the results to be written
         netOutBuffer.flip();
@@ -392,6 +383,7 @@ public class SecureNio2Channel extends N
             //prepare the buffer with the incoming data
             netInBuffer.flip();
             //call unwrap
+            bufHandler.configureReadBufferForWrite();
             result = sslEngine.unwrap(netInBuffer, bufHandler.getReadBuffer());
             //compact the buffer, this is an optional method, wonder what would happen if we didn't
             netInBuffer.compact();

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java?rev=1652004&r1=1652003&r2=1652004&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java Thu Jan 15 09:21:24 2015
@@ -84,14 +84,6 @@ public class SecureNioChannel extends Ni
         handshakeStatus = sslEngine.getHandshakeStatus();
     }
 
-    @Override
-    public int getBufferSize() {
-        int size = super.getBufferSize();
-        size += netInBuffer!=null?netInBuffer.capacity():0;
-        size += netOutBuffer!=null?netOutBuffer.capacity():0;
-        return size;
-    }
-
 
 //===========================================================================================
 //                  NIO SSL METHODS



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org