From 2dc78a5cd9b135127d3ce2e864447df0c0b57d48 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 23 Dec 2015 14:12:47 +1100 Subject: [PATCH 1/3] 484822 Jetty ThreadMonitor memory leak --- .../eclipse/jetty/monitor/ThreadMonitor.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java index cdbaac45d41..e26619f6d91 100644 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java +++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java @@ -24,8 +24,11 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import org.eclipse.jetty.monitor.thread.ThreadMonitorException; import org.eclipse.jetty.monitor.thread.ThreadMonitorInfo; @@ -321,6 +324,8 @@ public class ThreadMonitor extends AbstractLifeCycle implements Runnable _runner.join(); } catch (InterruptedException ex) {} + + _monitorInfo.clear(); } } @@ -424,6 +429,8 @@ public class ThreadMonitor extends AbstractLifeCycle implements Runnable // retrieving a single thread stack trace. Map all = Thread.getAllStackTraces(); + Set newOrUpdatedIds = new HashSet(); + for (Map.Entry entry : all.entrySet()) { Thread thread = entry.getKey(); @@ -490,7 +497,18 @@ public class ThreadMonitor extends AbstractLifeCycle implements Runnable } } } + newOrUpdatedIds.add(Long.valueOf(threadId)); } + + //clean out threads that no longer exist + Iterator iter = _monitorInfo.keySet().iterator(); + while (iter.hasNext()) + { + Long id = iter.next(); + if (!newOrUpdatedIds.contains(id)) + iter.remove(); + } + newOrUpdatedIds.clear(); } catch (Exception ex) { From 9fd3a9342f2cfa9736595e9eb0abcf4bda38c98a Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 23 Dec 2015 14:22:19 +1100 Subject: [PATCH 2/3] Fix duplicate declaration of felix plugin execution for jetty-runner --- jetty-runner/pom.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/jetty-runner/pom.xml b/jetty-runner/pom.xml index 17be7ef8a0d..7b449d96585 100644 --- a/jetty-runner/pom.xml +++ b/jetty-runner/pom.xml @@ -42,8 +42,6 @@ true - bundle-manifest - process-classes manifest From f65a7db8c53113c25635b7f46567abce6a88e559 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 23 Dec 2015 15:07:05 +1100 Subject: [PATCH 3/3] 458745 Async ISE in async Echo The HttpOutput class was throwing an ISE if it was dispatched when PENDING or UNREADY. However this can occur when it has been dispatched, but a prior call to onDataAvailable() does output after calling isReady(). The HttpOutput now does not enforce that part of the state machine and defers to the application correctly calling isReady() --- .../jetty/embedded/AsyncEchoServlet.java | 24 +++++++++++++++---- .../main/resources/jetty-logging.properties | 4 ++-- .../org/eclipse/jetty/server/HttpOutput.java | 2 ++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java index 74231763c8f..9a557cce46e 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java @@ -34,6 +34,8 @@ import javax.servlet.http.HttpServletResponse; public class AsyncEchoServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -62,17 +64,22 @@ public class AsyncEchoServlet extends HttpServlet @Override public void onDataAvailable() throws IOException { - onWritePossible(); + handleAsyncIO(); } @Override public void onAllDataRead() throws IOException { - onWritePossible(); + handleAsyncIO(); } @Override public void onWritePossible() throws IOException + { + handleAsyncIO(); + } + + private void handleAsyncIO() throws IOException { // This method is called: // 1) after first registering a WriteListener (ready for first write) @@ -81,8 +88,17 @@ public class AsyncEchoServlet extends HttpServlet // 4) from an input callback // We should try to read, only if we are able to write! - while (output.isReady() && input.isReady()) + while (true) { + if (!output.isReady()) + // Don't even try to read anything until it is possible to write something, + // when onWritePossible will be called + break; + + if (!input.isReady()) + // Nothing available to read, so wait for another call to onDataAvailable + break; + int read = input.read(buffer); if (read<0) { @@ -100,7 +116,7 @@ public class AsyncEchoServlet extends HttpServlet @Override public void onError(Throwable failure) { - failure.printStackTrace(); + new Throwable("onError",failure).printStackTrace(); asyncContext.complete(); } } diff --git a/examples/embedded/src/main/resources/jetty-logging.properties b/examples/embedded/src/main/resources/jetty-logging.properties index 62624e2d4a4..7bffba83dbb 100644 --- a/examples/embedded/src/main/resources/jetty-logging.properties +++ b/examples/embedded/src/main/resources/jetty-logging.properties @@ -1,8 +1,8 @@ #org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.JavaUtilLog #org.eclipse.jetty.util.log.javautil.PROPERTIES=java-util-logging.properties #org.eclipse.jetty.util.log.SOURCE=true -org.eclipse.jetty.LEVEL=INFO -org.eclipse.jetty.STACKS=true +#org.eclipse.jetty.LEVEL=INFO +#org.eclipse.jetty.STACKS=true #org.eclipse.jetty.STACKS=false #org.eclipse.jetty.io.LEVEL=DEBUG #org.eclipse.jetty.io.ssl.LEVEL=DEBUG diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java index e1b8b6b1337..ea69d416f39 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java @@ -926,6 +926,8 @@ public class HttpOutput extends ServletOutputStream implements Runnable // occurred, we need to call onWritePossible to tell async // producer that the last write completed. // So fall through + case PENDING: + case UNREADY: case READY: try {