rewrite mailbox selection logic, see #3342

- add “mailbox-requirement” key to dispatcher section
- split out mailbox section, add akka.actor.default-mailbox
- rewrite findMarker method and use it for Props.create() and getting
  the required mailbox of an actor
- add ProducesMessageQueue trait for MailboxType so that requirements
  can be checked before trying to create the actor for real
- verify actor as well as dispatcher requirements for message queue
  before creation, even in remote-deployed case
- change MessageDispatcher constructor to take a Configurator, add that
  to migration guide
This commit is contained in:
Roland 2013-06-01 21:58:34 +02:00
parent 51ed174432
commit f317aaf711
37 changed files with 843 additions and 419 deletions

View file

@ -347,7 +347,7 @@ trait MessageQueue {
def cleanUp(owner: ActorRef, deadLetters: MessageQueue): Unit
}
class NodeMessageQueue extends AbstractNodeQueue[Envelope] with MessageQueue {
class NodeMessageQueue extends AbstractNodeQueue[Envelope] with MessageQueue with UnboundedMessageQueueSemantics {
final def enqueue(receiver: ActorRef, handle: Envelope): Unit = add(handle)
@ -418,10 +418,16 @@ private[akka] trait DefaultSystemMessageQueue { self: Mailbox ⇒
}
/**
* This is a marker trait for message queues which support multiple consumers,
* as is required by the BalancingDispatcher.
*/
trait MultipleConsumerSemantics
/**
* A QueueBasedMessageQueue is a MessageQueue backed by a java.util.Queue.
*/
trait QueueBasedMessageQueue extends MessageQueue {
trait QueueBasedMessageQueue extends MessageQueue with MultipleConsumerSemantics {
def queue: Queue[Envelope]
def numberOfMessages = queue.size
def hasMessages = !queue.isEmpty
@ -440,7 +446,9 @@ trait QueueBasedMessageQueue extends MessageQueue {
* UnboundedMessageQueueSemantics adds unbounded semantics to a QueueBasedMessageQueue,
* i.e. a non-blocking enqueue and dequeue.
*/
trait UnboundedMessageQueueSemantics extends QueueBasedMessageQueue {
trait UnboundedMessageQueueSemantics
trait UnboundedQueueBasedMessageQueue extends QueueBasedMessageQueue with UnboundedMessageQueueSemantics {
def enqueue(receiver: ActorRef, handle: Envelope): Unit = queue add handle
def dequeue(): Envelope = queue.poll()
}
@ -449,8 +457,11 @@ trait UnboundedMessageQueueSemantics extends QueueBasedMessageQueue {
* BoundedMessageQueueSemantics adds bounded semantics to a QueueBasedMessageQueue,
* i.e. blocking enqueue with timeout.
*/
trait BoundedMessageQueueSemantics extends QueueBasedMessageQueue {
trait BoundedMessageQueueSemantics {
def pushTimeOut: Duration
}
trait BoundedQueueBasedMessageQueue extends QueueBasedMessageQueue with BoundedMessageQueueSemantics {
override def queue: BlockingQueue[Envelope]
def enqueue(receiver: ActorRef, handle: Envelope): Unit =
@ -466,16 +477,23 @@ trait BoundedMessageQueueSemantics extends QueueBasedMessageQueue {
/**
* DequeBasedMessageQueue refines QueueBasedMessageQueue to be backed by a java.util.Deque.
*/
trait DequeBasedMessageQueue extends QueueBasedMessageQueue {
def queue: Deque[Envelope]
trait DequeBasedMessageQueueSemantics {
def enqueueFirst(receiver: ActorRef, handle: Envelope): Unit
}
trait UnboundedDequeBasedMessageQueueSemantics extends DequeBasedMessageQueueSemantics with UnboundedMessageQueueSemantics
trait BoundedDequeBasedMessageQueueSemantics extends DequeBasedMessageQueueSemantics with BoundedMessageQueueSemantics
trait DequeBasedMessageQueue extends QueueBasedMessageQueue with DequeBasedMessageQueueSemantics {
def queue: Deque[Envelope]
}
/**
* UnboundedDequeBasedMessageQueueSemantics adds unbounded semantics to a DequeBasedMessageQueue,
* i.e. a non-blocking enqueue and dequeue.
*/
trait UnboundedDequeBasedMessageQueueSemantics extends DequeBasedMessageQueue {
trait UnboundedDequeBasedMessageQueue extends DequeBasedMessageQueue with UnboundedDequeBasedMessageQueueSemantics {
def enqueue(receiver: ActorRef, handle: Envelope): Unit = queue add handle
def enqueueFirst(receiver: ActorRef, handle: Envelope): Unit = queue addFirst handle
def dequeue(): Envelope = queue.poll()
@ -485,7 +503,7 @@ trait UnboundedDequeBasedMessageQueueSemantics extends DequeBasedMessageQueue {
* BoundedMessageQueueSemantics adds bounded semantics to a DequeBasedMessageQueue,
* i.e. blocking enqueue with timeout.
*/
trait BoundedDequeBasedMessageQueueSemantics extends DequeBasedMessageQueue {
trait BoundedDequeBasedMessageQueue extends DequeBasedMessageQueue with BoundedDequeBasedMessageQueueSemantics {
def pushTimeOut: Duration
override def queue: BlockingDeque[Envelope]
@ -523,17 +541,23 @@ trait MailboxType {
def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue
}
trait ProducesMessageQueue[T <: MessageQueue]
/**
* UnboundedMailbox is the default unbounded MailboxType used by Akka Actors.
*/
case class UnboundedMailbox() extends MailboxType {
case class UnboundedMailbox() extends MailboxType with ProducesMessageQueue[UnboundedMailbox.MessageQueue] {
def this(settings: ActorSystem.Settings, config: Config) = this()
final override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue =
new ConcurrentLinkedQueue[Envelope]() with QueueBasedMessageQueue with UnboundedMessageQueueSemantics {
final def queue: Queue[Envelope] = this
}
new UnboundedMailbox.MessageQueue
}
object UnboundedMailbox {
class MessageQueue extends ConcurrentLinkedQueue[Envelope] with UnboundedQueueBasedMessageQueue {
final def queue: Queue[Envelope] = this
}
}
/**
@ -541,17 +565,18 @@ case class UnboundedMailbox() extends MailboxType {
* the only drawback is that you can't have multiple consumers,
* which rules out using it with BalancingDispatcher for instance.
*/
case class SingleConsumerOnlyUnboundedMailbox() extends MailboxType {
case class SingleConsumerOnlyUnboundedMailbox() extends MailboxType with ProducesMessageQueue[NodeMessageQueue] {
def this(settings: ActorSystem.Settings, config: Config) = this()
final override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue = new NodeMessageQueue()
final override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue = new NodeMessageQueue
}
/**
* BoundedMailbox is the default bounded MailboxType used by Akka Actors.
*/
case class BoundedMailbox( final val capacity: Int, final val pushTimeOut: FiniteDuration) extends MailboxType {
case class BoundedMailbox(val capacity: Int, val pushTimeOut: FiniteDuration)
extends MailboxType with ProducesMessageQueue[BoundedMailbox.MessageQueue] {
def this(settings: ActorSystem.Settings, config: Config) = this(config.getInt("mailbox-capacity"),
Duration(config.getNanoseconds("mailbox-push-timeout-time"), TimeUnit.NANOSECONDS))
@ -560,57 +585,78 @@ case class BoundedMailbox( final val capacity: Int, final val pushTimeOut: Finit
if (pushTimeOut eq null) throw new IllegalArgumentException("The push time-out for BoundedMailbox can not be null")
final override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue =
new LinkedBlockingQueue[Envelope](capacity) with QueueBasedMessageQueue with BoundedMessageQueueSemantics {
final def queue: BlockingQueue[Envelope] = this
final val pushTimeOut = BoundedMailbox.this.pushTimeOut
}
new BoundedMailbox.MessageQueue(capacity, pushTimeOut)
}
object BoundedMailbox {
class MessageQueue(capacity: Int, final val pushTimeOut: FiniteDuration)
extends LinkedBlockingQueue[Envelope](capacity) with BoundedQueueBasedMessageQueue {
final def queue: BlockingQueue[Envelope] = this
}
}
/**
* UnboundedPriorityMailbox is an unbounded mailbox that allows for prioritization of its contents.
* Extend this class and provide the Comparator in the constructor.
*/
class UnboundedPriorityMailbox( final val cmp: Comparator[Envelope], final val initialCapacity: Int) extends MailboxType {
class UnboundedPriorityMailbox(val cmp: Comparator[Envelope], val initialCapacity: Int)
extends MailboxType with ProducesMessageQueue[UnboundedPriorityMailbox.MessageQueue] {
def this(cmp: Comparator[Envelope]) = this(cmp, 11)
final override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue =
new PriorityBlockingQueue[Envelope](initialCapacity, cmp) with QueueBasedMessageQueue with UnboundedMessageQueueSemantics {
final def queue: Queue[Envelope] = this
}
new UnboundedPriorityMailbox.MessageQueue(initialCapacity, cmp)
}
object UnboundedPriorityMailbox {
class MessageQueue(initialCapacity: Int, cmp: Comparator[Envelope])
extends PriorityBlockingQueue[Envelope](initialCapacity, cmp) with UnboundedQueueBasedMessageQueue {
final def queue: Queue[Envelope] = this
}
}
/**
* BoundedPriorityMailbox is a bounded mailbox that allows for prioritization of its contents.
* Extend this class and provide the Comparator in the constructor.
*/
class BoundedPriorityMailbox( final val cmp: Comparator[Envelope], final val capacity: Int, final val pushTimeOut: Duration) extends MailboxType {
class BoundedPriorityMailbox( final val cmp: Comparator[Envelope], final val capacity: Int, final val pushTimeOut: Duration)
extends MailboxType with ProducesMessageQueue[BoundedPriorityMailbox.MessageQueue] {
if (capacity < 0) throw new IllegalArgumentException("The capacity for BoundedMailbox can not be negative")
if (pushTimeOut eq null) throw new IllegalArgumentException("The push time-out for BoundedMailbox can not be null")
final override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue =
new BoundedBlockingQueue[Envelope](capacity, new PriorityQueue[Envelope](11, cmp)) with QueueBasedMessageQueue with BoundedMessageQueueSemantics {
final def queue: BlockingQueue[Envelope] = this
final val pushTimeOut = BoundedPriorityMailbox.this.pushTimeOut
}
new BoundedPriorityMailbox.MessageQueue(capacity, cmp, pushTimeOut)
}
object BoundedPriorityMailbox {
class MessageQueue(capacity: Int, cmp: Comparator[Envelope], val pushTimeOut: Duration)
extends BoundedBlockingQueue[Envelope](capacity, new PriorityQueue[Envelope](11, cmp))
with BoundedQueueBasedMessageQueue {
final def queue: BlockingQueue[Envelope] = this
}
}
/**
* UnboundedDequeBasedMailbox is an unbounded MailboxType, backed by a Deque.
*/
case class UnboundedDequeBasedMailbox() extends MailboxType {
case class UnboundedDequeBasedMailbox() extends MailboxType with ProducesMessageQueue[UnboundedDequeBasedMailbox.MessageQueue] {
def this(settings: ActorSystem.Settings, config: Config) = this()
final override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue =
new LinkedBlockingDeque[Envelope]() with DequeBasedMessageQueue with UnboundedDequeBasedMessageQueueSemantics {
final val queue = this
}
new UnboundedDequeBasedMailbox.MessageQueue
}
object UnboundedDequeBasedMailbox {
class MessageQueue extends LinkedBlockingDeque[Envelope] with UnboundedDequeBasedMessageQueue {
final val queue = this
}
}
/**
* BoundedDequeBasedMailbox is an bounded MailboxType, backed by a Deque.
*/
case class BoundedDequeBasedMailbox( final val capacity: Int, final val pushTimeOut: FiniteDuration) extends MailboxType {
case class BoundedDequeBasedMailbox( final val capacity: Int, final val pushTimeOut: FiniteDuration)
extends MailboxType with ProducesMessageQueue[BoundedDequeBasedMailbox.MessageQueue] {
def this(settings: ActorSystem.Settings, config: Config) = this(config.getInt("mailbox-capacity"),
Duration(config.getNanoseconds("mailbox-push-timeout-time"), TimeUnit.NANOSECONDS))
@ -619,10 +665,14 @@ case class BoundedDequeBasedMailbox( final val capacity: Int, final val pushTime
if (pushTimeOut eq null) throw new IllegalArgumentException("The push time-out for BoundedDequeBasedMailbox can not be null")
final override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue =
new LinkedBlockingDeque[Envelope](capacity) with DequeBasedMessageQueue with BoundedDequeBasedMessageQueueSemantics {
final val queue = this
final val pushTimeOut = BoundedDequeBasedMailbox.this.pushTimeOut
}
new BoundedDequeBasedMailbox.MessageQueue(capacity, pushTimeOut)
}
object BoundedDequeBasedMailbox {
class MessageQueue(capacity: Int, val pushTimeOut: FiniteDuration)
extends LinkedBlockingDeque[Envelope](capacity) with BoundedDequeBasedMessageQueue {
final val queue = this
}
}
/**