Author: markt Date: Fri May 10 09:35:53 2013 New Revision: 1480963 URL: http://svn.apache.org/r1480963 Log: Non-blocking Servlet 3.1 reads for APR
Modified: tomcat/trunk/java/org/apache/coyote/http11/InternalAprInputBuffer.java tomcat/trunk/java/org/apache/coyote/http11/InternalAprOutputBuffer.java tomcat/trunk/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java Modified: tomcat/trunk/java/org/apache/coyote/http11/InternalAprInputBuffer.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/InternalAprInputBuffer.java?rev=1480963&r1=1480962&r2=1480963&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http11/InternalAprInputBuffer.java (original) +++ tomcat/trunk/java/org/apache/coyote/http11/InternalAprInputBuffer.java Fri May 10 09:35:53 2013 @@ -21,6 +21,8 @@ import java.io.IOException; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.apache.coyote.InputBuffer; import org.apache.coyote.Request; @@ -89,9 +91,10 @@ public class InternalAprInputBuffer exte private long socket; - // --------------------------------------------------------- Public Methods + private SocketWrapper<Long> wrapper; + // --------------------------------------------------------- Public Methods /** * Recycle the input buffer. This should be called when closing the @@ -100,6 +103,7 @@ public class InternalAprInputBuffer exte @Override public void recycle() { socket = 0; + wrapper = null; super.recycle(); } @@ -133,7 +137,7 @@ public class InternalAprInputBuffer exte if (useAvailableData) { return false; } - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } @@ -150,7 +154,7 @@ public class InternalAprInputBuffer exte if (useAvailableData) { return false; } - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } @@ -165,7 +169,7 @@ public class InternalAprInputBuffer exte // Read new bytes if needed if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } @@ -188,7 +192,7 @@ public class InternalAprInputBuffer exte while (space) { // Read new bytes if needed if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { @@ -213,7 +217,7 @@ public class InternalAprInputBuffer exte // Read new bytes if needed if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } @@ -249,7 +253,7 @@ public class InternalAprInputBuffer exte while (space) { // Read new bytes if needed if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { @@ -273,7 +277,7 @@ public class InternalAprInputBuffer exte // Read new bytes if needed if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } @@ -340,7 +344,7 @@ public class InternalAprInputBuffer exte // Read new bytes if needed if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } @@ -374,7 +378,7 @@ public class InternalAprInputBuffer exte // Read new bytes if needed if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } @@ -416,7 +420,7 @@ public class InternalAprInputBuffer exte // Read new bytes if needed if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } @@ -435,7 +439,7 @@ public class InternalAprInputBuffer exte // Read new bytes if needed if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } @@ -463,7 +467,7 @@ public class InternalAprInputBuffer exte // Read new bytes if needed if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } @@ -499,7 +503,7 @@ public class InternalAprInputBuffer exte // Read new bytes if needed if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) throw new EOFException(sm.getString("iib.eof.error")); } @@ -545,24 +549,20 @@ public class InternalAprInputBuffer exte AbstractEndpoint endpoint) throws IOException { socket = socketWrapper.getSocket().longValue(); + wrapper = socketWrapper; Socket.setrbb(this.socket, bbuf); } - @Override - protected boolean fill(boolean block) throws IOException { - // Ignore the block parameter and just call fill - return fill(); - } - - /** - * Fill the internal buffer using data from the underlying input stream. + * Attempts to read some data into the input buffer. * - * @return false if at end of stream + * @return <code>true</code> if more data was added to the input buffer + * otherwise <code>false</code> */ - protected boolean fill() - throws IOException { + @Override + protected boolean fill(boolean block) throws IOException { + // Ignore the block parameter int nRead = 0; @@ -574,7 +574,7 @@ public class InternalAprInputBuffer exte } bbuf.clear(); - nRead = Socket.recvbb(socket, 0, buf.length - lastValid); + nRead = doReadSocket(true); if (nRead > 0) { bbuf.limit(nRead); bbuf.get(buf, pos, nRead); @@ -599,7 +599,7 @@ public class InternalAprInputBuffer exte pos = end; lastValid = pos; bbuf.clear(); - nRead = Socket.recvbb(socket, 0, buf.length - lastValid); + nRead = doReadSocket(true); if (nRead > 0) { bbuf.limit(nRead); bbuf.get(buf, pos, nRead); @@ -618,15 +618,69 @@ public class InternalAprInputBuffer exte } return (nRead > 0); - } @Override protected int nbRead() throws IOException { - return 0; - // TODO - // throw new UnsupportedOperationException("APR non-blocking read"); + bbuf.clear(); + int nRead = doReadSocket(false); + + if (nRead > 0) { + bbuf.limit(nRead); + bbuf.get(buf, pos, nRead); + lastValid = pos + nRead; + return nRead; + } else if (-nRead == Status.EAGAIN) { + return 0; + } else { + throw new IOException(sm.getString("iib.failedread", + Integer.valueOf(-nRead))); + } + } + + + private int doReadSocket(boolean block) { + + Lock readLock = wrapper.getBlockingStatusReadLock(); + WriteLock writeLock = wrapper.getBlockingStatusWriteLock(); + + boolean readDone = false; + int result = 0; + try { + readLock.lock(); + if (wrapper.getBlockingStatus() == block) { + result = Socket.recvbb(socket, 0, buf.length - lastValid); + readDone = true; + } + } finally { + readLock.unlock(); + } + + if (!readDone) { + try { + writeLock.lock(); + wrapper.setBlockingStatus(block); + // Set the current settings for this socket + Socket.optSet(socket, Socket.APR_SO_NONBLOCK, (block ? 0 : 1)); + // Downgrade the lock + try { + readLock.lock(); + writeLock.unlock(); + result = Socket.recvbb(socket, 0, buf.length - lastValid); + } finally { + readLock.unlock(); + } + } finally { + // Should have been released above but may not have been on some + // exception paths + if (writeLock.isHeldByCurrentThread()) { + writeLock.unlock(); + } + } + } + + return result; } @@ -648,7 +702,7 @@ public class InternalAprInputBuffer exte throws IOException { if (pos >= lastValid) { - if (!fill()) + if (!fill(true)) return -1; } Modified: tomcat/trunk/java/org/apache/coyote/http11/InternalAprOutputBuffer.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/InternalAprOutputBuffer.java?rev=1480963&r1=1480962&r2=1480963&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http11/InternalAprOutputBuffer.java (original) +++ tomcat/trunk/java/org/apache/coyote/http11/InternalAprOutputBuffer.java Fri May 10 09:35:53 2013 @@ -125,6 +125,7 @@ public class InternalAprOutputBuffer ext bbuf.clear(); flipped = false; + socket = 0; wrapper = null; } Modified: tomcat/trunk/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java?rev=1480963&r1=1480962&r2=1480963&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java (original) +++ tomcat/trunk/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java Fri May 10 09:35:53 2013 @@ -57,14 +57,9 @@ public class TestNonBlockingAPI extends public void testNonBlockingRead() throws Exception { Tomcat tomcat = getTomcatInstance(); - // TODO Non-blocking reads are not yet implemented for APR. - if (tomcat.getConnector().getProtocolHandlerClassName().equals( - "org.apache.coyote.http11.Http11AprProtocol")) { - return; - } - // Must have a real docBase - just use temp - StandardContext ctx = (StandardContext) tomcat.addContext("", System.getProperty("java.io.tmpdir")); + StandardContext ctx = (StandardContext) tomcat.addContext("", + System.getProperty("java.io.tmpdir")); NBReadServlet servlet = new NBReadServlet(); String servletName = NBReadServlet.class.getName(); @@ -74,8 +69,8 @@ public class TestNonBlockingAPI extends tomcat.start(); Map<String, List<String>> resHeaders = new HashMap<>(); - int rc = postUrl(true, new DataWriter(500), "http://localhost:"; + getPort() + "/", new ByteChunk(), - resHeaders, null); + int rc = postUrl(true, new DataWriter(500), "http://localhost:"; + + getPort() + "/", new ByteChunk(), resHeaders, null); Assert.assertEquals(HttpServletResponse.SC_OK, rc); } @@ -84,7 +79,8 @@ public class TestNonBlockingAPI extends public void testNonBlockingWrite() throws Exception { Tomcat tomcat = getTomcatInstance(); // Must have a real docBase - just use temp - StandardContext ctx = (StandardContext) tomcat.addContext("", System.getProperty("java.io.tmpdir")); + StandardContext ctx = (StandardContext) tomcat.addContext("", + System.getProperty("java.io.tmpdir")); NBWriteServlet servlet = new NBWriteServlet(); String servletName = NBWriteServlet.class.getName(); --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org