Author: remm Date: Wed Jun 10 12:45:26 2015 New Revision: 1684663 URL: http://svn.apache.org/r1684663 Log: Direct buffers need explicit cleanup to ensure complete reliability without OOMs.
Modified: tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java tomcat/trunk/java/org/apache/tomcat/util/buf/ByteBufferUtils.java tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.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 tomcat/trunk/java/org/apache/tomcat/util/net/SocketBufferHandler.java Modified: tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java?rev=1684663&r1=1684662&r2=1684663&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java (original) +++ tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java Wed Jun 10 12:45:26 2015 @@ -263,6 +263,7 @@ public final class SecurityClassLoad { throws Exception { final String basePackage = "org.apache.tomcat."; // buf + loader.loadClass(basePackage + "util.buf.ByteBufferUtils"); loader.loadClass(basePackage + "util.buf.HexUtils"); loader.loadClass(basePackage + "util.buf.StringCache"); loader.loadClass(basePackage + "util.buf.StringCache$ByteEntry"); Modified: tomcat/trunk/java/org/apache/tomcat/util/buf/ByteBufferUtils.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/buf/ByteBufferUtils.java?rev=1684663&r1=1684662&r2=1684663&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/buf/ByteBufferUtils.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/buf/ByteBufferUtils.java Wed Jun 10 12:45:26 2015 @@ -16,10 +16,29 @@ */ package org.apache.tomcat.util.buf; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.nio.ByteBuffer; public class ByteBufferUtils { + private static final Method cleanerMethod; + private static final Method cleanMethod; + + static { + try { + ByteBuffer tempBuffer = ByteBuffer.allocateDirect(0); + cleanerMethod = tempBuffer.getClass().getMethod("cleaner"); + cleanerMethod.setAccessible(true); + Object cleanerObject = cleanerMethod.invoke(tempBuffer); + cleanMethod = cleanerObject.getClass().getMethod("clean"); + cleanMethod.invoke(cleanerObject); + } catch (IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + throw new ExceptionInInitializerError(e); + } + } + private ByteBufferUtils() { // Hide the default constructor since this is a utility class. } @@ -56,8 +75,10 @@ public class ByteBufferUtils { } ByteBuffer out; + boolean direct = false; if (in.isDirect()) { out = ByteBuffer.allocateDirect(newSize); + direct = true; } else { out = ByteBuffer.allocate(newSize); } @@ -66,6 +87,20 @@ public class ByteBufferUtils { in.flip(); out.put(in); + if (direct) { + cleanDirectBuffer(in); + } + return out; } + + public static void cleanDirectBuffer(ByteBuffer buf) { + try { + cleanMethod.invoke(cleanerMethod.invoke(buf)); + } catch (IllegalAccessException | IllegalArgumentException + | InvocationTargetException | SecurityException e) { + // Ignore + } + } + } 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=1684663&r1=1684662&r2=1684663&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Wed Jun 10 12:45:26 2015 @@ -51,6 +51,7 @@ import org.apache.tomcat.jni.Sockaddr; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.jni.Status; import org.apache.tomcat.util.ExceptionUtils; +import org.apache.tomcat.util.buf.ByteBufferUtils; import org.apache.tomcat.util.net.AbstractEndpoint.Acceptor.AcceptorState; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.SSLHostConfig.Type; @@ -2569,6 +2570,9 @@ public class AprEndpoint extends Abstrac return; } closed = true; + if (sslOutputBuffer != null) { + ByteBufferUtils.cleanDirectBuffer(sslOutputBuffer); + } ((AprEndpoint) getEndpoint()).getPoller().close(getSocket().longValue()); } } 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=1684663&r1=1684662&r2=1684663&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java Wed Jun 10 12:45:26 2015 @@ -55,6 +55,13 @@ public class Nio2Channel implements Asyn bufHandler.reset(); } + /** + * Free the channel memory + */ + public void free() { + bufHandler.free(); + } + public SocketWrapperBase<Nio2Channel> getSocket() { return socket; } 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=1684663&r1=1684662&r2=1684663&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java Wed Jun 10 12:45:26 2015 @@ -1660,7 +1660,9 @@ public class Nio2Endpoint extends Abstra // Close socket and pool closeSocket(socket); if (running && !paused) { - nioChannels.push(socket.getSocket()); + if (!nioChannels.push(socket.getSocket())) { + socket.getSocket().free(); + } } } else if (state == Handler.SocketState.LONG) { if (socket.isAsync()) { @@ -1673,7 +1675,9 @@ public class Nio2Endpoint extends Abstra } else if (handshake == -1 ) { closeSocket(socket); if (running && !paused) { - nioChannels.push(socket.getSocket()); + if (!nioChannels.push(socket.getSocket())) { + socket.getSocket().free(); + } } } } catch (VirtualMachineError vme) { 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=1684663&r1=1684662&r2=1684663&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java Wed Jun 10 12:45:26 2015 @@ -66,6 +66,13 @@ public class NioChannel implements ByteC /** + * Free the channel memory + */ + public void free() { + bufHandler.free(); + } + + /** * Returns true if the network buffer has been flushed out and is empty. * * @param block Unused. May be used when overridden 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=1684663&r1=1684662&r2=1684663&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Wed Jun 10 12:45:26 2015 @@ -1536,7 +1536,9 @@ public class NioEndpoint extends Abstrac // We do NOT want to do this more than once - see BZ // 57340. if (running && !paused) { - nioChannels.push(socket); + if (!nioChannels.push(socket)) { + socket.free(); + } } socket = null; } @@ -1550,7 +1552,9 @@ public class NioEndpoint extends Abstrac socket.getPoller().cancelledKey(key); } if (running && !paused) { - nioChannels.push(socket); + if (!nioChannels.push(socket)) { + socket.free(); + } } socket = null; ka = null; 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=1684663&r1=1684662&r2=1684663&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java Wed Jun 10 12:45:26 2015 @@ -122,6 +122,14 @@ public class SecureNio2Channel extends N closing = false; } + @Override + public void free() { + super.free(); + if (endpoint.getSocketProperties().getDirectSslBuffer()) { + ByteBufferUtils.cleanDirectBuffer(netInBuffer); + ByteBufferUtils.cleanDirectBuffer(netOutBuffer); + } + } private class FutureFlush implements Future<Boolean> { private Future<Integer> integer; 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=1684663&r1=1684662&r2=1684663&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java Wed Jun 10 12:45:26 2015 @@ -93,6 +93,14 @@ public class SecureNioChannel extends Ni netInBuffer.clear(); } + @Override + public void free() { + super.free(); + if (endpoint.getSocketProperties().getDirectSslBuffer()) { + ByteBufferUtils.cleanDirectBuffer(netInBuffer); + ByteBufferUtils.cleanDirectBuffer(netOutBuffer); + } + } //=========================================================================================== // NIO SSL METHODS Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SocketBufferHandler.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SocketBufferHandler.java?rev=1684663&r1=1684662&r2=1684663&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SocketBufferHandler.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SocketBufferHandler.java Wed Jun 10 12:45:26 2015 @@ -28,9 +28,11 @@ public class SocketBufferHandler { private volatile boolean writeBufferConfiguredForWrite = true; private volatile ByteBuffer writeBuffer; + private final boolean direct; public SocketBufferHandler(int readBufferSize, int writeBufferSize, boolean direct) { + this.direct = direct; if (direct) { readBuffer = ByteBuffer.allocateDirect(readBufferSize); writeBuffer = ByteBuffer.allocateDirect(writeBufferSize); @@ -156,4 +158,12 @@ public class SocketBufferHandler { configureWriteBufferForWrite(); writeBuffer = ByteBufferUtils.expand(writeBuffer, newSize); } + + public void free() { + if (direct) { + ByteBufferUtils.cleanDirectBuffer(readBuffer); + ByteBufferUtils.cleanDirectBuffer(writeBuffer); + } + } + } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org