diff --git a/akka-actor-tests/src/test/scala/akka/actor/SupervisorTreeSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/SupervisorTreeSpec.scala index a77f8c20c1..f8e92b93dc 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/SupervisorTreeSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/SupervisorTreeSpec.scala @@ -24,15 +24,15 @@ class SupervisorTreeSpec extends AkkaSpec with ImplicitSender { def receive = { case p: Props ⇒ sender ! context.actorOf(p) } - override def preRestart(cause: Throwable, msg: Option[Any]) { testActor ! self.address } + override def preRestart(cause: Throwable, msg: Option[Any]) { testActor ! self.path } }).withFaultHandler(OneForOneStrategy(List(classOf[Exception]), 3, 1000)) val headActor = actorOf(p) val middleActor = (headActor ? p).as[ActorRef].get val lastActor = (middleActor ? p).as[ActorRef].get middleActor ! Kill - expectMsg(middleActor.address) - expectMsg(lastActor.address) + expectMsg(middleActor.path) + expectMsg(lastActor.path) expectNoMsg(2 seconds) headActor.stop() } diff --git a/akka-actor-tests/src/test/scala/akka/routing/ActorPoolSpec.scala b/akka-actor-tests/src/test/scala/akka/routing/ActorPoolSpec.scala index d9503e31b7..ff65b46bf5 100644 --- a/akka-actor-tests/src/test/scala/akka/routing/ActorPoolSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/routing/ActorPoolSpec.scala @@ -263,7 +263,7 @@ class ActorPoolSpec extends AkkaSpec { def instance(p: Props): ActorRef = actorOf(p.withCreator(new Actor { def receive = { case _ ⇒ - delegates put (self.address, "") + delegates put (self.path.toString, "") latch1.countDown() } })) @@ -291,7 +291,7 @@ class ActorPoolSpec extends AkkaSpec { def instance(p: Props) = actorOf(p.withCreator(new Actor { def receive = { case _ ⇒ - delegates put (self.address, "") + delegates put (self.path.toString, "") latch2.countDown() } })) diff --git a/akka-actor/src/main/scala/akka/actor/ActorCell.scala b/akka-actor/src/main/scala/akka/actor/ActorCell.scala index 6e40ab8f34..8c17fa418e 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorCell.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorCell.scala @@ -266,15 +266,15 @@ private[akka] class ActorCell( } def supervise(child: ActorRef): Unit = { - val dl = system.deadLetters - childrenRefs.get(child.name) match { - case None | Some(ChildRestartStats(`dl`, _, _)) ⇒ - childrenRefs = childrenRefs.updated(child.name, ChildRestartStats(child)) + childrenRefs.get(child.path.name) match { + case None ⇒ + childrenRefs = childrenRefs.updated(child.path.name, ChildRestartStats(child)) if (system.settings.DebugLifecycle) system.eventStream.publish(Debug(self.path.toString, "now supervising " + child)) case Some(ChildRestartStats(`child`, _, _)) ⇒ - system.eventStream.publish(Warning(self.path.toString, "Already supervising " + child)) + // this is the nominal case where we created the child and entered it in actorCreated() above + if (system.settings.DebugLifecycle) system.eventStream.publish(Debug(self.path.toString, "now supervising " + child)) case Some(ChildRestartStats(c, _, _)) ⇒ - system.eventStream.publish(Warning(self.path.toString, "Already supervising other child with same name '" + child.name + "', old: " + c + " new: " + child)) + system.eventStream.publish(Warning(self.path.toString, "Already supervising other child with same name '" + child.path.name + "', old: " + c + " new: " + child)) } } @@ -392,14 +392,14 @@ private[akka] class ActorCell( } } - final def handleFailure(child: ActorRef, cause: Throwable): Unit = childrenRefs.get(child.name) match { + final def handleFailure(child: ActorRef, cause: Throwable): Unit = childrenRefs.get(child.path.name) match { case Some(stats) if stats.child == child ⇒ if (!props.faultHandler.handleFailure(child, cause, stats, childrenRefs.values)) throw cause case Some(stats) ⇒ system.eventStream.publish(Warning(self.path.toString, "dropping Failed(" + cause + ") from unknown child " + child + " matching names but not the same, was: " + stats.child)) case None ⇒ system.eventStream.publish(Warning(self.path.toString, "dropping Failed(" + cause + ") from unknown child " + child)) } final def handleChildTerminated(child: ActorRef): Unit = { - childrenRefs -= child.name + childrenRefs -= child.path.name props.faultHandler.handleChildTerminated(child, children) if (stopping && childrenRefs.isEmpty) doTerminate() } diff --git a/akka-actor/src/main/scala/akka/actor/ActorPath.scala b/akka-actor/src/main/scala/akka/actor/ActorPath.scala index 4203c5c9b5..1146c4e0f0 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorPath.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorPath.scala @@ -12,8 +12,14 @@ object ActorPath { /** * Actor path is a unique path to an actor that shows the creation path * up through the actor tree to the root actor. + * + * ActorPath defines a natural ordering (so that ActorRefs can be put into + * collections with this requirement); this ordering is intended to be as fast + * as possible, which owing to the bottom-up recursive nature of ActorPath + * is sorted by path elements FROM RIGHT TO LEFT, where RootActorPath > + * ChildActorPath in case the number of elements is different. */ -sealed trait ActorPath { +sealed trait ActorPath extends Comparable[ActorPath] { /** * The Address under which this path can be reached; walks up the tree to * the RootActorPath. @@ -67,6 +73,11 @@ final case class RootActorPath(address: Address, name: String = ActorPath.separa def pathElements: Iterable[String] = Iterable.empty override val toString = address + name + + def compareTo(other: ActorPath) = other match { + case r: RootActorPath ⇒ toString compareTo r.toString + case c: ChildActorPath ⇒ 1 + } } final class ChildActorPath(val parent: ActorPath, val name: String) extends ActorPath { @@ -113,7 +124,8 @@ final class ChildActorPath(val parent: ActorPath, val name: String) extends Acto @tailrec def rec(left: ActorPath, right: ActorPath): Boolean = if (left eq right) true - else if (left.isInstanceOf[RootActorPath] || right.isInstanceOf[RootActorPath]) left == right + else if (left.isInstanceOf[RootActorPath]) left equals right + else if (right.isInstanceOf[RootActorPath]) right equals left else left.name == right.name && rec(left.parent, right.parent) other match { @@ -133,5 +145,20 @@ final class ChildActorPath(val parent: ActorPath, val name: String) extends Acto finalizeHash(rec(this, startHash(42), startMagicA, startMagicB)) } + + def compareTo(other: ActorPath) = { + @tailrec + def rec(left: ActorPath, right: ActorPath): Int = + if (left eq right) 0 + else if (left.isInstanceOf[RootActorPath]) left compareTo right + else if (right.isInstanceOf[RootActorPath]) -(right compareTo left) + else { + val x = left.name compareTo right.name + if (x == 0) rec(left.parent, right.parent) + else x + } + + rec(this, other) + } } diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index ade2ba3a53..463bb994a5 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -43,31 +43,23 @@ import akka.event.DeathWatch * actor.stop() * * + * The natural ordering of ActorRef is defined in terms of its [[akka.actor.ActorPath]]. + * * @author Jonas Bonér */ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable { scalaRef: ScalaActorRef ⇒ // Only mutable for RemoteServer in order to maintain identity across nodes - /** - * Returns the name for this actor. Locally unique (across siblings). - */ - def name: String - /** * Returns the path for this actor (from this actor up to the root actor). */ def path: ActorPath - /** - * Returns the absolute address for this actor in the form hostname:port/path/to/actor. - */ - def address: String - /** * Comparison only takes address into account. */ - def compareTo(other: ActorRef) = this.address compareTo other.address + def compareTo(other: ActorRef) = this.path compareTo other.path /** * Sends the specified message to the sender, i.e. fire-and-forget semantics.

@@ -146,11 +138,12 @@ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable */ def stopsWatching(subject: ActorRef): ActorRef //TODO FIXME REMOVE THIS - override def hashCode: Int = HashCode.hash(HashCode.SEED, address) + // FIXME check if we should scramble the bits or whether they can stay the same + override def hashCode: Int = path.hashCode - override def equals(that: Any): Boolean = { - that.isInstanceOf[ActorRef] && - that.asInstanceOf[ActorRef].address == address + override def equals(that: Any): Boolean = that match { + case other: ActorRef ⇒ path == other.path + case _ ⇒ false } override def toString = "Actor[%s]".format(path) @@ -171,10 +164,6 @@ class LocalActorRef private[akka] ( _hotswap: Stack[PartialFunction[Any, Unit]] = Props.noHotSwap) extends ActorRef with ScalaActorRef { - def name = path.name - - def address: String = path.toString - /* * actorCell.start() publishes actorCell & this to the dispatcher, which * means that messages may be processed theoretically before the constructor @@ -329,9 +318,6 @@ case class SerializedActorRef(hostname: String, port: Int, path: String) { */ trait MinimalActorRef extends ActorRef with ScalaActorRef { - private[akka] val uuid: Uuid = newUuid() - def name: String = uuid.toString - def startsWatching(actorRef: ActorRef): ActorRef = actorRef def stopsWatching(actorRef: ActorRef): ActorRef = actorRef @@ -354,7 +340,6 @@ trait MinimalActorRef extends ActorRef with ScalaActorRef { object MinimalActorRef { def apply(_path: ActorPath)(receive: PartialFunction[Any, Unit]): ActorRef = new MinimalActorRef { def path = _path - def address = path.toString override def !(message: Any)(implicit sender: ActorRef = null): Unit = if (receive.isDefinedAt(message)) receive(message) } @@ -386,10 +371,6 @@ class DeadLetterActorRef(val eventStream: EventStream) extends MinimalActorRef { brokenPromise = new KeptPromise[Any](Left(new ActorKilledException("In DeadLetterActorRef, promises are always broken.")))(dispatcher) } - override val name: String = "dead-letter" - - def address: String = path.toString - override def isTerminated(): Boolean = true override def !(message: Any)(implicit sender: ActorRef = this): Unit = message match { @@ -411,10 +392,6 @@ class DeadLetterActorRef(val eventStream: EventStream) extends MinimalActorRef { class AskActorRef(val path: ActorPath, provider: ActorRefProvider, deathWatch: DeathWatch, timeout: Timeout, val dispatcher: MessageDispatcher) extends MinimalActorRef { final val result = new DefaultPromise[Any](timeout)(dispatcher) - override def name = path.name - - def address: String = path.toString - { val callback: Future[Any] ⇒ Unit = { _ ⇒ deathWatch.publish(Terminated(AskActorRef.this)); whenDone() } result onComplete callback diff --git a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala index 9cea955cd3..039baa3dc6 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala @@ -222,15 +222,11 @@ class LocalActorRefProvider( @volatile var causeOfTermination: Option[Throwable] = None - override val name = "bubble-walker" - // FIXME (actor path): move the root path to the new root guardian - val path = rootPath / name + val path = rootPath / "bubble-walker" val address = path.toString - override def toString = name - override def stop() = stopped switchOn { terminationFuture.complete(causeOfTermination.toLeft(())) } diff --git a/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala b/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala index 42c96c8296..c905a7297d 100644 --- a/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala +++ b/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala @@ -76,7 +76,7 @@ class Dispatchers(val settings: ActorSystem.Settings, val prerequisites: Dispatc */ def newPinnedDispatcher(actor: LocalActorRef) = actor match { case null ⇒ new PinnedDispatcher(prerequisites, null, "anon", MailboxType, settings.DispatcherDefaultShutdown) - case some ⇒ new PinnedDispatcher(prerequisites, some.underlying, some.address, MailboxType, settings.DispatcherDefaultShutdown) + case some ⇒ new PinnedDispatcher(prerequisites, some.underlying, some.path.toString, MailboxType, settings.DispatcherDefaultShutdown) } /** @@ -87,7 +87,7 @@ class Dispatchers(val settings: ActorSystem.Settings, val prerequisites: Dispatc */ def newPinnedDispatcher(actor: LocalActorRef, mailboxType: MailboxType) = actor match { case null ⇒ new PinnedDispatcher(prerequisites, null, "anon", mailboxType, settings.DispatcherDefaultShutdown) - case some ⇒ new PinnedDispatcher(prerequisites, some.underlying, some.address, mailboxType, settings.DispatcherDefaultShutdown) + case some ⇒ new PinnedDispatcher(prerequisites, some.underlying, some.path.toString, mailboxType, settings.DispatcherDefaultShutdown) } /** diff --git a/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala b/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala index 7d3b3c3d8b..ebc8f5df6b 100644 --- a/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala +++ b/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala @@ -196,7 +196,7 @@ abstract class Mailbox(val actor: ActorCell) extends MessageQueue with SystemMes } } catch { case e ⇒ - actor.system.eventStream.publish(Error(e, actor.self.toString, "exception during processing system messages, dropping " + SystemMessage.size(nextMessage) + " messages!")) + actor.system.eventStream.publish(Error(e, actor.self.path.toString, "exception during processing system messages, dropping " + SystemMessage.size(nextMessage) + " messages!")) throw e } } diff --git a/akka-actor/src/main/scala/akka/event/Logging.scala b/akka-actor/src/main/scala/akka/event/Logging.scala index b8da310b1d..374151376e 100644 --- a/akka-actor/src/main/scala/akka/event/Logging.scala +++ b/akka-actor/src/main/scala/akka/event/Logging.scala @@ -404,12 +404,6 @@ object Logging { event.thread.getName, event.logSource, event.message)) - - def instanceName(instance: AnyRef): String = instance match { - case null ⇒ "NULL" - case a: ActorRef ⇒ a.address - case _ ⇒ simpleName(instance) - } } /** @@ -420,9 +414,7 @@ object Logging { * akka.stdout-loglevel in akka.conf. */ class StandardOutLogger extends MinimalActorRef with StdOutLogger { - override val name: String = "standard-out-logger" - val path: ActorPath = null // pathless - val address: String = name + val path: ActorPath = new RootActorPath(LocalAddress("all-systems"), "/StandardOutLogger") override val toString = "StandardOutLogger" override def !(message: Any)(implicit sender: ActorRef = null): Unit = print(message) } diff --git a/akka-actor/src/main/scala/akka/routing/Routing.scala b/akka-actor/src/main/scala/akka/routing/Routing.scala index 293c1abb4b..48814a4e43 100644 --- a/akka-actor/src/main/scala/akka/routing/Routing.scala +++ b/akka-actor/src/main/scala/akka/routing/Routing.scala @@ -171,7 +171,7 @@ abstract private[akka] class AbstractRoutedActorRef(val system: ActorSystem, val * A RoutedActorRef is an ActorRef that has a set of connected ActorRef and it uses a Router to send a message to * on (or more) of these actors. */ -private[akka] class RoutedActorRef(system: ActorSystem, val routedProps: RoutedProps, val supervisor: ActorRef, override val name: String) extends AbstractRoutedActorRef(system, routedProps) { +private[akka] class RoutedActorRef(system: ActorSystem, val routedProps: RoutedProps, val supervisor: ActorRef, name: String) extends AbstractRoutedActorRef(system, routedProps) { val path = supervisor.path / name diff --git a/akka-remote/src/main/scala/akka/remote/Gossiper.scala b/akka-remote/src/main/scala/akka/remote/Gossiper.scala index 250fbc727c..4854489839 100644 --- a/akka-remote/src/main/scala/akka/remote/Gossiper.scala +++ b/akka-remote/src/main/scala/akka/remote/Gossiper.scala @@ -256,12 +256,12 @@ class Gossiper(remote: Remote) { log.error(cause, cause.toString) case None ⇒ - val error = new RemoteException("Gossip to [%s] timed out".format(connection.address)) + val error = new RemoteException("Gossip to [%s] timed out".format(connection.path)) log.error(error, error.toString) } } catch { case e: Exception ⇒ - log.error(e, "Could not gossip to [{}] due to: {}", connection.address, e.toString) + log.error(e, "Could not gossip to [{}] due to: {}", connection.path, e.toString) } seeds exists (peer == _) diff --git a/akka-remote/src/main/scala/akka/remote/Remote.scala b/akka-remote/src/main/scala/akka/remote/Remote.scala index 4eccce6b33..6c8f4ca69d 100644 --- a/akka-remote/src/main/scala/akka/remote/Remote.scala +++ b/akka-remote/src/main/scala/akka/remote/Remote.scala @@ -84,8 +84,8 @@ class Remote(val system: ActorSystemImpl, val nodename: String) { _server = remote - val daemonAddress = remoteDaemon.address //Force init of daemon - log.info("Starting remote server on [{}] and starting remoteDaemon with address [{}]", remoteAddress, daemonAddress) + val daemonPath = remoteDaemon.path //Force init of daemon + log.info("Starting remote server on [{}] and starting remoteDaemon with path [{}]", remoteAddress, daemonPath) } } diff --git a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala index 6240ed1b97..b82b953747 100644 --- a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala +++ b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala @@ -247,13 +247,13 @@ class RemoteActorRefProvider( throw cause case None ⇒ - val error = new RemoteException("Remote system command to [%s] timed out".format(connection.address)) + val error = new RemoteException("Remote system command to [%s] timed out".format(connection.path)) log.error(error, error.toString) throw error } } catch { case e: Exception ⇒ - log.error(e, "Could not send remote system command to [{}] due to: {}", connection.address, e.toString) + log.error(e, "Could not send remote system command to [{}] due to: {}", connection.path, e.toString) throw e } } else { diff --git a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala index 2c23940c9f..346324e3b2 100644 --- a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala +++ b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala @@ -75,7 +75,7 @@ class Hakker(name: String, left: ActorRef, right: ActorRef) extends Actor { //back to think about how he should obtain his chopsticks :-) def waiting_for(chopstickToWaitFor: ActorRef, otherChopstick: ActorRef): Receive = { case Taken(`chopstickToWaitFor`) ⇒ - println("%s has picked up %s and %s, and starts to eat", name, left.address, right.address) + println("%s has picked up %s and %s, and starts to eat", name, left.path.name, right.path.name) become(eating) system.scheduler.scheduleOnce(self, Think, 5 seconds) diff --git a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala index 987f630784..a76ecbc619 100644 --- a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala +++ b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala @@ -125,7 +125,7 @@ class FSMHakker(name: String, left: ActorRef, right: ActorRef) extends Actor wit } private def startEating(left: ActorRef, right: ActorRef): State = { - println("%s has picked up %s and %s, and starts to eat", name, left.address, right.address) + println("%s has picked up %s and %s, and starts to eat", name, left.path.name, right.path.name) goto(Eating) using TakenChopsticks(Some(left), Some(right)) forMax (5 seconds) } diff --git a/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala b/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala index 6f03df59b2..ed4472e6f6 100644 --- a/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala +++ b/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala @@ -42,9 +42,12 @@ class TestActorRef[T <: Actor]( */ def underlyingActor: T = underlyingActorInstance.asInstanceOf[T] - override def toString = "TestActor[" + address + "]" + override def toString = "TestActor[" + path + "]" - override def equals(other: Any) = other.isInstanceOf[TestActorRef[_]] && other.asInstanceOf[TestActorRef[_]].address == address + override def equals(other: Any) = other match { + case r: TestActorRef[_] ⇒ path == r.path + case _ ⇒ false + } } object TestActorRef {