Author: markt
Date: Thu Sep 30 17:56:42 2010
New Revision: 1003183
URL: http://svn.apache.org/viewvc?rev=1003183&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=49730
Race condition in executor can lead to long delays in request processing
Modified:
tomcat/trunk/java/org/apache/tomcat/util/threads/TaskQueue.java
tomcat/trunk/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java
tomcat/trunk/webapps/docs/changelog.xml
Modified: tomcat/trunk/java/org/apache/tomcat/util/threads/TaskQueue.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/threads/TaskQueue.java?rev=1003183&r1=1003182&r2=1003183&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/threads/TaskQueue.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/threads/TaskQueue.java Thu Sep 30
17:56:42 2010
@@ -19,8 +19,8 @@ package org.apache.tomcat.util.threads;
import java.util.Collection;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+
/**
* As task queue specifically designed to run with a thread pool executor.
* The task queue is optimised to properly utilize threads within
@@ -65,7 +65,7 @@ public class TaskQueue extends LinkedBlo
//we are maxed out on threads, simply queue the object
if (parent.getPoolSize() == parent.getMaximumPoolSize()) return
super.offer(o);
//we have idle threads, just add it to the queue
- if (parent.getActiveCount()<(parent.getPoolSize())) return
super.offer(o);
+ if (parent.getSubmittedCount()<(parent.getPoolSize())) return
super.offer(o);
//if we have less threads than maximum force creation of a new thread
if (parent.getPoolSize()<parent.getMaximumPoolSize()) return false;
//if we reached here, we need to add it to the queue
Modified:
tomcat/trunk/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java?rev=1003183&r1=1003182&r2=1003183&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java
Thu Sep 30 17:56:42 2010
@@ -24,7 +24,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Same as a java.util.concurrent.ThreadPoolExecutor but implements a much
more efficient
- * getActiveCount method, to be used to properly handle the work queue
+ * {...@link #getSubmittedCount()} method, to be used to properly handle the
work queue.
* If a RejectedExecutionHandler is not specified a default one will be
configured
* and that one will always throw a RejectedExecutionException
* @author fhanik
@@ -32,7 +32,13 @@ import java.util.concurrent.atomic.Atomi
*/
public class ThreadPoolExecutor extends
java.util.concurrent.ThreadPoolExecutor {
- private final AtomicInteger activeCount = new AtomicInteger(0);
+ /**
+ * The number of tasks submitted but not yet finished. This includes tasks
+ * in the queue and tasks that have been handed to a worker thread but the
+ * latter did not start executing the task yet.
+ * This number is always greater or equal to {...@link #getActiveCount()}.
+ */
+ private final AtomicInteger submittedCount = new AtomicInteger(0);
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long
keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
handler);
@@ -53,17 +59,11 @@ public class ThreadPoolExecutor extends
@Override
protected void afterExecute(Runnable r, Throwable t) {
- activeCount.decrementAndGet();
- }
-
- @Override
- protected void beforeExecute(Thread t, Runnable r) {
- activeCount.incrementAndGet();
+ submittedCount.decrementAndGet();
}
- @Override
- public int getActiveCount() {
- return activeCount.get();
+ public int getSubmittedCount() {
+ return submittedCount.get();
}
/**
@@ -88,6 +88,7 @@ public class ThreadPoolExecutor extends
* @throws NullPointerException if command or unit is null
*/
public void execute(Runnable command, long timeout, TimeUnit unit) {
+ submittedCount.incrementAndGet();
try {
super.execute(command);
} catch (RejectedExecutionException rx) {
@@ -95,13 +96,16 @@ public class ThreadPoolExecutor extends
final TaskQueue queue = (TaskQueue)super.getQueue();
try {
if (!queue.force(command, timeout, unit)) {
+ submittedCount.decrementAndGet();
throw new RejectedExecutionException("Queue capacity
is full.");
}
} catch (InterruptedException x) {
+ submittedCount.decrementAndGet();
Thread.interrupted();
throw new RejectedExecutionException(x);
}
} else {
+ submittedCount.decrementAndGet();
throw rx;
}
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1003183&r1=1003182&r2=1003183&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Thu Sep 30 17:56:42 2010
@@ -87,6 +87,11 @@
managing the PID file and Tomcat does not have write access. (markt)
</fix>
<fix>
+ <bug>49730</bug>: Fix a race condition in StandardThreadExector that
can
+ cause requests to experience large delays. Patch provided by Sylvain
+ Laurent. (markt)
+ </fix>
+ <fix>
<bug>49749</bug>: Single sign on cookies should have httpOnly flag set
using same rules as session cookies. (markt)
</fix>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]