2009-05-25 14:48:43 +02:00
/* *
* Copyright ( C ) 2009 Scalable Solutions .
*/
/* *
2009-05-25 15:18:18 +02:00
* Implements the Reactor pattern as defined in : [ http :// www . cs . wustl . edu /~ schmidt / PDF / reactor - siemens . pdf ] .
* See also this article : [ http :// today . java . net / cs / user / print / a / 3 5 0 ] .
*
2009-05-25 14:48:43 +02:00
* Based on code from the actorom actor framework by Sergio Bossa [ http :// code . google . com / p / actorom / ] .
*/
package se.scalablesolutions.akka.kernel.reactor
2009-06-11 13:52:22 +02:00
class EventBasedThreadPoolDispatcher extends MessageDispatcherBase {
2009-06-05 22:08:53 +02:00
import java.util.concurrent.Executors
import java.util.HashSet
// FIXME: make configurable using configgy + JMX
// FIXME: create one executor per invocation to dispatch(..), grab config settings for specific actor (set in registerHandler)
2009-06-10 20:04:33 +02:00
private val threadPoolSize : Int = 100
2009-05-25 14:48:43 +02:00
private val busyHandlers = new HashSet [ AnyRef ]
2009-06-10 20:04:33 +02:00
private val handlerExecutor = Executors . newCachedThreadPool ( )
2009-05-25 14:48:43 +02:00
2009-06-05 22:08:53 +02:00
def start = if ( ! active ) {
active = true
2009-06-11 13:52:22 +02:00
val messageDemultiplexer = new EventBasedThreadPoolDemultiplexer ( messageQueue )
2009-06-05 22:08:53 +02:00
selectorThread = new Thread {
2009-06-10 20:04:33 +02:00
//val enqued = new LinkedList[MessageHandle]
2009-06-05 22:08:53 +02:00
override def run = {
while ( active ) {
try {
guard . synchronized { /* empty */ } // prevents risk for deadlock as described in [http://developers.sun.com/learning/javaoneonline/2006/coreplatform/TS-1315.pdf]
2009-05-25 14:48:43 +02:00
try {
2009-06-03 02:41:10 +02:00
guard . synchronized { /* empty */ } // prevents risk for deadlock as described in [http://developers.sun.com/learning/javaoneonline/2006/coreplatform/TS-1315.pdf]
2009-05-25 14:48:43 +02:00
messageDemultiplexer . select
2009-06-05 22:08:53 +02:00
} catch { case e : InterruptedException => active = false }
val queue = messageDemultiplexer . acquireSelectedQueue
2009-06-10 20:04:33 +02:00
// while (!queue.isEmpty) {
2009-06-05 22:08:53 +02:00
for ( index <- 0 until queue . size ) {
val message = queue . peek
val messageHandler = getIfNotBusy ( message . sender )
if ( messageHandler . isDefined ) {
handlerExecutor . execute ( new Runnable {
override def run = {
messageHandler . get . handle ( message )
free ( message . sender )
messageDemultiplexer . wakeUp
}
} )
queue . remove
2009-05-25 14:48:43 +02:00
}
}
2009-06-10 20:04:33 +02:00
// }
if ( ! queue . isEmpty ) {
for ( index <- 0 until queue . size ) messageQueue . append ( queue . remove )
}
2009-06-05 22:08:53 +02:00
} finally {
messageDemultiplexer . releaseSelectedQueue
2009-05-25 14:48:43 +02:00
}
}
2009-06-05 22:08:53 +02:00
}
} ;
selectorThread . start
2009-05-25 14:48:43 +02:00
}
2009-06-05 22:08:53 +02:00
override protected def doShutdown = handlerExecutor . shutdownNow
2009-05-25 14:48:43 +02:00
2009-06-05 22:08:53 +02:00
private def getIfNotBusy ( key : AnyRef ) : Option [ MessageHandler ] = synchronized {
if ( ! busyHandlers . contains ( key ) && messageHandlers . containsKey ( key ) ) {
2009-05-25 14:48:43 +02:00
busyHandlers . add ( key )
2009-06-05 22:08:53 +02:00
Some ( messageHandlers . get ( key ) )
2009-05-25 14:48:43 +02:00
} else None
}
private def free ( key : AnyRef ) = synchronized { busyHandlers . remove ( key ) }
}
2009-06-11 13:52:22 +02:00
class EventBasedThreadPoolDemultiplexer ( private val messageQueue : MessageQueue ) extends MessageDemultiplexer {
2009-06-05 22:08:53 +02:00
import java.util.concurrent.locks.ReentrantLock
import java.util. { LinkedList , Queue }
2009-05-25 14:48:43 +02:00
private val selectedQueue : Queue [ MessageHandle ] = new LinkedList [ MessageHandle ]
private val selectedQueueLock = new ReentrantLock
def select = try {
selectedQueueLock . lock
messageQueue . read ( selectedQueue )
} finally {
selectedQueueLock . unlock
}
def acquireSelectedQueue : Queue [ MessageHandle ] = {
selectedQueueLock . lock
selectedQueue
}
2009-06-10 20:04:33 +02:00
def releaseSelectedQueue = {
selectedQueue . clear
selectedQueueLock . unlock
}
2009-05-25 14:48:43 +02:00
def wakeUp = messageQueue . interrupt
}