From 48bb75b7dc1ae418709af6f2193afde4a3c0f6ba Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Tue, 20 Jan 2009 12:53:41 +0000 Subject: [PATCH] Fixed a problem where calling Timeout.extend() generates multiple timeouts when the timeout is not expired --- .../handler/timeout/HashedWheelTimer.java | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jboss/netty/handler/timeout/HashedWheelTimer.java b/src/main/java/org/jboss/netty/handler/timeout/HashedWheelTimer.java index e5f05b2a94..fcbdc32a3c 100644 --- a/src/main/java/org/jboss/netty/handler/timeout/HashedWheelTimer.java +++ b/src/main/java/org/jboss/netty/handler/timeout/HashedWheelTimer.java @@ -54,7 +54,7 @@ public class HashedWheelTimer implements Timer { private static final AtomicInteger id = new AtomicInteger(); private final Worker worker = new Worker(); - private final Thread workerThread; + final Thread workerThread; final AtomicBoolean shutdown = new AtomicBoolean(); private final long roundDuration; @@ -423,10 +423,22 @@ public class HashedWheelTimer implements Timer { lock.readLock().lock(); try { // Reinsert the timeout to the appropriate bucket. + int oldStopIndex; int newStopIndex; synchronized (this) { - newStopIndex = stopIndex = schedule(this, additionalDelay); + oldStopIndex = stopIndex; + stopIndex = newStopIndex = schedule(this, additionalDelay); } + + // Remove the timeout from the old bucket if necessary. + // If this method is called from the worker thread, it means + // this timeout has been removed from the bucket already. + if (oldStopIndex != newStopIndex && + Thread.currentThread() != workerThread) { + wheel[oldStopIndex].remove(this); + } + + // And add to the new bucket. If added already, that's fine. wheel[newStopIndex].add(this); } finally { extensionCount ++; @@ -514,4 +526,16 @@ public class HashedWheelTimer implements Timer { return buf.append(')').toString(); } } + + public static void main(String[] args) throws Exception { + Timer timer = new HashedWheelTimer(); + for (int i = 0; i < 100000; i ++) { + timer.newTimeout(new TimerTask() { + public void run(Timeout timeout) throws Exception { + // Extend another second. + timeout.extend(); + } + }, 1000, TimeUnit.MILLISECONDS); + } + } }