This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 7.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/7.0.x by this push: new c88cf8f Improve clean-up after an OOME during request processing c88cf8f is described below commit c88cf8f1befbe29aafb38c5ee9d8a2e852801ac6 Author: Mark Thomas <ma...@apache.org> AuthorDate: Mon May 13 20:10:13 2019 +0100 Improve clean-up after an OOME during request processing --- .../apache/catalina/core/StandardWrapperValve.java | 167 ++++++++++----------- java/org/apache/coyote/AbstractProtocol.java | 8 +- java/org/apache/coyote/LocalStrings.properties | 1 + webapps/docs/changelog.xml | 4 + 4 files changed, 94 insertions(+), 86 deletions(-) diff --git a/java/org/apache/catalina/core/StandardWrapperValve.java b/java/org/apache/catalina/core/StandardWrapperValve.java index be7e7e5..b621e12 100644 --- a/java/org/apache/catalina/core/StandardWrapperValve.java +++ b/java/org/apache/catalina/core/StandardWrapperValve.java @@ -268,57 +268,57 @@ final class StandardWrapperValve context.getName()), e); throwable = e; exception(request, response, e); - } - - // Release the filter chain (if any) for this request - if (filterChain != null) { - if (request.isComet()) { - // If this is a Comet request, then the same chain will be used for the - // processing of all subsequent events. - filterChain.reuse(); - } else { - filterChain.release(); + } finally { + // Release the filter chain (if any) for this request + if (filterChain != null) { + if (request.isComet()) { + // If this is a Comet request, then the same chain will be used for the + // processing of all subsequent events. + filterChain.reuse(); + } else { + filterChain.release(); + } } - } - // Deallocate the allocated servlet instance - try { - if (servlet != null) { - wrapper.deallocate(servlet); - } - } catch (Throwable e) { - ExceptionUtils.handleThrowable(e); - container.getLogger().error(sm.getString("standardWrapper.deallocateException", - wrapper.getName()), e); - if (throwable == null) { - throwable = e; - exception(request, response, e); + // Deallocate the allocated servlet instance + try { + if (servlet != null) { + wrapper.deallocate(servlet); + } + } catch (Throwable e) { + ExceptionUtils.handleThrowable(e); + container.getLogger().error(sm.getString("standardWrapper.deallocateException", + wrapper.getName()), e); + if (throwable == null) { + throwable = e; + exception(request, response, e); + } } - } - // If this servlet has been marked permanently unavailable, - // unload it and release this instance - try { - if ((servlet != null) && - (wrapper.getAvailable() == Long.MAX_VALUE)) { - wrapper.unload(); - } - } catch (Throwable e) { - ExceptionUtils.handleThrowable(e); - container.getLogger().error(sm.getString("standardWrapper.unloadException", - wrapper.getName()), e); - if (throwable == null) { - throwable = e; - exception(request, response, e); + // If this servlet has been marked permanently unavailable, + // unload it and release this instance + try { + if ((servlet != null) && + (wrapper.getAvailable() == Long.MAX_VALUE)) { + wrapper.unload(); + } + } catch (Throwable e) { + ExceptionUtils.handleThrowable(e); + container.getLogger().error(sm.getString("standardWrapper.unloadException", + wrapper.getName()), e); + if (throwable == null) { + throwable = e; + exception(request, response, e); + } } - } - long t2=System.currentTimeMillis(); - long time=t2-t1; - processingTime += time; - if( time > maxTime) maxTime=time; - if( time < minTime) minTime=time; + long t2=System.currentTimeMillis(); + long time=t2-t1; + processingTime += time; + if( time > maxTime) maxTime=time; + if( time < minTime) minTime=time; + } } @@ -441,57 +441,54 @@ final class StandardWrapperValve context.getName()), e); throwable = e; exception(request, response, e); - } - - // Release the filter chain (if any) for this request - if (filterChain != null) { - filterChain.reuse(); - } - - // Deallocate the allocated servlet instance - try { - if (servlet != null) { - wrapper.deallocate(servlet); - } - } catch (Throwable e) { - ExceptionUtils.handleThrowable(e); - container.getLogger().error(sm.getString("standardWrapper.deallocateException", - wrapper.getName()), e); - if (throwable == null) { - throwable = e; - exception(request, response, e); + } finally { + // Release the filter chain (if any) for this request + if (filterChain != null) { + filterChain.reuse(); } - } - // If this servlet has been marked permanently unavailable, - // unload it and release this instance - try { - if ((servlet != null) && - (wrapper.getAvailable() == Long.MAX_VALUE)) { - wrapper.unload(); - } - } catch (Throwable e) { - ExceptionUtils.handleThrowable(e); - container.getLogger().error(sm.getString("standardWrapper.unloadException", - wrapper.getName()), e); - if (throwable == null) { - exception(request, response, e); + // Deallocate the allocated servlet instance + try { + if (servlet != null) { + wrapper.deallocate(servlet); + } + } catch (Throwable e) { + ExceptionUtils.handleThrowable(e); + container.getLogger().error(sm.getString("standardWrapper.deallocateException", + wrapper.getName()), e); + if (throwable == null) { + throwable = e; + exception(request, response, e); + } } - } - long t2=System.currentTimeMillis(); - - long time=t2-t1; - processingTime += time; - if( time > maxTime) maxTime=time; - if( time < minTime) minTime=time; + // If this servlet has been marked permanently unavailable, + // unload it and release this instance + try { + if ((servlet != null) && + (wrapper.getAvailable() == Long.MAX_VALUE)) { + wrapper.unload(); + } + } catch (Throwable e) { + ExceptionUtils.handleThrowable(e); + container.getLogger().error(sm.getString("standardWrapper.unloadException", + wrapper.getName()), e); + if (throwable == null) { + exception(request, response, e); + } + } + long t2=System.currentTimeMillis(); + long time=t2-t1; + processingTime += time; + if( time > maxTime) maxTime=time; + if( time < minTime) minTime=time; + } } // -------------------------------------------------------- Private Methods - /** * Handle the specified ServletException encountered while processing * the specified Request to produce the specified Response. Any diff --git a/java/org/apache/coyote/AbstractProtocol.java b/java/org/apache/coyote/AbstractProtocol.java index f7a2b7f..b18c087 100644 --- a/java/org/apache/coyote/AbstractProtocol.java +++ b/java/org/apache/coyote/AbstractProtocol.java @@ -752,7 +752,13 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler, // Future developers: if you discover any other // rare-but-nonfatal exceptions, catch them here, and log as // above. - catch (Throwable e) { + catch (OutOfMemoryError oome) { + // Try and handle this here to give Tomcat a chance to close the + // connection and prevent clients waiting until they time out. + // Worst case, it isn't recoverable and the attempt at logging + // will trigger another OOME. + getLog().error(sm.getString("abstractConnectionHandler.oome"), oome); + } catch (Throwable e) { ExceptionUtils.handleThrowable(e); // any other exception or error is odd. Here we log it // with "ERROR" level, so it will show up even on diff --git a/java/org/apache/coyote/LocalStrings.properties b/java/org/apache/coyote/LocalStrings.properties index 6feef10..3de0cd7 100644 --- a/java/org/apache/coyote/LocalStrings.properties +++ b/java/org/apache/coyote/LocalStrings.properties @@ -15,6 +15,7 @@ abstractConnectionHandler.error=Error reading request, ignored abstractConnectionHandler.ioexception.debug=IOExceptions are normal, ignored +abstractConnectionHandler.oome=Failed to complete processing of a request abstractConnectionHandler.socketexception.debug=SocketExceptions are normal, ignored abstractProcessor.fallToDebug=\n\ diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 4eb0788..cd1a8f0 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -66,6 +66,10 @@ <bug>63832</bug>: Properly mark container as FAILED when a JVM error occurs on stop. (remm) </fix> + <fix> + Make a best efforts attempt to clean-up if a request fails during + processing due to an <code>OutOfMemoryException</code>. (markt) + </fix> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org