diff --git a/akka-actor/src/main/scala/akka/actor/ActorCell.scala b/akka-actor/src/main/scala/akka/actor/ActorCell.scala index fb1a7a5636..fc49fcc10a 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorCell.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorCell.scala @@ -223,7 +223,7 @@ private[akka] class ActorCell( final var childrenRefs: TreeMap[String, ChildRestartStats] = emptyChildrenRefs private def _actorOf(props: Props, name: String): ActorRef = { - val actor = provider.actorOf(systemImpl, props, guardian, name, false) + val actor = provider.actorOf(systemImpl, props, self, self.path / name, false) childrenRefs = childrenRefs.updated(name, ChildRestartStats(actor)) actor } diff --git a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala index e9f75dba9d..10a750cbe5 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala @@ -80,7 +80,7 @@ trait ActorRefProvider { * in case of remote supervision). If systemService is true, deployment is * bypassed (local-only). */ - def actorOf(system: ActorSystemImpl, props: Props, supervisor: InternalActorRef, name: String, systemService: Boolean = false): InternalActorRef + def actorOf(system: ActorSystemImpl, props: Props, supervisor: InternalActorRef, path: ActorPath, systemService: Boolean): InternalActorRef /** * Create actor reference for a specified local or remote path. If no such @@ -408,31 +408,33 @@ class LocalActorRefProvider( } } + /* + * Guardians can be asked by ActorSystem to create children, i.e. top-level + * actors. Therefore these need to answer to these requests, forwarding any + * exceptions which might have occurred. + */ private class Guardian extends Actor { def receive = { - case Terminated(_) ⇒ context.self.stop() - case CreateChild(child, name) ⇒ sender ! (try context.actorOf(child, name) catch { - case e: Exception ⇒ e - }) - case CreateRandomNameChild(child) ⇒ sender ! (try context.actorOf(child) catch { - case e: Exception ⇒ e - }) - case m ⇒ deadLetters ! DeadLetter(m, sender, self) + case Terminated(_) ⇒ context.self.stop() + case CreateChild(child, name) ⇒ sender ! (try context.actorOf(child, name) catch { case e: Exception ⇒ e }) + case CreateRandomNameChild(child) ⇒ sender ! (try context.actorOf(child) catch { case e: Exception ⇒ e }) + case m ⇒ deadLetters ! DeadLetter(m, sender, self) } } + /* + * Guardians can be asked by ActorSystem to create children, i.e. top-level + * actors. Therefore these need to answer to these requests, forwarding any + * exceptions which might have occurred. + */ private class SystemGuardian extends Actor { def receive = { case Terminated(_) ⇒ eventStream.stopDefaultLoggers() context.self.stop() - case CreateChild(child, name) ⇒ sender ! (try context.actorOf(child, name) catch { - case e: Exception ⇒ e - }) - case CreateRandomNameChild(child) ⇒ sender ! (try context.actorOf(child) catch { - case e: Exception ⇒ e - }) - case m ⇒ deadLetters ! DeadLetter(m, sender, self) + case CreateChild(child, name) ⇒ sender ! (try context.actorOf(child, name) catch { case e: Exception ⇒ e }) + case CreateRandomNameChild(child) ⇒ sender ! (try context.actorOf(child) catch { case e: Exception ⇒ e }) + case m ⇒ deadLetters ! DeadLetter(m, sender, self) } } @@ -463,24 +465,36 @@ class LocalActorRefProvider( @volatile private var extraNames: Map[String, InternalActorRef] = Map() - lazy val rootGuardian: InternalActorRef = new LocalActorRef(system, guardianProps, theOneWhoWalksTheBubblesOfSpaceTime, rootPath, true) { - object Extra { - def unapply(s: String): Option[InternalActorRef] = extraNames.get(s) - } - override def getParent: InternalActorRef = this + /** + * Higher-level providers (or extensions) might want to register new synthetic + * top-level paths for doing special stuff. This is the way to do just that. + * Just be careful to complete all this before ActorSystem.start() finishes, + * or before you start your own auto-spawned actors. + */ + def registerExtraNames(_extras: Map[String, InternalActorRef]): Unit = extraNames ++= _extras - override def getSingleChild(name: String): InternalActorRef = { - name match { - case "temp" ⇒ tempContainer - case Extra(e) ⇒ e - case _ ⇒ super.getSingleChild(name) + lazy val rootGuardian: InternalActorRef = + new LocalActorRef(system, guardianProps, theOneWhoWalksTheBubblesOfSpaceTime, rootPath, true) { + object Extra { + def unapply(s: String): Option[InternalActorRef] = extraNames.get(s) + } + + override def getParent: InternalActorRef = this + + override def getSingleChild(name: String): InternalActorRef = { + name match { + case "temp" ⇒ tempContainer + case Extra(e) ⇒ e + case _ ⇒ super.getSingleChild(name) + } } } - } - lazy val guardian: InternalActorRef = actorOf(system, guardianProps, rootGuardian, "user", true) + lazy val guardian: InternalActorRef = + actorOf(system, guardianProps, rootGuardian, rootPath / "user", true) - lazy val systemGuardian: InternalActorRef = actorOf(system, guardianProps.withCreator(new SystemGuardian), rootGuardian, "system", true) + lazy val systemGuardian: InternalActorRef = + actorOf(system, guardianProps.withCreator(new SystemGuardian), rootGuardian, rootPath / "system", true) lazy val tempContainer = new VirtualPathContainer(tempNode, rootGuardian, log) @@ -494,8 +508,6 @@ class LocalActorRefProvider( eventStream.startDefaultLoggers(_system) } - def registerExtraNames(_extras: Map[String, InternalActorRef]): Unit = extraNames ++= _extras - def actorFor(ref: InternalActorRef, path: String): InternalActorRef = path match { case RelativeActorPath(elems) ⇒ if (elems.isEmpty) deadLetters @@ -516,9 +528,7 @@ class LocalActorRefProvider( case x ⇒ x } - def actorOf(system: ActorSystemImpl, props: Props, supervisor: InternalActorRef, name: String, systemService: Boolean): InternalActorRef = { - val path = supervisor.path / name - + def actorOf(system: ActorSystemImpl, props: Props, supervisor: InternalActorRef, path: ActorPath, systemService: Boolean): InternalActorRef = { props.routerConfig match { case NoRouting ⇒ new LocalActorRef(system, props, supervisor, path, systemService) // create a local actor case routedActor ⇒ new RoutedActorRef(system, props.withRouting(adaptFromDeploy(routedActor, path)), supervisor, path) diff --git a/akka-remote/src/main/scala/akka/remote/Remote.scala b/akka-remote/src/main/scala/akka/remote/Remote.scala index 092dbd8bb6..3572875860 100644 --- a/akka-remote/src/main/scala/akka/remote/Remote.scala +++ b/akka-remote/src/main/scala/akka/remote/Remote.scala @@ -162,7 +162,7 @@ class RemoteSystemDaemon(remote: Remote, _path: ActorPath, _parent: InternalActo val subpath = elems.drop(1) val path = remote.remoteDaemon.path / subpath val supervisor = remote.system.actorFor(message.getSupervisor).asInstanceOf[InternalActorRef] - val actor = new LocalActorRef(remote.system, Props(creator = actorFactory), supervisor, path, true) + val actor = remote.system.provider.actorOf(remote.system, Props(creator = actorFactory), supervisor, path, true) addChild(subpath.mkString("/"), actor) remote.system.deathWatch.subscribe(this, actor) case _ ⇒ diff --git a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala index 56a02219f9..07c855fd6a 100644 --- a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala +++ b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala @@ -56,8 +56,10 @@ class RemoteActorRefProvider( private val local = new LocalActorRefProvider(systemName, settings, eventStream, scheduler, _deadLetters, rootPath, deployer) + @volatile private var serialization: Serialization = _ + @volatile private var _remote: Remote = _ def remote = _remote @@ -69,10 +71,34 @@ class RemoteActorRefProvider( terminationFuture.onComplete(_ ⇒ remote.server.shutdown()) } - def actorOf(system: ActorSystemImpl, props: Props, supervisor: InternalActorRef, name: String, systemService: Boolean): InternalActorRef = - if (systemService) local.actorOf(system, props, supervisor, name, systemService) + def actorOf(system: ActorSystemImpl, props: Props, supervisor: InternalActorRef, path: ActorPath, systemService: Boolean): InternalActorRef = + if (systemService) local.actorOf(system, props, supervisor, path, systemService) else { - val path = supervisor.path / name + + /* + * This needs to deal with “mangled” paths, which are created by remote + * deployment, also in this method. The scheme is the following: + * + * Whenever a remote deployment is found, create a path on that remote + * address below “remote”, including the current system’s identification + * as “sys@host:port” (typically; it will use whatever the remote + * transport uses). This means that on a path up an actor tree each node + * change introduces one layer or “remote/sys@host:port/” within the URI. + * + * Example: + * + * akka://sys@home:1234/remote/sys@remote:6667/remote/sys@other:3333/user/a/b/c + * + * means that the logical parent originates from “sys@other:3333” with + * one child (may be “a” or “b”) being deployed on “sys@remote:6667” and + * finally either “b” or “c” being created on “sys@home:1234”, where + * this whole thing actually resides. Thus, the logical path is + * “/user/a/b/c” and the physical path contains all remote placement + * information. + * + * Deployments are always looked up using the logical path, which is the + * purpose of the lookupRemotes internal method. + */ @scala.annotation.tailrec def lookupRemotes(p: Iterable[String]): Option[DeploymentConfig.Deploy] = { @@ -94,14 +120,14 @@ class RemoteActorRefProvider( deployment match { case Some(DeploymentConfig.Deploy(_, _, _, _, RemoteDeploymentConfig.RemoteScope(address))) ⇒ - if (address == rootPath.address) local.actorOf(system, props, supervisor, name) + if (address == rootPath.address) local.actorOf(system, props, supervisor, path, false) else { val rpath = RootActorPath(address) / "remote" / rootPath.address.hostPort / path.elements useActorOnNode(rpath, props.creator, supervisor) new RemoteActorRef(this, remote.server, rpath, supervisor, None) } - case _ ⇒ local.actorOf(system, props, supervisor, name, systemService) + case _ ⇒ local.actorOf(system, props, supervisor, path, systemService) } }