public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) { if (task == null) { throw new NullPointerException("task"); } if (unit == null) { throw new NullPointerException("unit"); } start(); // Add the timeout to the timeout queue which will be processed on the next tick. // During processing all the queued HashedWheelTimeouts will be added to the correct HashedWheelBucket. long deadline = System.nanoTime() + unit.toNanos(delay) - startTime; HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline); timeouts.add(timeout); return timeout; }
private void transferTimeoutsToBuckets() { // transfer only max. 100000 timeouts per tick to prevent a thread to stale the workerThread when it just // adds new timeouts in a loop. for (int i = 0; i < 100000; i++) { HashedWheelTimeout timeout = timeouts.poll(); if (timeout == null) { // all processed break; } if (timeout.state() == HashedWheelTimeout.ST_CANCELLED || !timeout.compareAndSetState(HashedWheelTimeout.ST_INIT, HashedWheelTimeout.ST_IN_BUCKET)) { // Was cancelled in the meantime. So just remove it and continue with next HashedWheelTimeout // in the queue timeout.remove(); continue; } long calculated = timeout.deadline / tickDuration; long remainingRounds = (calculated - tick) / wheel.length; timeout.remainingRounds = remainingRounds; final long ticks = Math.max(calculated, tick); // Ensure we don't schedule for past. int stopIndex = (int) (ticks & mask); HashedWheelBucket bucket = wheel[stopIndex]; bucket.addTimeout(timeout); } } /**
/** * Expire all {@link HashedWheelTimeout}s for the given {@code deadline}. */ public void expireTimeouts(long deadline) { HashedWheelTimeout timeout = head; // process all timeouts while (timeout != null) { boolean remove = false; if (timeout.remainingRounds <= 0) { if (timeout.deadline <= deadline) { timeout.expire(); } else { // The timeout was placed into a wrong slot. This should never happen. throw new IllegalStateException(String.format( "timeout.deadline (%d) > deadline (%d)", timeout.deadline, deadline)); } remove = true; } else if (timeout.isCancelled()) { remove = true; } else { timeout.remainingRounds --; } // store reference to next as we may null out timeout.next in the remove block. HashedWheelTimeout next = timeout.next; if (remove) { remove(timeout); } timeout = next; } }
/** * Expire all {@link HashedWheelTimeout}s for the given {@code deadline}. */ public void expireTimeouts(long deadline) { HashedWheelTimeout timeout = head; // process all timeouts while (timeout != null) { boolean remove = false; if (timeout.remainingRounds <= 0) { if (timeout.deadline <= deadline) { timeout.expire(); } else { // The timeout was placed into a wrong slot. This should never happen. throw new IllegalStateException(String.format( "timeout.deadline (%d) > deadline (%d)", timeout.deadline, deadline)); } remove = true; } else if (timeout.isCancelled()) { remove = true; } else { timeout.remainingRounds --; } // store reference to next as we may null out timeout.next in the remove block. HashedWheelTimeout next = timeout.next; if (remove) { remove(timeout); } timeout = next; } }
@Override public String toString() { final long currentTime = System.nanoTime(); long remaining = deadline - currentTime + timer.startTime; StringBuilder buf = new StringBuilder(192); buf.append(getClass().getSimpleName()); buf.append('('); buf.append("deadline: "); if (remaining > 0) { buf.append(remaining); buf.append(" ns later"); } else if (remaining < 0) { buf.append(-remaining); buf.append(" ns ago"); } else { buf.append("now"); } if (isCancelled()) { buf.append(", cancelled"); } buf.append(", task: "); buf.append(getTask()); return buf.append(')').toString(); } }
private void transferTimeoutsToBuckets() { // transfer only max. 100000 timeouts per tick to prevent a thread to stale the workerThread when it just // adds new timeouts in a loop. for (int i = 0; i < 100000; i++) { HashedWheelTimeout timeout = timeouts.poll(); if (timeout == null) { // all processed break; } if (timeout.state() == HashedWheelTimeout.ST_CANCELLED || !timeout.compareAndSetState(HashedWheelTimeout.ST_INIT, HashedWheelTimeout.ST_IN_BUCKET)) { // Was cancelled in the meantime. So just remove it and continue with next HashedWheelTimeout // in the queue timeout.remove(); continue; } long calculated = timeout.deadline / tickDuration; long remainingRounds = (calculated - tick) / wheel.length; timeout.remainingRounds = remainingRounds; final long ticks = Math.max(calculated, tick); // Ensure we don't schedule for past. int stopIndex = (int) (ticks & mask); HashedWheelBucket bucket = wheel[stopIndex]; bucket.addTimeout(timeout); } } /**
public void cancel() { int state = state(); if (state >= ST_CANCELLED) { // fail fast if the task was cancelled or expired before. return; } if (state != ST_IN_BUCKET && compareAndSetState(ST_INIT, ST_CANCELLED)) { // Was cancelled before the HashedWheelTimeout was added to its HashedWheelBucket. // In this case we can just return here as it will be discarded by the WorkerThread when handling // the adding of HashedWheelTimeout to the HashedWheelBuckets. return; } // only update the state it will be removed from HashedWheelBucket on next tick. if (!compareAndSetState(ST_IN_BUCKET, ST_CANCELLED)) { return; } // Add the HashedWheelTimeout back to the timeouts queue so it will be picked up on the next tick // and remove this HashedTimeTask from the HashedWheelBucket. After this is done it is ready to get // GC'ed once the user has no reference to it anymore. timer.timeouts.add(this); }
public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) { if (task == null) { throw new NullPointerException("task"); } if (unit == null) { throw new NullPointerException("unit"); } start(); // Add the timeout to the timeout queue which will be processed on the next tick. // During processing all the queued HashedWheelTimeouts will be added to the correct HashedWheelBucket. long deadline = System.nanoTime() + unit.toNanos(delay) - startTime; HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline); timeouts.add(timeout); return timeout; }
/** * Clear this bucket and return all not expired / cancelled {@link Timeout}s. */ public void clearTimeouts(Set<Timeout> set) { for (;;) { HashedWheelTimeout timeout = pollTimeout(); if (timeout == null) { return; } if (timeout.isExpired() || timeout.isCancelled()) { continue; } set.add(timeout); } }
public void expire() { if (!compareAndSetState(ST_IN_BUCKET, ST_EXPIRED)) { assert state() != ST_INIT; return; } try { task.run(this); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn("An exception was thrown by " + TimerTask.class.getSimpleName() + '.', t); } } }
@Override public String toString() { final long currentTime = System.nanoTime(); long remaining = deadline - currentTime + timer.startTime; StringBuilder buf = new StringBuilder(192); buf.append(getClass().getSimpleName()); buf.append('('); buf.append("deadline: "); if (remaining > 0) { buf.append(remaining); buf.append(" ns later"); } else if (remaining < 0) { buf.append(-remaining); buf.append(" ns ago"); } else { buf.append("now"); } if (isCancelled()) { buf.append(", cancelled"); } buf.append(", task: "); buf.append(getTask()); return buf.append(')').toString(); } }
public void cancel() { int state = state(); if (state >= ST_CANCELLED) { // fail fast if the task was cancelled or expired before. return; } if (state != ST_IN_BUCKET && compareAndSetState(ST_INIT, ST_CANCELLED)) { // Was cancelled before the HashedWheelTimeout was added to its HashedWheelBucket. // In this case we can just return here as it will be discarded by the WorkerThread when handling // the adding of HashedWheelTimeout to the HashedWheelBuckets. return; } // only update the state it will be removed from HashedWheelBucket on next tick. if (!compareAndSetState(ST_IN_BUCKET, ST_CANCELLED)) { return; } // Add the HashedWheelTimeout back to the timeouts queue so it will be picked up on the next tick // and remove this HashedTimeTask from the HashedWheelBucket. After this is done it is ready to get // GC'ed once the user has no reference to it anymore. timer.timeouts.add(this); }
/** * Clear this bucket and return all not expired / cancelled {@link Timeout}s. */ public void clearTimeouts(Set<Timeout> set) { for (;;) { HashedWheelTimeout timeout = pollTimeout(); if (timeout == null) { return; } if (timeout.isExpired() || timeout.isCancelled()) { continue; } set.add(timeout); } }
public void expire() { if (!compareAndSetState(ST_IN_BUCKET, ST_EXPIRED)) { assert state() != ST_INIT; return; } try { task.run(this); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn("An exception was thrown by " + TimerTask.class.getSimpleName() + '.', t); } } }