org.curjent.impl.agent
Class ExpirationsTask

java.lang.Object
  extended by org.curjent.impl.agent.ExpirationsTask
All Implemented Interfaces:
Runnable

final class ExpirationsTask
extends Object
implements Runnable

Background task for expiring messages. Uses the controller's executor (Messengers.getExecutor()) to run the task. The task only runs when there are timers to process.


Field Summary
private  Controller controller
          Owning controller.
private  ArrayList<ExpirationsTimer> feed
          New timers from the controller are queued in a simple list and processed in the background.
private  Condition monitor
          Synchronization monitor for timer feeds.
private  PriorityBlockingQueue<ExpirationsTimer> queue
          Ordered queue of timers.
private  AtomicBoolean running
          Starting, stopping, and restarting the background task is coordinated using AtomicBoolean.compareAndSet(boolean, boolean).
private  ExpirationsTimer[] timers
          Enqueued timers from feed are copied to this buffer while the controller is locked so that they can be processed outside of the lock.
 
Constructor Summary
ExpirationsTask(Controller controller, ReentrantLock lock)
          Saves the controller and its lock for internal use.
 
Method Summary
private  boolean awaitFeed(long timeout)
          Waits for new timers to queue, or for the given timeout period.
(package private)  void enqueue(ExpirationsTimer timer)
          Enqueues a new timer for expiration.
private  long processQueue()
          Dequeues and expires messages.
 void run()
          Runs the background task for as long as there are more timers to process.
(package private)  void signal()
          Notifies the background task that a message has finished.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

controller

private final Controller controller
Owning controller. Foreground operations, such as enqueueing a new timer, assume the controller is locked. Background tasks, such as polling for enqueued timers, explicitly lock the controller.


monitor

private final Condition monitor
Synchronization monitor for timer feeds.

See Also:
feed

running

private final AtomicBoolean running
Starting, stopping, and restarting the background task is coordinated using AtomicBoolean.compareAndSet(boolean, boolean).


feed

private final ArrayList<ExpirationsTimer> feed
New timers from the controller are queued in a simple list and processed in the background. This defers the overhead of priority ordering to the background thread outside of the controller's lock. The controller is locked to add and pull new timers to the feed via timers, but those timers are added to queue in the background without locking the controller.


timers

private ExpirationsTimer[] timers
Enqueued timers from feed are copied to this buffer while the controller is locked so that they can be processed outside of the lock. The awaitFeed(long) expands this buffer as needed.

Thread safety is ensured by updating the buffer while the controller is locked and only reading from it when unlocked. Reading is safe since only one background executor thread accesses the buffer at a time. The JVM memory model ensures consistency across threads used by the controller's executor.


queue

private final PriorityBlockingQueue<ExpirationsTimer> queue
Ordered queue of timers. A synchronized queue implementation is used to ensure consistency across executor threads. Only the background task accesses the queue. New timers are fed to the task via feed.

Constructor Detail

ExpirationsTask

ExpirationsTask(Controller controller,
                ReentrantLock lock)
Saves the controller and its lock for internal use.

Method Detail

enqueue

void enqueue(ExpirationsTimer timer)
Enqueues a new timer for expiration. Starts the background task if needed.

Called while the controller is locked.


signal

void signal()
Notifies the background task that a message has finished.

Called while the controller is locked.


run

public void run()
Runs the background task for as long as there are more timers to process. Exits once all timers are processed. Waits on a condition of the controller's lock for timing out the next message.

Specified by:
run in interface Runnable

processQueue

private long processQueue()
Dequeues and expires messages. Also cleans up finished messages. Returns the amount of time the background task should wait before timing out the next message. Returns Long.MAX_VALUE if the queue is empty.


awaitFeed

private boolean awaitFeed(long timeout)
                   throws InterruptedException
Waits for new timers to queue, or for the given timeout period. Notifications for new timers are signaled via monitor. The timeout is specified by processQueue() and denotes how long the task should wait to expire the next message. A timeout value of Long.MAX_VALUE means the priority queue is empty.

Returns true if there are more timers in the queue to process. Sets running to false and returns the same if there are no more timers, and the task should exit.

Throws:
InterruptedException


Copyright 2009-2011 Tom Landon
Apache License 2.0