make system.actorOf() non-blocking (and working), see #2031
- introducing RepointableActorRef, which starts out with an UnstartedActorCell which can cheaply be created; the Supervise() message will trigger child.activate() in the supervisor, which means that the actual creation (now with normal ActorCell) happens exactly in the right place and with the right semantics. Messages which were enqueued to the dummy cell are transferred atomically into the ActorCell (using normal .tell()), so message sends keep working exactly as they used to - this enables getting rid of the brittle synchronization around RoutedActorRef by replacing that one with a RepointableActorRef subclass which creates RoutedActorCells upon activate(), with the nice benefit that there is no hurry then to get it right because the new cell is constructed “on the side” misc fixes: - InvalidMessageException is now actually enforced when trying to send “null” - Mailboxes may be created without having an ActorCell, which can come in handy later, because the cell is only needed when this mailbox is going to be scheduled on some executor - remove occurrences of Props(), which is equivalent to Props[Nothing], which is equivalent to «bug» - add test case which verifies that context.actorOf is still synchronous - plus all the stuff I have forgotten.
This commit is contained in:
parent
8cd11550fa
commit
b60210362e
37 changed files with 772 additions and 310 deletions
|
|
@ -1,14 +1,17 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
package akka.dispatch
|
||||
|
||||
import org.scalatest.{ BeforeAndAfterAll, BeforeAndAfterEach }
|
||||
import java.util.concurrent.{ TimeUnit, BlockingQueue }
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import akka.util._
|
||||
import akka.util.duration._
|
||||
import akka.testkit.AkkaSpec
|
||||
import akka.actor.{ ActorRef, ActorContext, Props, LocalActorRef }
|
||||
import java.util.concurrent.{ ConcurrentLinkedQueue, BlockingQueue }
|
||||
|
||||
import org.scalatest.{ BeforeAndAfterEach, BeforeAndAfterAll }
|
||||
|
||||
import com.typesafe.config.Config
|
||||
import akka.actor.ActorSystem
|
||||
|
||||
import akka.actor.{ RepointableRef, Props, ActorSystem, ActorRefWithCell, ActorRef, ActorCell }
|
||||
import akka.testkit.AkkaSpec
|
||||
import akka.util.duration._
|
||||
|
||||
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
|
||||
abstract class MailboxSpec extends AkkaSpec with BeforeAndAfterAll with BeforeAndAfterEach {
|
||||
|
|
@ -75,7 +78,7 @@ abstract class MailboxSpec extends AkkaSpec with BeforeAndAfterAll with BeforeAn
|
|||
result
|
||||
}
|
||||
|
||||
def createMessageInvocation(msg: Any): Envelope = Envelope(msg, system.deadLetters)(system)
|
||||
def createMessageInvocation(msg: Any): Envelope = Envelope(msg, system.deadLetters, system)
|
||||
|
||||
def ensureInitialMailboxState(config: MailboxType, q: MessageQueue) {
|
||||
q must not be null
|
||||
|
|
@ -136,8 +139,8 @@ abstract class MailboxSpec extends AkkaSpec with BeforeAndAfterAll with BeforeAn
|
|||
class DefaultMailboxSpec extends MailboxSpec {
|
||||
lazy val name = "The default mailbox implementation"
|
||||
def factory = {
|
||||
case u: UnboundedMailbox ⇒ u.create(None)
|
||||
case b: BoundedMailbox ⇒ b.create(None)
|
||||
case u: UnboundedMailbox ⇒ u.create(None, None)
|
||||
case b: BoundedMailbox ⇒ b.create(None, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -145,8 +148,8 @@ class PriorityMailboxSpec extends MailboxSpec {
|
|||
val comparator = PriorityGenerator(_.##)
|
||||
lazy val name = "The priority mailbox implementation"
|
||||
def factory = {
|
||||
case UnboundedMailbox() ⇒ new UnboundedPriorityMailbox(comparator).create(None)
|
||||
case BoundedMailbox(capacity, pushTimeOut) ⇒ new BoundedPriorityMailbox(comparator, capacity, pushTimeOut).create(None)
|
||||
case UnboundedMailbox() ⇒ new UnboundedPriorityMailbox(comparator).create(None, None)
|
||||
case BoundedMailbox(capacity, pushTimeOut) ⇒ new BoundedPriorityMailbox(comparator, capacity, pushTimeOut).create(None, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -158,13 +161,13 @@ object CustomMailboxSpec {
|
|||
"""
|
||||
|
||||
class MyMailboxType(settings: ActorSystem.Settings, config: Config) extends MailboxType {
|
||||
override def create(owner: Option[ActorContext]) = owner match {
|
||||
override def create(owner: Option[ActorRef], system: Option[ActorSystem]) = owner match {
|
||||
case Some(o) ⇒ new MyMailbox(o)
|
||||
case None ⇒ throw new Exception("no mailbox owner given")
|
||||
}
|
||||
}
|
||||
|
||||
class MyMailbox(owner: ActorContext) extends QueueBasedMessageQueue with UnboundedMessageQueueSemantics {
|
||||
class MyMailbox(owner: ActorRef) extends QueueBasedMessageQueue with UnboundedMessageQueueSemantics {
|
||||
final val queue = new ConcurrentLinkedQueue[Envelope]()
|
||||
}
|
||||
}
|
||||
|
|
@ -174,7 +177,11 @@ class CustomMailboxSpec extends AkkaSpec(CustomMailboxSpec.config) {
|
|||
"Dispatcher configuration" must {
|
||||
"support custom mailboxType" in {
|
||||
val actor = system.actorOf(Props.empty.withDispatcher("my-dispatcher"))
|
||||
val queue = actor.asInstanceOf[LocalActorRef].underlying.mailbox.messageQueue
|
||||
awaitCond(actor match {
|
||||
case r: RepointableRef ⇒ r.isStarted
|
||||
case _ ⇒ true
|
||||
}, 1 second, 10 millis)
|
||||
val queue = actor.asInstanceOf[ActorRefWithCell].underlying.asInstanceOf[ActorCell].mailbox.messageQueue
|
||||
queue.getClass must be(classOf[CustomMailboxSpec.MyMailbox])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue