From e7f3945776369cf6fbff1e0dee76981c0bede343 Mon Sep 17 00:00:00 2001 From: Roland Date: Sun, 26 Jun 2011 17:40:30 +0200 Subject: [PATCH 01/51] add TestKit.expectMsgType - plus docs - and replace softTimeout hack with better solution --- akka-docs/scala/testing.rst | 21 +++++++--- .../src/main/scala/akka/testkit/TestKit.scala | 39 ++++++++++++------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/akka-docs/scala/testing.rst b/akka-docs/scala/testing.rst index f3bb07c5bb..e8b20aa830 100644 --- a/akka-docs/scala/testing.rst +++ b/akka-docs/scala/testing.rst @@ -288,6 +288,13 @@ assertions concerning received messages. Here is the full list: does a conformance check; if you need the class to be equal, have a look at :meth:`expectMsgAllClassOf` with a single given class argument. + * :meth:`expectMsgType[T: Manifest](d: Duration)` + + An object which is an instance of the given type (after erasure) must be + received within the allotted time frame; the object will be returned. This + method is approximately equivalent to + ``expectMsgClass(manifest[T].erasure)``. + * :meth:`expectMsgAnyOf[T](d: Duration, obj: T*): T` An object must be received within the given time, and it must be equal ( @@ -398,21 +405,25 @@ is between :obj:`min` and :obj:`max`, where the former defaults to zero. The deadline calculated by adding the :obj:`max` parameter to the block's start time is implicitly available within the block to all examination methods, if you do not specify it, is is inherited from the innermost enclosing -:meth:`within` block. It should be noted that using :meth:`expectNoMsg` will -terminate upon reception of a message or at the deadline, whichever occurs -first; it follows that this examination usually is the last statement in a :meth:`within` block. +It should be noted that if the last message-receiving assertion of the block is +:meth:`expectNoMsg` or :meth:`receiveWhile`, the final check of the +:meth:`within` is skipped in order to avoid false positives due to wake-up +latencies. This means that while individual contained assertions still use the +maximum time bound, the overall block may take arbitrarily longer in this case. + .. code-block:: scala class SomeSpec extends WordSpec with MustMatchers with TestKit { "A Worker" must { "send timely replies" in { val worker = actorOf(...) - within (50 millis) { + within (500 millis) { worker ! "some work" expectMsg("some result") - expectNoMsg + expectNoMsg // will block for the rest of the 500ms + Thread.sleep(1000) // will NOT make this block fail } } } diff --git a/akka-testkit/src/main/scala/akka/testkit/TestKit.scala b/akka-testkit/src/main/scala/akka/testkit/TestKit.scala index bb9f69168b..10727ffc7c 100644 --- a/akka-testkit/src/main/scala/akka/testkit/TestKit.scala +++ b/akka-testkit/src/main/scala/akka/testkit/TestKit.scala @@ -110,13 +110,12 @@ trait TestKitLight { val senderOption = Some(testActor) private var end: Duration = Duration.Inf - /* - * THIS IS A HACK: expectNoMsg and receiveWhile are bounded by `end`, but - * running them should not trigger an AssertionError, so mark their end - * time here and do not fail at the end of `within` if that time is not - * long gone. + + /** + * if last assertion was expectNoMsg, disable timing failure upon within() + * block end. */ - private var lastSoftTimeout: Duration = now - 5.millis + private var lastWasNoMsg = false /** * Stop test actor. Should be done at the end of the test unless relying on @@ -211,6 +210,8 @@ trait TestKitLight { val rem = end - start assert(rem >= min, "required min time " + min + " not possible, only " + format(min.unit, rem) + " left") + lastWasNoMsg = false + val max_diff = _max min rem val prev_end = end end = start + max_diff @@ -219,13 +220,8 @@ trait TestKitLight { val diff = now - start assert(min <= diff, "block took " + format(min.unit, diff) + ", should at least have been " + min) - /* - * caution: HACK AHEAD - */ - if (now - lastSoftTimeout > 5.millis) { + if (!lastWasNoMsg) { assert(diff <= max_diff, "block took " + format(_max.unit, diff) + ", exceeding " + format(_max.unit, max_diff)) - } else { - lastSoftTimeout -= 5.millis } ret @@ -302,6 +298,20 @@ trait TestKitLight { f(o) } + /** + * Same as `expectMsgType[T](remaining)`, but correctly treating the timeFactor. + */ + def expectMsgType[T](implicit m: Manifest[T]): T = expectMsgClass_internal(remaining, m.erasure.asInstanceOf[Class[T]]) + + /** + * Receive one message from the test actor and assert that it conforms to the + * given type (after erasure). Wait time is bounded by the given duration, + * with an AssertionFailure being thrown in case of timeout. + * + * @return the received object + */ + def expectMsgType[T](max: Duration)(implicit m: Manifest[T]): T = expectMsgClass_internal(max.dilated, m.erasure.asInstanceOf[Class[T]]) + /** * Same as `expectMsgClass(remaining, c)`, but correctly treating the timeFactor. */ @@ -454,7 +464,7 @@ trait TestKitLight { private def expectNoMsg_internal(max: Duration) { val o = receiveOne(max) assert(o eq null, "received unexpected message " + o) - lastSoftTimeout = now + lastWasNoMsg = true } /** @@ -503,7 +513,7 @@ trait TestKitLight { } val ret = doit(Nil) - lastSoftTimeout = now + lastWasNoMsg = true ret } @@ -543,6 +553,7 @@ trait TestKitLight { } else { queue.takeFirst } + lastWasNoMsg = false message match { case null ⇒ lastMessage = NullMessage From 48feec0bbb1d81d74e7706f553638a217933da53 Mon Sep 17 00:00:00 2001 From: Roland Date: Sun, 26 Jun 2011 21:33:27 +0200 Subject: [PATCH 02/51] add debug output to investigate cause of RoutingSpec sporadic failures "smallest mailbox" test fails randomly on my notebook --- .../src/test/scala/akka/routing/RoutingSpec.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala b/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala index 3544767453..52ceb098bd 100644 --- a/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala @@ -10,6 +10,7 @@ import akka.util.duration._ import akka.actor._ import akka.actor.Actor._ import akka.routing._ +import akka.event.EventHandler import java.util.concurrent.atomic.AtomicInteger import akka.dispatch.{ KeptPromise, Future } @@ -122,9 +123,11 @@ class RoutingSpec extends WordSpec with MustMatchers { latch.await(10 seconds) } finally { // because t1 is much slower and thus has a bigger mailbox all the time - t1Count.get must be < (t2Count.get) + EventHandler.info(this, "t1=" + t1Count + " t2=" + t2Count) } + t1Count.get must be < t2Count.get + for (a ← List(t1, t2, d)) a.stop() } From 10256991cbd1e52fbebab5d426dee7331e786652 Mon Sep 17 00:00:00 2001 From: Roland Date: Mon, 27 Jun 2011 19:09:09 +0200 Subject: [PATCH 03/51] add Actor.freshInstance hook, test #955 --- .../akka/actor/actor/ActorRestartSpec.scala | 148 ++++++++++++++++++ .../src/main/scala/akka/actor/Actor.scala | 12 ++ .../src/main/scala/akka/actor/ActorRef.scala | 15 +- akka-docs/scala/actors.rst | 116 +++++++++----- 4 files changed, 253 insertions(+), 38 deletions(-) create mode 100644 akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala new file mode 100644 index 0000000000..3f1398e596 --- /dev/null +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala @@ -0,0 +1,148 @@ +/** + * Copyright (C) 2009-2011 Scalable Solutions AB + */ + +package akka.actor + +import org.scalatest.{ WordSpec, BeforeAndAfterAll, BeforeAndAfterEach } +import org.scalatest.matchers.MustMatchers + +import Actor.actorOf +import akka.testkit._ +import akka.util.duration._ +import akka.config.Supervision.OneForOneStrategy + +import java.util.concurrent.atomic._ + +object ActorRestartSpec { + + private var _gen = new AtomicInteger(0) + def generation = _gen.incrementAndGet + def generation_=(x: Int) { _gen.set(x) } + + sealed trait RestartType + case object Normal extends RestartType + case object Nested extends RestartType + case object Handover extends RestartType + case object Fail extends RestartType + + class Restarter(val testActor: ActorRef) extends Actor { + val gen = generation + var xx = 0 + var restart: RestartType = Normal + def receive = { + case x: Int ⇒ xx = x + case t: RestartType ⇒ restart = t + case "get" ⇒ self reply xx + } + override def preStart { testActor ! (("preStart", gen)) } + override def postStop { testActor ! (("postStop", gen)) } + override def preRestart(cause: Throwable) { testActor ! (("preRestart", gen)) } + override def postRestart(cause: Throwable) { testActor ! (("postRestart", gen)) } + override def freshInstance() = { + restart match { + case Normal ⇒ None + case Nested ⇒ + val ref = TestActorRef(new Actor { + def receive = { case _ ⇒ } + override def preStart { testActor ! ((this, self)) } + }).start() + testActor ! ((ref.underlyingActor, ref)) + None + case Handover ⇒ + val fresh = new Restarter(testActor) + fresh.xx = xx + Some(fresh) + case Fail ⇒ + throw new IllegalActorStateException("expected") + } + } + } + + class Supervisor extends Actor { + self.faultHandler = OneForOneStrategy(List(classOf[Throwable]), 5, 5000) + def receive = { + case _ ⇒ + } + } +} + +class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with BeforeAndAfterEach { + import ActorRestartSpec._ + + override def beforeEach { generation = 0 } + + "An Actor restart" must { + + "invoke preRestart, preStart, postRestart" in { + val actor = actorOf(new Restarter(testActor)).start() + expectMsg(1 second, ("preStart", 1)) + val supervisor = actorOf[Supervisor].start() + supervisor link actor + actor ! Kill + within(1 second) { + expectMsg(("preRestart", 1)) + expectMsg(("preStart", 2)) + expectMsg(("postRestart", 2)) + expectNoMsg + } + } + + "support creation of nested actors in freshInstance()" in { + val actor = actorOf(new Restarter(testActor)).start() + expectMsg(1 second, ("preStart", 1)) + val supervisor = actorOf[Supervisor].start() + supervisor link actor + actor ! Nested + actor ! Kill + within(1 second) { + expectMsg(("preRestart", 1)) + val (tActor, tRef) = expectMsgType[(Actor, TestActorRef[Actor])] + tRef.underlyingActor must be(tActor) + expectMsg((tActor, tRef)) + tRef.stop() + expectMsg(("preStart", 2)) + expectMsg(("postRestart", 2)) + expectNoMsg + } + } + + "use freshInstance() if available" in { + val actor = actorOf(new Restarter(testActor)).start() + expectMsg(1 second, ("preStart", 1)) + val supervisor = actorOf[Supervisor].start() + supervisor link actor + actor ! 42 + actor ! Handover + actor ! Kill + within(1 second) { + expectMsg(("preRestart", 1)) + expectMsg(("preStart", 2)) + expectMsg(("postRestart", 2)) + expectNoMsg + } + actor ! "get" + expectMsg(1 second, 42) + } + + "fall back to default factory if freshInstance() fails" in { + val actor = actorOf(new Restarter(testActor)).start() + expectMsg(1 second, ("preStart", 1)) + val supervisor = actorOf[Supervisor].start() + supervisor link actor + actor ! 42 + actor ! Fail + actor ! Kill + within(1 second) { + expectMsg(("preRestart", 1)) + expectMsg(("preStart", 2)) + expectMsg(("postRestart", 2)) + expectNoMsg + } + actor ! "get" + expectMsg(1 second, 0) + } + + } + +} diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index 0ec0616acb..9925c060a5 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -662,6 +662,18 @@ trait Actor { */ def preRestart(reason: Throwable) {} + /** + * User overridable callback. + *

+ * Is called on the crashed Actor to give it the option of producing the + * Actor's reincarnation. If it returns None, which is the default, the + * initially provided actor factory is used. + *

+ * Warning: Propagating state from a crashed actor carries the risk + * of proliferating the cause of the error. Consider let-it-crash first. + */ + def freshInstance(): Option[Actor] = None + /** * User overridable callback. *

diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index 17fa3139dd..5e3c5fd3cf 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -845,7 +845,20 @@ class LocalActorRef private[akka] ( val stackBefore = refStack.get refStack.set(stackBefore.push(this)) try { - actorFactory() + if (_status == ActorRefInternals.BEING_RESTARTED) { + val a = actor + val fresh = try a.freshInstance catch { + case e ⇒ + EventHandler.error(e, a, "freshInstance() failed, falling back to initial actor factory") + None + } + fresh match { + case Some(ref) ⇒ ref + case None ⇒ actorFactory() + } + } else { + actorFactory() + } } finally { val stackAfter = refStack.get if (stackAfter.nonEmpty) diff --git a/akka-docs/scala/actors.rst b/akka-docs/scala/actors.rst index eb25cb2d1a..ad9fbf2756 100644 --- a/akka-docs/scala/actors.rst +++ b/akka-docs/scala/actors.rst @@ -92,6 +92,83 @@ Here we create a light-weight actor-based thread, that can be used to spawn off ... // do stuff } +Actor Internal API +------------------ + +The :class:`Actor` trait defines only one abstract method, the abovementioned +:meth:`receive`. In addition, it offers two convenience methods +:meth:`become`/:meth:`unbecome` for modifying the hotswap behavior stack as +described in :ref:`Actor.HotSwap` and the :obj:`self` reference to this actor’s +:class:`ActorRef` object. The remaining visible methods are user-overridable +life-cycle hooks which are described in the following:: + + def preStart() {} + def preRestart(cause: Throwable) {} + def freshInstance(): Option[Actor] = None + def postRestart(cause: Throwable) {} + def postStop() {} + +The implementations shown above are the defaults provided by the :class:`Actor` +trait. + +Start Hook +^^^^^^^^^^ + +Right after starting the actor, its :meth:`preStart` method is invoked. This is +guaranteed to happen before the first message from external sources is queued +to the actor’s mailbox. + +:: + + override def preStart { + // e.g. send initial message to self + self ! GetMeStarted + // or do any other stuff, e.g. registering with other actors + someService ! Register(self) + } + +Restart Hooks +^^^^^^^^^^^^^ + +A supervised actor, i.e. one which is linked to another actor with a fault +handling strategy, will be restarted in case an exception is thrown while +processing a message. This restart involves four of the hooks mentioned above: + +1. The old actor is informed by calling :meth:`preRestart` with the exception + which caused the restart; this method is the best place for cleaning up, + preparing hand-over to the fresh actor instance, etc. +2. The old actor’s :meth:`freshInstance` factory method is invoked, which may + optionally produce the new actor instance which will replace this actor. If + this method returns :obj:`None` or throws an exception, the initial factory + from the ``Actor.actorOf`` call is used to produce the fresh instance. +3. The new actor’s :meth:`preStart` method is invoked, just as in the normal + start-up case. +4. The new actor’s :meth:`postRestart` method is called with the exception + which caused the restart. + +.. warning:: + + The :meth:`freshInstance` hook may be used to propagate (part of) the failed + actor’s state to the fresh instance. This carries the risk of proliferating + the cause for the crash which triggered the restart. If you are tempted to + take this route, it is strongly advised to step back and consider other + possible approaches, e.g. distributing the state in question using other + means or spawning short-lived worker actors for carrying out “risky” tasks. + +An actor restart replaces only the actual actor object; the contents of the +mailbox and the hotswap stack are unaffected by the restart, so processing of +messages will resume after the :meth:`postRestart` hook returns. Any message +sent to an actor which is being restarted will be queued to its mailbox as +usual. + +Stop Hook +^^^^^^^^^ + +After stopping an actor, its :meth:`postStop` hook is called, which may be used +e.g. for deregistering this actor from other services. This hook is guaranteed +to run after message queuing has been disabled for this actor, i.e. sending +messages would fail with an :class:`IllegalActorStateException`. + Identifying Actors ------------------ @@ -252,43 +329,6 @@ This method should return a ``PartialFunction``, e.g. a ‘match/case’ clause } } -Actor internal API ------------------- - -The Actor trait contains almost no member fields or methods to invoke, you just use the Actor trait to implement the: - -#. ``receive`` message handler -#. life-cycle callbacks: - - #. preStart - #. postStop - #. preRestart - #. postRestart - -The ``Actor`` trait has one single member field: - -.. code-block:: scala - - val self: ActorRef - -This ``self`` field holds a reference to its ``ActorRef`` and it is this reference you want to access the Actor's API. Here, for example, you find methods to reply to messages, send yourself messages, define timeouts, fault tolerance etc., start and stop etc. - -However, for convenience you can import these functions and fields like below, which will allow you do drop the ``self`` prefix: - -.. code-block:: scala - - class MyActor extends Actor { - import self._ - id = ... - dispatcher = ... - start - ... - } - -But in this documentation we will always prefix the calls with ``self`` for clarity. - -Let's start by looking how we can reply to messages in a convenient way using this ``ActorRef`` API. - Reply to messages ----------------- @@ -441,6 +481,8 @@ You can also send an actor the ``akka.actor.PoisonPill`` message, which will sto If the sender is a ``Future`` (e.g. the message is sent with ``?``), the ``Future`` will be completed with an ``akka.actor.ActorKilledException("PoisonPill")``. +.. _Actor.HotSwap: + HotSwap ------- From 956d055d872ec19f8944b217a89a60e220636bef Mon Sep 17 00:00:00 2001 From: Roland Date: Mon, 27 Jun 2011 22:20:09 +0200 Subject: [PATCH 04/51] make currentMessage available in preRestart, test #957 - use Option[Any] since currentMessage may be unavailable (supervisor being restarted) - plus docs --- .../akka/actor/actor/ActorRestartSpec.scala | 41 +++++++++++++++---- .../src/main/scala/akka/actor/Actor.scala | 13 +++++- .../src/main/scala/akka/actor/ActorRef.scala | 3 +- akka-docs/scala/actors.rst | 17 +++++--- 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala index 3f1398e596..2b52c5cd4f 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala @@ -36,7 +36,6 @@ object ActorRestartSpec { case "get" ⇒ self reply xx } override def preStart { testActor ! (("preStart", gen)) } - override def postStop { testActor ! (("postStop", gen)) } override def preRestart(cause: Throwable) { testActor ! (("preRestart", gen)) } override def postRestart(cause: Throwable) { testActor ! (("postRestart", gen)) } override def freshInstance() = { @@ -71,13 +70,21 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo import ActorRestartSpec._ override def beforeEach { generation = 0 } + override def afterEach { toStop foreach (_.stop()) } + + private var toStop = List.empty[ActorRef] + private def newActor(f: ⇒ Actor): ActorRef = { + val ref = actorOf(f) + toStop ::= ref + ref.start() + } "An Actor restart" must { "invoke preRestart, preStart, postRestart" in { - val actor = actorOf(new Restarter(testActor)).start() + val actor = newActor(new Restarter(testActor)) expectMsg(1 second, ("preStart", 1)) - val supervisor = actorOf[Supervisor].start() + val supervisor = newActor(new Supervisor) supervisor link actor actor ! Kill within(1 second) { @@ -89,9 +96,9 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo } "support creation of nested actors in freshInstance()" in { - val actor = actorOf(new Restarter(testActor)).start() + val actor = newActor(new Restarter(testActor)) expectMsg(1 second, ("preStart", 1)) - val supervisor = actorOf[Supervisor].start() + val supervisor = newActor(new Supervisor) supervisor link actor actor ! Nested actor ! Kill @@ -108,9 +115,9 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo } "use freshInstance() if available" in { - val actor = actorOf(new Restarter(testActor)).start() + val actor = newActor(new Restarter(testActor)) expectMsg(1 second, ("preStart", 1)) - val supervisor = actorOf[Supervisor].start() + val supervisor = newActor(new Supervisor) supervisor link actor actor ! 42 actor ! Handover @@ -126,9 +133,9 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo } "fall back to default factory if freshInstance() fails" in { - val actor = actorOf(new Restarter(testActor)).start() + val actor = newActor(new Restarter(testActor)) expectMsg(1 second, ("preStart", 1)) - val supervisor = actorOf[Supervisor].start() + val supervisor = newActor(new Supervisor) supervisor link actor actor ! 42 actor ! Fail @@ -143,6 +150,22 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo expectMsg(1 second, 0) } + "call preRestart(cause, currentMessage) if defined" in { + val actor = newActor(new Actor { + def receive = { case _ ⇒ } + override def preRestart(cause: Throwable, currentMessage: Option[Any]) { + testActor ! (("preRestart", currentMessage)) + } + }) + val supervisor = newActor(new Supervisor) + supervisor link actor + actor ! Kill + within(1 second) { + expectMsg(("preRestart", Some(Kill))) + expectNoMsg + } + } + } } diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index 9925c060a5..bb4bb47327 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -658,10 +658,21 @@ trait Actor { /** * User overridable callback. *

- * Is called on a crashed Actor right BEFORE it is restarted to allow clean up of resources before Actor is terminated. + * Is called on a crashed Actor right BEFORE it is restarted to allow clean + * up of resources before Actor is terminated. Override either the variant + * with or without the currentMessage argument. */ def preRestart(reason: Throwable) {} + /** + * User overridable callback. + *

+ * Is called on a crashed Actor right BEFORE it is restarted to allow clean + * up of resources before Actor is terminated. Override either the variant + * with or without the currentMessage argument. + */ + def preRestart(reason: Throwable, message: Option[Any]) { preRestart(reason) } + /** * User overridable callback. *

diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index 5e3c5fd3cf..1287324288 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -766,7 +766,8 @@ class LocalActorRef private[akka] ( def performRestart() { val failedActor = actorInstance.get if (Actor.debugLifecycle) EventHandler.debug(failedActor, "restarting") - failedActor.preRestart(reason) + val message = if (currentMessage ne null) Some(currentMessage.message) else None + failedActor.preRestart(reason, message) val freshActor = newActor setActorSelfFields(failedActor, null) // Only null out the references if we could instantiate the new actor actorInstance.set(freshActor) // Assign it here so if preStart fails, we can null out the sef-refs next call diff --git a/akka-docs/scala/actors.rst b/akka-docs/scala/actors.rst index ad9fbf2756..b23d53385e 100644 --- a/akka-docs/scala/actors.rst +++ b/akka-docs/scala/actors.rst @@ -99,11 +99,15 @@ The :class:`Actor` trait defines only one abstract method, the abovementioned :meth:`receive`. In addition, it offers two convenience methods :meth:`become`/:meth:`unbecome` for modifying the hotswap behavior stack as described in :ref:`Actor.HotSwap` and the :obj:`self` reference to this actor’s -:class:`ActorRef` object. The remaining visible methods are user-overridable -life-cycle hooks which are described in the following:: +:class:`ActorRef` object. If the current actor behavior does not match a +received message, :meth:`unhandled` is called, which by default throws an +:class:`UnhandledMessageException`. + +The remaining visible methods are user-overridable life-cycle hooks which are +described in the following:: def preStart() {} - def preRestart(cause: Throwable) {} + def preRestart(cause: Throwable, message: Option[Any]) {} def freshInstance(): Option[Actor] = None def postRestart(cause: Throwable) {} def postStop() {} @@ -135,7 +139,10 @@ handling strategy, will be restarted in case an exception is thrown while processing a message. This restart involves four of the hooks mentioned above: 1. The old actor is informed by calling :meth:`preRestart` with the exception - which caused the restart; this method is the best place for cleaning up, + which caused the restart and the message which triggered that exception; the + latter may be ``None`` if the restart was not caused by processing a + message, e.g. when a supervisor does not trap the exception and is restarted + in turn by its supervisor. This method is the best place for cleaning up, preparing hand-over to the fresh actor instance, etc. 2. The old actor’s :meth:`freshInstance` factory method is invoked, which may optionally produce the new actor instance which will replace this actor. If @@ -158,7 +165,7 @@ processing a message. This restart involves four of the hooks mentioned above: An actor restart replaces only the actual actor object; the contents of the mailbox and the hotswap stack are unaffected by the restart, so processing of messages will resume after the :meth:`postRestart` hook returns. Any message -sent to an actor which is being restarted will be queued to its mailbox as +sent to an actor while it is being restarted will be queued to its mailbox as usual. Stop Hook From 00b9166b577ef6a270cfe4eb6bdfdb4049bc8f31 Mon Sep 17 00:00:00 2001 From: Roland Date: Sun, 3 Jul 2011 20:38:06 +0200 Subject: [PATCH 05/51] make ActorRestartSpec thread safe --- .../scala/akka/actor/actor/ActorRestartSpec.scala | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala index 2b52c5cd4f..cdff70c461 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala @@ -70,12 +70,18 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo import ActorRestartSpec._ override def beforeEach { generation = 0 } - override def afterEach { toStop foreach (_.stop()) } + override def afterEach { + val it = toStop.iterator + while (it.hasNext) { + it.next.stop() + it.remove + } + } - private var toStop = List.empty[ActorRef] + private var toStop = new java.util.concurrent.ConcurrentSkipListSet[ActorRef] private def newActor(f: ⇒ Actor): ActorRef = { val ref = actorOf(f) - toStop ::= ref + toStop add ref ref.start() } From 5de2ca7aa55df94f7591c78f1a5b7cdd95f5068e Mon Sep 17 00:00:00 2001 From: Roland Date: Sun, 3 Jul 2011 22:19:34 +0200 Subject: [PATCH 06/51] remove Actor.preRestart(cause: Throwable) - adapt all internal uses (all tests green) - start migration guide for 2.0 with this change --- .../scala/akka/actor/actor/ActorRefSpec.scala | 2 +- .../akka/actor/actor/ActorRestartSpec.scala | 26 ++++--------------- .../akka/actor/actor/FSMTransitionSpec.scala | 2 +- .../actor/supervisor/SupervisorTreeSpec.scala | 2 +- .../akka/actor/supervisor/Ticket669Spec.scala | 2 +- .../src/main/scala/akka/actor/Actor.scala | 14 ++-------- .../main/scala/akka/actor/UntypedActor.scala | 2 +- .../src/main/scala/akka/camel/Producer.scala | 2 +- .../scala/akka/camel/ConsumerScalaTest.scala | 2 +- .../src/main/scala/akka/cluster/Cluster.scala | 2 +- .../project/migration-guide-1.1.x-1.2.x.rst | 6 +++++ .../project/migration-guide-1.2.x-2.0.x.rst | 20 ++++++++++++++ akka-docs/project/migration-guides.rst | 2 ++ .../akka/spring/RemoteTypedActorOneImpl.java | 4 ++- .../akka/spring/RemoteTypedActorTwoImpl.java | 4 ++- .../scala/akka/testkit/TestActorRefSpec.scala | 2 +- 16 files changed, 50 insertions(+), 44 deletions(-) create mode 100644 akka-docs/project/migration-guide-1.1.x-1.2.x.rst create mode 100644 akka-docs/project/migration-guide-1.2.x-2.0.x.rst diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRefSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRefSpec.scala index 4bef71a74d..f11b762493 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRefSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRefSpec.scala @@ -334,7 +334,7 @@ class ActorRefSpec extends WordSpec with MustMatchers { val ref = Actor.actorOf( new Actor { def receive = { case _ ⇒ } - override def preRestart(reason: Throwable) = latch.countDown() + override def preRestart(reason: Throwable, msg: Option[Any]) = latch.countDown() override def postRestart(reason: Throwable) = latch.countDown() }).start() diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala index cdff70c461..d2b9a42ee5 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRestartSpec.scala @@ -36,7 +36,7 @@ object ActorRestartSpec { case "get" ⇒ self reply xx } override def preStart { testActor ! (("preStart", gen)) } - override def preRestart(cause: Throwable) { testActor ! (("preRestart", gen)) } + override def preRestart(cause: Throwable, msg: Option[Any]) { testActor ! (("preRestart", msg, gen)) } override def postRestart(cause: Throwable) { testActor ! (("postRestart", gen)) } override def freshInstance() = { restart match { @@ -94,7 +94,7 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo supervisor link actor actor ! Kill within(1 second) { - expectMsg(("preRestart", 1)) + expectMsg(("preRestart", Some(Kill), 1)) expectMsg(("preStart", 2)) expectMsg(("postRestart", 2)) expectNoMsg @@ -109,7 +109,7 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo actor ! Nested actor ! Kill within(1 second) { - expectMsg(("preRestart", 1)) + expectMsg(("preRestart", Some(Kill), 1)) val (tActor, tRef) = expectMsgType[(Actor, TestActorRef[Actor])] tRef.underlyingActor must be(tActor) expectMsg((tActor, tRef)) @@ -129,7 +129,7 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo actor ! Handover actor ! Kill within(1 second) { - expectMsg(("preRestart", 1)) + expectMsg(("preRestart", Some(Kill), 1)) expectMsg(("preStart", 2)) expectMsg(("postRestart", 2)) expectNoMsg @@ -147,7 +147,7 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo actor ! Fail actor ! Kill within(1 second) { - expectMsg(("preRestart", 1)) + expectMsg(("preRestart", Some(Kill), 1)) expectMsg(("preStart", 2)) expectMsg(("postRestart", 2)) expectNoMsg @@ -156,22 +156,6 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo expectMsg(1 second, 0) } - "call preRestart(cause, currentMessage) if defined" in { - val actor = newActor(new Actor { - def receive = { case _ ⇒ } - override def preRestart(cause: Throwable, currentMessage: Option[Any]) { - testActor ! (("preRestart", currentMessage)) - } - }) - val supervisor = newActor(new Supervisor) - supervisor link actor - actor ! Kill - within(1 second) { - expectMsg(("preRestart", Some(Kill))) - expectNoMsg - } - } - } } diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/FSMTransitionSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/FSMTransitionSpec.scala index 0cbaddd8e6..1eba7a71c1 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/actor/FSMTransitionSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/FSMTransitionSpec.scala @@ -32,7 +32,7 @@ object FSMTransitionSpec { case Ev("reply") ⇒ stay replying "reply" } initialize - override def preRestart(reason: Throwable) { target ! "restarted" } + override def preRestart(reason: Throwable, msg: Option[Any]) { target ! "restarted" } } class Forwarder(target: ActorRef) extends Actor { diff --git a/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorTreeSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorTreeSpec.scala index d8aaa9d0e4..85b41c777c 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorTreeSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorTreeSpec.scala @@ -25,7 +25,7 @@ class SupervisorTreeSpec extends WordSpec with MustMatchers { case Die ⇒ throw new Exception(self.address + " is dying...") } - override def preRestart(reason: Throwable) { + override def preRestart(reason: Throwable, msg: Option[Any]) { log += self.address } } diff --git a/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala b/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala index 0a70058c7b..41019fc0a8 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala @@ -59,7 +59,7 @@ object Ticket669Spec { case msg ⇒ throw new Exception("test") } - override def preRestart(reason: scala.Throwable) { + override def preRestart(reason: scala.Throwable, msg: Option[Any]) { self.reply_?("failure1") } diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index bb4bb47327..fecd776ca1 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -659,19 +659,9 @@ trait Actor { * User overridable callback. *

* Is called on a crashed Actor right BEFORE it is restarted to allow clean - * up of resources before Actor is terminated. Override either the variant - * with or without the currentMessage argument. + * up of resources before Actor is terminated. */ - def preRestart(reason: Throwable) {} - - /** - * User overridable callback. - *

- * Is called on a crashed Actor right BEFORE it is restarted to allow clean - * up of resources before Actor is terminated. Override either the variant - * with or without the currentMessage argument. - */ - def preRestart(reason: Throwable, message: Option[Any]) { preRestart(reason) } + def preRestart(reason: Throwable, message: Option[Any]) {} /** * User overridable callback. diff --git a/akka-actor/src/main/scala/akka/actor/UntypedActor.scala b/akka-actor/src/main/scala/akka/actor/UntypedActor.scala index d561ce6221..fa546b2437 100644 --- a/akka-actor/src/main/scala/akka/actor/UntypedActor.scala +++ b/akka-actor/src/main/scala/akka/actor/UntypedActor.scala @@ -102,7 +102,7 @@ abstract class UntypedActor extends Actor { *

* Is called on a crashed Actor right BEFORE it is restarted to allow clean up of resources before Actor is terminated. */ - override def preRestart(reason: Throwable) {} + override def preRestart(reason: Throwable, lastMessage: Option[Any]) {} /** * User overridable callback. diff --git a/akka-camel/src/main/scala/akka/camel/Producer.scala b/akka-camel/src/main/scala/akka/camel/Producer.scala index 041f3397ff..9ad6ce22d2 100644 --- a/akka-camel/src/main/scala/akka/camel/Producer.scala +++ b/akka-camel/src/main/scala/akka/camel/Producer.scala @@ -58,7 +58,7 @@ trait ProducerSupport { this: Actor ⇒ * Default implementation of Actor.preRestart for freeing resources needed * to actually send messages to endpointUri. */ - override def preRestart(reason: Throwable) { + override def preRestart(reason: Throwable, msg: Option[Any]) { try { preRestartProducer(reason) } finally { processor.stop } } diff --git a/akka-camel/src/test/scala/akka/camel/ConsumerScalaTest.scala b/akka-camel/src/test/scala/akka/camel/ConsumerScalaTest.scala index d80e847efa..27bbc264d7 100644 --- a/akka-camel/src/test/scala/akka/camel/ConsumerScalaTest.scala +++ b/akka-camel/src/test/scala/akka/camel/ConsumerScalaTest.scala @@ -254,7 +254,7 @@ object ConsumerScalaTest { case "succeed" ⇒ self.reply("ok") } - override def preRestart(reason: scala.Throwable) { + override def preRestart(reason: scala.Throwable, msg: Option[Any]) { self.reply_?("pr") } diff --git a/akka-cluster/src/main/scala/akka/cluster/Cluster.scala b/akka-cluster/src/main/scala/akka/cluster/Cluster.scala index 48c77ce7db..afab58547a 100644 --- a/akka-cluster/src/main/scala/akka/cluster/Cluster.scala +++ b/akka-cluster/src/main/scala/akka/cluster/Cluster.scala @@ -1606,7 +1606,7 @@ class RemoteClusterDaemon(cluster: ClusterNode) extends Actor { self.dispatcher = Dispatchers.newPinnedDispatcher(self) - override def preRestart(reason: Throwable) { + override def preRestart(reason: Throwable, msg: Option[Any]) { EventHandler.debug(this, "RemoteClusterDaemon failed due to [%s] restarting...".format(reason)) } diff --git a/akka-docs/project/migration-guide-1.1.x-1.2.x.rst b/akka-docs/project/migration-guide-1.1.x-1.2.x.rst new file mode 100644 index 0000000000..e4988b9460 --- /dev/null +++ b/akka-docs/project/migration-guide-1.1.x-1.2.x.rst @@ -0,0 +1,6 @@ +.. _migration-1.2: + +################################ + Migration Guide 1.1.x to 1.2.x +################################ + diff --git a/akka-docs/project/migration-guide-1.2.x-2.0.x.rst b/akka-docs/project/migration-guide-1.2.x-2.0.x.rst new file mode 100644 index 0000000000..7eabcf2f10 --- /dev/null +++ b/akka-docs/project/migration-guide-1.2.x-2.0.x.rst @@ -0,0 +1,20 @@ +.. _migration-2.0: + +################################ + Migration Guide 1.2.x to 2.0.x +################################ + +Actors +====== + +The 2.0 release contains several new features which require source-level +changes in client code. This API cleanup is planned to be the last one for a +significant amount of time. + +Lifecycle Callbacks +------------------- + +The :meth:`preRestart(cause: Throwable)` method has been replaced by +:meth:`preRestart(cause: Throwable, lastMessage: Any)`, hence you must insert +the second argument in all overriding methods. The good news is that any missed +actor will not compile without error. diff --git a/akka-docs/project/migration-guides.rst b/akka-docs/project/migration-guides.rst index 7eb063811c..7af815f241 100644 --- a/akka-docs/project/migration-guides.rst +++ b/akka-docs/project/migration-guides.rst @@ -6,6 +6,8 @@ Migration Guides .. toctree:: :maxdepth: 1 + migration-guide-1.2.x-2.0.x + migration-guide-1.1.x-1.2.x migration-guide-1.0.x-1.1.x migration-guide-0.10.x-1.0.x migration-guide-0.9.x-0.10.x diff --git a/akka-spring/src/test/java/akka/spring/RemoteTypedActorOneImpl.java b/akka-spring/src/test/java/akka/spring/RemoteTypedActorOneImpl.java index c7ad0f3de6..f6ab0e56e7 100644 --- a/akka-spring/src/test/java/akka/spring/RemoteTypedActorOneImpl.java +++ b/akka-spring/src/test/java/akka/spring/RemoteTypedActorOneImpl.java @@ -2,6 +2,8 @@ package akka.spring; import akka.actor.*; +import scala.Option; + import java.util.concurrent.CountDownLatch; public class RemoteTypedActorOneImpl extends TypedActor implements RemoteTypedActorOne { @@ -22,7 +24,7 @@ public class RemoteTypedActorOneImpl extends TypedActor implements RemoteTypedAc } @Override - public void preRestart(Throwable e) { + public void preRestart(Throwable e, Option msg) { try { RemoteTypedActorLog.messageLog().put(e.getMessage()); } catch(Exception ex) {} latch.countDown(); } diff --git a/akka-spring/src/test/java/akka/spring/RemoteTypedActorTwoImpl.java b/akka-spring/src/test/java/akka/spring/RemoteTypedActorTwoImpl.java index 1479db0d8c..2ee07195e2 100644 --- a/akka-spring/src/test/java/akka/spring/RemoteTypedActorTwoImpl.java +++ b/akka-spring/src/test/java/akka/spring/RemoteTypedActorTwoImpl.java @@ -2,6 +2,8 @@ package akka.spring; import akka.actor.*; +import scala.Option; + import java.util.concurrent.CountDownLatch; public class RemoteTypedActorTwoImpl extends TypedActor implements RemoteTypedActorTwo { @@ -22,7 +24,7 @@ public class RemoteTypedActorTwoImpl extends TypedActor implements RemoteTypedAc } @Override - public void preRestart(Throwable e) { + public void preRestart(Throwable e, Option msg) { try { RemoteTypedActorLog.messageLog().put(e.getMessage()); } catch(Exception ex) {} latch.countDown(); } diff --git a/akka-testkit/src/test/scala/akka/testkit/TestActorRefSpec.scala b/akka-testkit/src/test/scala/akka/testkit/TestActorRefSpec.scala index 3ef904fe88..6b4f2415b9 100644 --- a/akka-testkit/src/test/scala/akka/testkit/TestActorRefSpec.scala +++ b/akka-testkit/src/test/scala/akka/testkit/TestActorRefSpec.scala @@ -174,7 +174,7 @@ class TestActorRefSpec extends WordSpec with MustMatchers with BeforeAndAfterEac self.faultHandler = OneForOneStrategy(List(classOf[Throwable]), Some(2), Some(1000)) val ref = TestActorRef(new TActor { def receiveT = { case _ ⇒ } - override def preRestart(reason: Throwable) { counter -= 1 } + override def preRestart(reason: Throwable, msg: Option[Any]) { counter -= 1 } override def postRestart(reason: Throwable) { counter -= 1 } }).start() self.dispatcher = CallingThreadDispatcher.global From 05a114470516c6ecfa4ba46ee847342f1f08bee3 Mon Sep 17 00:00:00 2001 From: Garrick Evans Date: Fri, 15 Jul 2011 14:25:09 -0700 Subject: [PATCH 07/51] Covers tickets 988 and 915. Changed ActorRef to notify supervisor with max retry msg when temporary actor shutdown. Actor pool now requires supervision strategy. Updated pool docs. --- .../test/scala/akka/routing/RoutingSpec.scala | 224 +++++++++++++++++- .../scala/akka/ticket/Ticket703Spec.scala | 2 +- .../src/main/scala/akka/actor/ActorRef.scala | 10 +- .../src/main/scala/akka/routing/Pool.scala | 153 +++++++++--- 4 files changed, 345 insertions(+), 44 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala b/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala index 5f4ceedabb..2cdd3e2c4a 100644 --- a/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala @@ -178,7 +178,7 @@ class RoutingSpec extends WordSpec with MustMatchers { val count = new AtomicInteger(0) val pool = actorOf( - new Actor with DefaultActorPool with FixedCapacityStrategy with SmallestMailboxSelector { + new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with FixedCapacityStrategy with SmallestMailboxSelector { def factory = actorOf(new Actor { def receive = { case _ ⇒ @@ -218,7 +218,7 @@ class RoutingSpec extends WordSpec with MustMatchers { "pass ticket #705" in { val pool = actorOf( - new Actor with DefaultActorPool with BoundedCapacityStrategy with MailboxPressureCapacitor with SmallestMailboxSelector with BasicFilter { + new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with BoundedCapacityStrategy with MailboxPressureCapacitor with SmallestMailboxSelector with BasicFilter { def lowerBound = 2 def upperBound = 20 def rampupRate = 0.1 @@ -256,7 +256,7 @@ class RoutingSpec extends WordSpec with MustMatchers { val count = new AtomicInteger(0) val pool = actorOf( - new Actor with DefaultActorPool with BoundedCapacityStrategy with ActiveFuturesPressureCapacitor with SmallestMailboxSelector with BasicNoBackoffFilter { + new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with BoundedCapacityStrategy with ActiveFuturesPressureCapacitor with SmallestMailboxSelector with BasicNoBackoffFilter { def factory = actorOf(new Actor { def receive = { case n: Int ⇒ @@ -321,7 +321,7 @@ class RoutingSpec extends WordSpec with MustMatchers { val count = new AtomicInteger(0) val pool = actorOf( - new Actor with DefaultActorPool with BoundedCapacityStrategy with MailboxPressureCapacitor with SmallestMailboxSelector with BasicNoBackoffFilter { + new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with BoundedCapacityStrategy with MailboxPressureCapacitor with SmallestMailboxSelector with BasicNoBackoffFilter { def factory = actorOf(new Actor { def receive = { case n: Int ⇒ @@ -375,7 +375,7 @@ class RoutingSpec extends WordSpec with MustMatchers { val delegates = new java.util.concurrent.ConcurrentHashMap[String, String] val pool1 = actorOf( - new Actor with DefaultActorPool with FixedCapacityStrategy with RoundRobinSelector with BasicNoBackoffFilter { + new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with FixedCapacityStrategy with RoundRobinSelector with BasicNoBackoffFilter { def factory = actorOf(new Actor { def receive = { case _ ⇒ @@ -404,7 +404,7 @@ class RoutingSpec extends WordSpec with MustMatchers { delegates.clear() val pool2 = actorOf( - new Actor with DefaultActorPool with FixedCapacityStrategy with RoundRobinSelector with BasicNoBackoffFilter { + new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with FixedCapacityStrategy with RoundRobinSelector with BasicNoBackoffFilter { def factory = actorOf(new Actor { def receive = { case _ ⇒ @@ -434,7 +434,7 @@ class RoutingSpec extends WordSpec with MustMatchers { val latch = TestLatch(10) val pool = actorOf( - new Actor with DefaultActorPool with BoundedCapacityStrategy with MailboxPressureCapacitor with SmallestMailboxSelector with Filter with RunningMeanBackoff with BasicRampup { + new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with BoundedCapacityStrategy with MailboxPressureCapacitor with SmallestMailboxSelector with Filter with RunningMeanBackoff with BasicRampup { def factory = actorOf(new Actor { def receive = { case n: Int ⇒ @@ -480,7 +480,7 @@ class RoutingSpec extends WordSpec with MustMatchers { "support typed actors" in { import RoutingSpec._ import TypedActor._ - def createPool = new Actor with DefaultActorPool with BoundedCapacityStrategy with MailboxPressureCapacitor with SmallestMailboxSelector with Filter with RunningMeanBackoff with BasicRampup { + def createPool = new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with BoundedCapacityStrategy with MailboxPressureCapacitor with SmallestMailboxSelector with Filter with RunningMeanBackoff with BasicRampup { def lowerBound = 1 def upperBound = 5 def pressureThreshold = 1 @@ -499,6 +499,214 @@ class RoutingSpec extends WordSpec with MustMatchers { for ((i, r) ← results) r.get must equal(i * i) } + + "provide default supervision of pooled actors" in { + import akka.config.Supervision._ + val pingCount = new AtomicInteger(0) + val deathCount = new AtomicInteger(0) + var keepDying = false + + val pool1 = actorOf( + new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with BoundedCapacityStrategy with ActiveFuturesPressureCapacitor with SmallestMailboxSelector with BasicFilter { + def lowerBound = 2 + def upperBound = 5 + def rampupRate = 0.1 + def backoffRate = 0.1 + def backoffThreshold = 0.5 + def partialFill = true + def selectionCount = 1 + def instance = factory + def receive = _route + def pressureThreshold = 1 + def factory = actorOf(new Actor { + if (deathCount.get > 5) deathCount.set(0) + if (deathCount.get > 0) {deathCount.incrementAndGet;throw new IllegalStateException("keep dying")} + def receive = { + case akka.Die ⇒ + if (keepDying) deathCount.incrementAndGet + throw new RuntimeException + case _ => pingCount.incrementAndGet + } + }).start() + }).start() + + val pool2 = actorOf( + new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with BoundedCapacityStrategy with ActiveFuturesPressureCapacitor with SmallestMailboxSelector with BasicFilter { + def lowerBound = 2 + def upperBound = 5 + def rampupRate = 0.1 + def backoffRate = 0.1 + def backoffThreshold = 0.5 + def partialFill = true + def selectionCount = 1 + def instance = factory + def receive = _route + def pressureThreshold = 1 + def factory = actorOf(new Actor { + self.lifeCycle = Permanent + if (deathCount.get > 5) deathCount.set(0) + if (deathCount.get > 0) {deathCount.incrementAndGet;throw new IllegalStateException("keep dying")} + def receive = { + case akka.Die ⇒ + if (keepDying) deathCount.incrementAndGet + throw new RuntimeException + case _ => pingCount.incrementAndGet + } + }).start() + }).start() + + val pool3 = actorOf( + new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with BoundedCapacityStrategy with ActiveFuturesPressureCapacitor with RoundRobinSelector with BasicFilter { + def lowerBound = 2 + def upperBound = 5 + def rampupRate = 0.1 + def backoffRate = 0.1 + def backoffThreshold = 0.5 + def partialFill = true + def selectionCount = 1 + def instance = factory + def receive = _route + def pressureThreshold = 1 + def factory = actorOf(new Actor { + self.lifeCycle = Temporary + if (deathCount.get > 5) deathCount.set(0) + if (deathCount.get > 0) {deathCount.incrementAndGet;throw new IllegalStateException("keep dying")} + def receive = { + case akka.Die ⇒ + if (keepDying) deathCount.incrementAndGet + throw new RuntimeException + case _ => pingCount.incrementAndGet + } + }).start() + }).start() + + // default lifecycle + // actor comes back right away + pingCount.set(0) + keepDying = false + pool1 ! "ping" + (pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pool1 ! akka.Die + sleepFor(2 seconds) + (pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pingCount.get must be (1) + + // default lifecycle + // actor dies completely + pingCount.set(0) + keepDying = true + pool1 ! "ping" + (pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pool1 ! akka.Die + sleepFor(2 seconds) + (pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(1) + pool1 ! "ping" + (pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pingCount.get must be (2) + + // permanent lifecycle + // actor comes back right away + pingCount.set(0) + keepDying = false + pool2 ! "ping" + (pool2 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pool2 ! akka.Die + sleepFor(2 seconds) + (pool2 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pingCount.get must be (1) + + // permanent lifecycle + // actor dies completely + pingCount.set(0) + keepDying = true + pool2 ! "ping" + (pool2 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pool2 ! akka.Die + sleepFor(2 seconds) + (pool2 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(1) + pool2 ! "ping" + (pool2 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pingCount.get must be (2) + + // temporary lifecycle + pingCount.set(0) + keepDying = false + pool3 ! "ping" + (pool3 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pool3 ! akka.Die + sleepFor(2 seconds) + (pool3 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(1) + pool3 ! "ping" + pool3 ! "ping" + pool3 ! "ping" + (pool3 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pingCount.get must be (4) + } + + "support customizable supervision config of pooled actors" in { + import akka.config.Supervision._ + val pingCount = new AtomicInteger(0) + val deathCount = new AtomicInteger(0) + var keepDying = false + + trait LimitedTrapSupervisionConfig extends ActorPoolSupervisionConfig { + def poolFaultHandler = OneForOneStrategy(List(classOf[IllegalStateException]), 5, 1000) + } + + object BadState + + val pool1 = actorOf( + new Actor with DefaultActorPool with LimitedTrapSupervisionConfig with BoundedCapacityStrategy with ActiveFuturesPressureCapacitor with SmallestMailboxSelector with BasicFilter { + def lowerBound = 2 + def upperBound = 5 + def rampupRate = 0.1 + def backoffRate = 0.1 + def backoffThreshold = 0.5 + def partialFill = true + def selectionCount = 1 + def instance = factory + def receive = _route + def pressureThreshold = 1 + def factory = actorOf(new Actor { + if (deathCount.get > 5) deathCount.set(0) + if (deathCount.get > 0) {deathCount.incrementAndGet;throw new IllegalStateException("keep dying")} + def receive = { + case BadState ⇒ + if (keepDying) deathCount.incrementAndGet + throw new IllegalStateException + case akka.Die => + throw new RuntimeException + case _ => pingCount.incrementAndGet + } + }).start() + }).start() + + + // actor comes back right away + pingCount.set(0) + keepDying = false + pool1 ! "ping" + (pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pool1 ! BadState + sleepFor(2 seconds) + (pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pingCount.get must be (1) + + // actor dies completely + pingCount.set(0) + keepDying = true + pool1 ! "ping" + (pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pool1 ! BadState + sleepFor(2 seconds) + (pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(1) + pool1 ! "ping" + (pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2) + pingCount.get must be (2) + + // kill it + intercept[RuntimeException](pool1.?(akka.Die).get) + } } } diff --git a/akka-actor-tests/src/test/scala/akka/ticket/Ticket703Spec.scala b/akka-actor-tests/src/test/scala/akka/ticket/Ticket703Spec.scala index b838f33efc..fd9bc4d1f7 100644 --- a/akka-actor-tests/src/test/scala/akka/ticket/Ticket703Spec.scala +++ b/akka-actor-tests/src/test/scala/akka/ticket/Ticket703Spec.scala @@ -11,7 +11,7 @@ class Ticket703Spec extends WordSpec with MustMatchers { "A ? call to an actor pool" should { "reuse the proper timeout" in { val actorPool = actorOf( - new Actor with DefaultActorPool with BoundedCapacityStrategy with MailboxPressureCapacitor with SmallestMailboxSelector with BasicNoBackoffFilter { + new Actor with DefaultActorPool with DefaultActorPoolSupervisionConfig with BoundedCapacityStrategy with MailboxPressureCapacitor with SmallestMailboxSelector with BasicNoBackoffFilter { def lowerBound = 2 def upperBound = 20 def rampupRate = 0.1 diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index 0874f93c4c..88cfdfe6a2 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -772,7 +772,7 @@ class LocalActorRef private[akka] (private[this] val actorFactory: () ⇒ Actor, lifeCycle match { case Temporary ⇒ - shutDownTemporaryActor(this) + shutDownTemporaryActor(this, reason) true case _ ⇒ // either permanent or none where default is permanent @@ -815,7 +815,7 @@ class LocalActorRef private[akka] (private[this] val actorFactory: () ⇒ Actor, val actorRef = i.next actorRef.lifeCycle match { // either permanent or none where default is permanent - case Temporary ⇒ shutDownTemporaryActor(actorRef) + case Temporary ⇒ shutDownTemporaryActor(actorRef, reason) case _ ⇒ actorRef.restart(reason, maxNrOfRetries, withinTimeRange) } } @@ -841,9 +841,11 @@ class LocalActorRef private[akka] (private[this] val actorFactory: () ⇒ Actor, case valid ⇒ valid } - private def shutDownTemporaryActor(temporaryActor: ActorRef) { + private def shutDownTemporaryActor(temporaryActor: ActorRef, reason: Throwable) { temporaryActor.stop() _linkedActors.remove(temporaryActor.uuid) // remove the temporary actor + // when this comes down through the handleTrapExit path, we get here when the temp actor is restarted + notifySupervisorWithMessage(MaximumNumberOfRestartsWithinTimeRangeReached(temporaryActor, Some(0), None, reason)) // if last temporary actor is gone, then unlink me from supervisor if (_linkedActors.isEmpty) notifySupervisorWithMessage(UnlinkAndStop(this)) true @@ -860,7 +862,7 @@ class LocalActorRef private[akka] (private[this] val actorFactory: () ⇒ Actor, if (supervisor.isDefined) notifySupervisorWithMessage(Death(this, reason)) else { lifeCycle match { - case Temporary ⇒ shutDownTemporaryActor(this) + case Temporary ⇒ shutDownTemporaryActor(this, reason) case _ ⇒ dispatcher.resume(this) //Resume processing for this actor } } diff --git a/akka-actor/src/main/scala/akka/routing/Pool.scala b/akka-actor/src/main/scala/akka/routing/Pool.scala index 249d087ed6..ea280adcae 100644 --- a/akka-actor/src/main/scala/akka/routing/Pool.scala +++ b/akka-actor/src/main/scala/akka/routing/Pool.scala @@ -4,8 +4,9 @@ package akka.routing -import akka.actor.{ Actor, ActorRef, PoisonPill } +import akka.actor.{ Actor, ActorRef, PoisonPill, Death, MaximumNumberOfRestartsWithinTimeRangeReached } import akka.dispatch.{ Promise } +import akka.config.Supervision._ /** * Actor pooling @@ -35,44 +36,102 @@ object ActorPool { * Defines the nature of an actor pool. */ trait ActorPool { - def instance(): ActorRef //Question, Instance of what? - def capacity(delegates: Seq[ActorRef]): Int //Question, What is the semantics of this return value? - def select(delegates: Seq[ActorRef]): Tuple2[Iterator[ActorRef], Int] //Question, Why does select return this instead of an ordered Set? + /** + * Adds a new actor to the pool. The DefaultActorPool implementation will start and link (supervise) this actor. + * This method is invoked whenever the pool determines it must boost capacity. + * @return A new actor for the pool + */ + def instance(): ActorRef + /** + * Returns the overall desired change in pool capacity. This method is used by non-static pools as the means + * for the capacity strategy to influence the pool. + * @param _delegates The current sequence of pooled actors + * @return the number of delegates by which the pool should be adjusted (positive, negative or zero) + */ + def capacity(delegates: Seq[ActorRef]): Int + /** + * Provides the results of the selector, one or more actors, to which an incoming message is forwarded. + * This method returns an iterator since a selector might return more than one actor to handle the message. + * You might want to do this to perform redundant processing of particularly error-prone messages. + * @param _delegates The current sequence of pooled actors + * @return a list of actors to which the message will be delivered + */ + def select(delegates: Seq[ActorRef]): Seq[ActorRef] } /** - * A default implementation of a pool, on each message to route, - * - checks the current capacity and adjusts accordingly if needed - * - routes the incoming message to a selection set of delegate actors + * Defines the configuration options for how the pool supervises the actors. */ -trait DefaultActorPool extends ActorPool { this: Actor ⇒ +trait ActorPoolSupervisionConfig { + /** + * Defines the default fault handling strategy to be employed by the pool. + */ + def poolFaultHandler: FaultHandlingStrategy +} + +/** + * Provides a default implementation of the supervision configuration by + * defining a One-for-One fault handling strategy, trapping exceptions, + * limited to 5 retries within 1 second. + * + * This is just a basic strategy and implementors are encouraged to define + * something more appropriate for their needs. + */ +trait DefaultActorPoolSupervisionConfig extends ActorPoolSupervisionConfig { + def poolFaultHandler = OneForOneStrategy(List(classOf[Exception]), 5, 1000) +} + +/** + * A default implementation of a pool that: + * First, invokes the pool's capacitor that tells it, based on the current delegate count + * and it's own heuristic by how many delegates the pool should be resized. Resizing can + * can be incremental, decremental or flat. If there is a change to capacity, new delegates + * are added or existing ones are removed. Removed actors are sent the PoisonPill message. + * New actors are automatically started and linked. The pool supervises the actors and will + * use the fault handling strategy specified by the mixed-in ActorPoolSupervisionConfig. + * Pooled actors may be any lifecycle. If you're testing pool sizes during runtime, take a + * look at the unit tests... Any delegate with a Permanent lifecycle will be + * restarted and the pool size will be level with what it was prior to the fault. In just + * about every other case, e.g. the delegates are Temporary or the delegate cannot be + * restarted within the time interval specified in the fault handling strategy, the pool will + * be temporarily shy by that actor (it will have been removed by not back-filled). The + * back-fill if any is required, will occur on the next message [as usual]. + * + * Second, invokes the pool's selector that returns a list of delegates that are to receive + * the incoming message. Selectors may return more than one actor. If partialFill + * is true then it might also the case that fewer than number of desired actors will be + * returned. + * + * Lastly, routes by forwarding, the incoming message to each delegate in the selected set. + */ +trait DefaultActorPool extends ActorPool { this: Actor with ActorPoolSupervisionConfig ⇒ import ActorPool._ - import akka.actor.MaximumNumberOfRestartsWithinTimeRangeReached - protected var _delegates = Vector[ActorRef]() - private var _lastCapacityChange = 0 - private var _lastSelectorCount = 0 + protected[akka] var _delegates = Vector[ActorRef]() - override def postStop() = _delegates foreach { delegate ⇒ - try { - delegate ! PoisonPill - } catch { case e: Exception ⇒ } //Ignore any exceptions here + override def preStart() { + self.faultHandler = poolFaultHandler + } + override def postStop() { + _delegates foreach { delegate ⇒ + try { + delegate ! PoisonPill + } catch { case e: Exception ⇒ } //Ignore any exceptions here + } } protected def _route(): Receive = { // for testing... case Stat ⇒ self reply_? Stats(_delegates length) - case max: MaximumNumberOfRestartsWithinTimeRangeReached ⇒ - _delegates = _delegates filterNot { _.uuid == max.victim.uuid } + case MaximumNumberOfRestartsWithinTimeRangeReached(victim, _, _, _) ⇒ + _delegates = _delegates filterNot { _.uuid == victim.uuid } + case Death(victim, _) => + _delegates = _delegates filterNot { _.uuid == victim.uuid } case msg ⇒ resizeIfAppropriate() - select(_delegates) match { - case (selectedDelegates, count) ⇒ - _lastSelectorCount = count - selectedDelegates foreach { _ forward msg } //Should we really send the same message to several actors? - } + select(_delegates) foreach { _ forward msg } } private def resizeIfAppropriate() { @@ -95,14 +154,15 @@ trait DefaultActorPool extends ActorPool { this: Actor ⇒ case _ ⇒ _delegates //No change } - _lastCapacityChange = requestedCapacity _delegates = newDelegates } } /** * Selectors - * These traits define how, when a message needs to be routed, delegate(s) are chosen from the pool + * + * These traits define how, when a message needs to be routed, delegate(s) are chosen from the pool. + * Note that it's acceptable to return more than one actor to handle a given message. */ /** @@ -112,7 +172,7 @@ trait SmallestMailboxSelector { def selectionCount: Int def partialFill: Boolean - def select(delegates: Seq[ActorRef]): Tuple2[Iterator[ActorRef], Int] = { + def select(delegates: Seq[ActorRef]): Seq[ActorRef] = { var set: Seq[ActorRef] = Nil var take = if (partialFill) math.min(selectionCount, delegates.length) else selectionCount @@ -121,7 +181,7 @@ trait SmallestMailboxSelector { take -= set.size } - (set.iterator, set.size) + set } } @@ -134,7 +194,7 @@ trait RoundRobinSelector { def selectionCount: Int def partialFill: Boolean - def select(delegates: Seq[ActorRef]): Tuple2[Iterator[ActorRef], Int] = { + def select(delegates: Seq[ActorRef]): Seq[ActorRef] = { val length = delegates.length val take = if (partialFill) math.min(selectionCount, length) else selectionCount @@ -145,13 +205,16 @@ trait RoundRobinSelector { delegates(_last) } - (set.iterator, set.size) + set } } /** * Capacitors - * These traits define how to alter the size of the pool + * + * These traits define how to alter the size of the pool according to some desired behavior. + * Capacitors are required (minimally) by the pool to establish bounds on the number of delegates + * that may exist in the pool. */ /** @@ -163,7 +226,13 @@ trait FixedSizeCapacitor { } /** - * Constrains the pool capacity to a bounded range + * Constrains the pool capacity to a bounded range. + * This capacitor employs 'pressure capacitors' (sorry for the unforunate confusing naming) + * to feed a 'pressure' delta into the capacity function. This measure is + * basically the difference between the current pressure level and a pre-established threshhold. + * When using this capacitor you must provide a method called 'pressure' or mix-in + * one of the PressureCapacitor traits below. + * */ trait BoundedCapacitor { def lowerBound: Int @@ -200,17 +269,39 @@ trait ActiveFuturesPressureCapacitor { } /** + * */ trait CapacityStrategy { import ActorPool._ + /** + * This method returns a 'pressure level' that will be fed into the capacitor and + * evaluated against the established threshhold. For instance, in general, if + * the current pressure level exceeds the capacity of the pool, new delegates will + * be added. + */ def pressure(delegates: Seq[ActorRef]): Int + /** + * This method can be used to smooth the response of the capacitor by considering + * the current pressure and current capacity. + */ def filter(pressure: Int, capacity: Int): Int protected def _eval(delegates: Seq[ActorRef]): Int = filter(pressure(delegates), delegates.size) } +/** + * Use this trait to setup a pool that uses a fixed delegate count. + */ trait FixedCapacityStrategy extends FixedSizeCapacitor + +/** + * Use this trait to setup a pool that may have a variable number of + * delegates but always within an established upper and lower limit. + * + * If mix this into your pool implementation, you must also provide a + * PressureCapacitor and a Filter. + */ trait BoundedCapacityStrategy extends CapacityStrategy with BoundedCapacitor /** From e7b33d46c23bf6e86260bb309df024628394a973 Mon Sep 17 00:00:00 2001 From: Garrick Evans Date: Fri, 15 Jul 2011 15:34:20 -0700 Subject: [PATCH 08/51] fix bad merge --- akka-actor/src/main/scala/akka/actor/ActorRef.scala | 5 ----- 1 file changed, 5 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index bea369af83..084ca12994 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -888,13 +888,8 @@ class LocalActorRef private[akka](private[this] val actorFactory: () ⇒ Actor, if (supervisor.isDefined) notifySupervisorWithMessage(Death(this, reason)) else { lifeCycle match { -<<<<<<< HEAD case Temporary ⇒ shutDownTemporaryActor(this, reason) case _ ⇒ dispatcher.resume(this) //Resume processing for this actor -======= - case Temporary ⇒ shutDownTemporaryActor(this) - case _ ⇒ dispatcher.resume(this) //Resume processing for this actor ->>>>>>> 2cf64bccae0afcfa2ed9062e1590cd9e4f187aeb } } } From 68fdaaaf0fc45446ea758ca4d3310a68152967a1 Mon Sep 17 00:00:00 2001 From: Martin Krasser Date: Sat, 16 Jul 2011 10:38:17 +0200 Subject: [PATCH 09/51] re-added akka-sample-camel to build --- .../src/main/scala/sample/camel/Boot.scala | 6 ++-- .../camel/HttpConcurrencyTestStress.scala | 4 ++- .../sample/camel/RemoteConsumerTest.scala | 4 +-- project/AkkaBuild.scala | 34 +++++++++++++++++-- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala index 5bf50a5e2c..8f3d16b318 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala @@ -7,7 +7,8 @@ import org.apache.camel.spring.spi.ApplicationContextRegistry import org.springframework.context.support.ClassPathXmlApplicationContext import akka.actor.Actor._ -import akka.actor.{TypedActor, Supervisor} +import akka.actor.TypedActor +import akka.actor.TypedActor.Configuration._ import akka.camel.CamelContextManager import akka.config.Supervision._ @@ -89,7 +90,8 @@ class Boot { // Active object example // ----------------------------------------------------------------------- - //TypedActor.newInstance(classOf[TypedConsumer1], classOf[TypedConsumer1Impl]) + // TODO: investigate why this consumer is not published + TypedActor.typedActorOf(classOf[TypedConsumer1], classOf[TypedConsumer1Impl], defaultConfiguration) } /** diff --git a/akka-samples/akka-sample-camel/src/test/scala/sample/camel/HttpConcurrencyTestStress.scala b/akka-samples/akka-sample-camel/src/test/scala/sample/camel/HttpConcurrencyTestStress.scala index 255a6262c0..3511ae701a 100644 --- a/akka-samples/akka-sample-camel/src/test/scala/sample/camel/HttpConcurrencyTestStress.scala +++ b/akka-samples/akka-sample-camel/src/test/scala/sample/camel/HttpConcurrencyTestStress.scala @@ -21,6 +21,8 @@ class HttpConcurrencyTestStress extends JUnitSuite { import HttpConcurrencyTestStress._ @Test def shouldProcessMessagesConcurrently = { + /* TODO: fix stress test + val num = 50 val latch1 = new CountDownLatch(num) val latch2 = new CountDownLatch(num) @@ -38,7 +40,7 @@ class HttpConcurrencyTestStress extends JUnitSuite { latch3.await assert(num == (client1 ? "getCorrelationIdCount").as[Int].get) assert(num == (client2 ? "getCorrelationIdCount").as[Int].get) - assert(num == (client3 ? "getCorrelationIdCount").as[Int].get) + assert(num == (client3 ? "getCorrelationIdCount").as[Int].get)*/ } } diff --git a/akka-samples/akka-sample-camel/src/test/scala/sample/camel/RemoteConsumerTest.scala b/akka-samples/akka-sample-camel/src/test/scala/sample/camel/RemoteConsumerTest.scala index 31586311fa..92b204ec53 100644 --- a/akka-samples/akka-sample-camel/src/test/scala/sample/camel/RemoteConsumerTest.scala +++ b/akka-samples/akka-sample-camel/src/test/scala/sample/camel/RemoteConsumerTest.scala @@ -5,8 +5,8 @@ import org.scalatest.{GivenWhenThen, BeforeAndAfterAll, FeatureSpec} import akka.actor.Actor._ import akka.actor._ import akka.camel._ -import akka.remote.netty.NettyRemoteSupport -import akka.remoteinterface.RemoteServerModule +//import akka.remote.netty.NettyRemoteSupport +//import akka.remoteinterface.RemoteServerModule /** * @author Martin Krasser diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index 12695596cb..ece39cd75e 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -200,7 +200,7 @@ object AkkaBuild extends Build { id = "akka-samples", base = file("akka-samples"), settings = parentSettings, - aggregate = Seq(fsmSample) + aggregate = Seq(fsmSample, camelSample) ) // lazy val antsSample = Project( @@ -224,6 +224,29 @@ object AkkaBuild extends Build { settings = defaultSettings ) + lazy val camelSampleXML = + + + + + + + + + + + + + lazy val camelSample = Project( + id = "akka-sample-camel", + base = file("akka-samples/akka-sample-camel"), + dependencies = Seq(actor, camelTyped), + settings = defaultSettings ++ Seq( + ivyXML := camelSampleXML, + libraryDependencies ++= Dependencies.sampleCamel + ) + ) + // lazy val helloSample = Project( // id = "akka-sample-hello", // base = file("akka-samples/akka-sample-hello"), @@ -356,6 +379,9 @@ object Dependencies { jettyUtil, jettyXml, jettyServlet, jerseyCore, jerseyJson, jerseyScala, jacksonCore, staxApi, Provided.jerseyServer ) + + val sampleCamel = Seq(camelCore, commonsCodec, Runtime.activemq, Runtime.springJms, + Test.junit, Test.scalatest, Test.logback) } object Dependency { @@ -426,7 +452,11 @@ object Dependency { // Runtime object Runtime { - val logback = "ch.qos.logback" % "logback-classic" % V.Logback % "runtime" // MIT + val activemq = "org.apache.activemq" % "activemq-core" % "5.4.2" % "runtime" // ApacheV2 + val camelJetty = "org.apache.camel" % "camel-jetty" % V.CamelPatch % "runtime" // ApacheV2 + val camelJms = "org.apache.camel" % "camel-jms" % V.Camel % "runtime" // ApacheV2 + val logback = "ch.qos.logback" % "logback-classic" % V.Logback % "runtime" // MIT + val springJms = "org.springframework" % "spring-jms" % V.Spring % "compile" // ApacheV2 } // Test From 13da7775869289a69423d93daa1e8d0224704096 Mon Sep 17 00:00:00 2001 From: Martin Krasser Date: Sat, 16 Jul 2011 11:18:08 +0200 Subject: [PATCH 10/51] Excluded conflicting jetty dependency --- .../test/scala/sample/camel/HttpConcurrencyTestStress.scala | 6 +++--- project/AkkaBuild.scala | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/akka-samples/akka-sample-camel/src/test/scala/sample/camel/HttpConcurrencyTestStress.scala b/akka-samples/akka-sample-camel/src/test/scala/sample/camel/HttpConcurrencyTestStress.scala index 3511ae701a..bbe039af22 100644 --- a/akka-samples/akka-sample-camel/src/test/scala/sample/camel/HttpConcurrencyTestStress.scala +++ b/akka-samples/akka-sample-camel/src/test/scala/sample/camel/HttpConcurrencyTestStress.scala @@ -52,9 +52,9 @@ object HttpConcurrencyTestStress { val workers = for (i <- 1 to 8) yield actorOf[HttpServerWorker].start val balancer = loadBalancerActor(new CyclicIterator(workers.toList)) - service.get.awaitEndpointActivation(1) { - actorOf(new HttpServerActor(balancer)).start - } + //service.get.awaitEndpointActivation(1) { + // actorOf(new HttpServerActor(balancer)).start + //} } @AfterClass diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index ece39cd75e..0e47476ac9 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -232,9 +232,9 @@ object AkkaBuild extends Build { - + lazy val camelSample = Project( From a3408bf3f8c0c1916754a036e1fcdb06e4b6d063 Mon Sep 17 00:00:00 2001 From: Martin Krasser Date: Sat, 16 Jul 2011 11:40:24 +0200 Subject: [PATCH 11/51] Move sampleCamel-specific Ivy XML to Dependencies object --- project/AkkaBuild.scala | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index 0e47476ac9..76a6c9646d 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -224,25 +224,12 @@ object AkkaBuild extends Build { settings = defaultSettings ) - lazy val camelSampleXML = - - - - - - - - - - lazy val camelSample = Project( id = "akka-sample-camel", base = file("akka-samples/akka-sample-camel"), dependencies = Seq(actor, camelTyped), settings = defaultSettings ++ Seq( - ivyXML := camelSampleXML, + ivyXML := Dependencies.sampleCamelXML, libraryDependencies ++= Dependencies.sampleCamel ) ) @@ -382,6 +369,20 @@ object Dependencies { val sampleCamel = Seq(camelCore, commonsCodec, Runtime.activemq, Runtime.springJms, Test.junit, Test.scalatest, Test.logback) + + val sampleCamelXML = + + + + + + + + + + } object Dependency { From 18dd81b12737f354701c1e651a8236d161486e08 Mon Sep 17 00:00:00 2001 From: Martin Krasser Date: Sat, 16 Jul 2011 11:52:23 +0200 Subject: [PATCH 12/51] changed scope of spring-jms dependency to runtime --- project/AkkaBuild.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index 76a6c9646d..2f507c9432 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -457,7 +457,7 @@ object Dependency { val camelJetty = "org.apache.camel" % "camel-jetty" % V.CamelPatch % "runtime" // ApacheV2 val camelJms = "org.apache.camel" % "camel-jms" % V.Camel % "runtime" // ApacheV2 val logback = "ch.qos.logback" % "logback-classic" % V.Logback % "runtime" // MIT - val springJms = "org.springframework" % "spring-jms" % V.Spring % "compile" // ApacheV2 + val springJms = "org.springframework" % "spring-jms" % V.Spring % "runtime" // ApacheV2 } // Test From a348025ccb0b76c547e98b5aee9af13a86d3e706 Mon Sep 17 00:00:00 2001 From: Roland Date: Sat, 16 Jul 2011 18:42:24 -0400 Subject: [PATCH 13/51] improve testing docs --- akka-docs/scala/testing.rst | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/akka-docs/scala/testing.rst b/akka-docs/scala/testing.rst index f3bb07c5bb..8b7b270bff 100644 --- a/akka-docs/scala/testing.rst +++ b/akka-docs/scala/testing.rst @@ -375,6 +375,19 @@ with message flows: This feature is useful e.g. when testing a logging system, where you want to ignore regular messages and are only interested in your specific ones. +Expecting Exceptions +-------------------- + +One case which is not handled by the :obj:`testActor` is if an exception is +thrown while processing the message sent to the actor under test. This can be +tested by using a :class:`Future` based invocation:: + + // assuming ScalaTest ShouldMatchers + + evaluating { + (someActor ? badOperation).await.get + } should produce [UnhandledMessageException] + .. _TestKit.within: Timing Assertions @@ -468,7 +481,7 @@ using a small example:: var dest1 : ActorRef = _ var dest2 : ActorRef = _ def receive = { - case (d1, d2) => + case (d1: ActorRef, d2: ActorRef) => dest1 = d1 dest2 = d2 case x => From 892c6e056c9bc790ad98f2446b81cbace56add6c Mon Sep 17 00:00:00 2001 From: Roland Date: Sat, 16 Jul 2011 21:30:08 -0400 Subject: [PATCH 14/51] improve scaladoc of TestKit.expectMsgAllOf --- akka-testkit/src/main/scala/akka/testkit/TestKit.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/akka-testkit/src/main/scala/akka/testkit/TestKit.scala b/akka-testkit/src/main/scala/akka/testkit/TestKit.scala index e7c23d30d7..f5d0a72046 100644 --- a/akka-testkit/src/main/scala/akka/testkit/TestKit.scala +++ b/akka-testkit/src/main/scala/akka/testkit/TestKit.scala @@ -378,11 +378,9 @@ trait TestKitLight { * given duration, with an AssertionFailure being thrown in case of timeout. * *
-   * within(1 second) {
    *   dispatcher ! SomeWork1()
    *   dispatcher ! SomeWork2()
-   *   expectMsgAllOf(Result1(), Result2())
-   * }
+   *   expectMsgAllOf(1 second, Result1(), Result2())
    * 
*/ def expectMsgAllOf[T](max: Duration, obj: T*): Seq[T] = expectMsgAllOf_internal(max.dilated, obj: _*) From 7983a66f681468432171d6c4391682c2840ba02c Mon Sep 17 00:00:00 2001 From: Peter Veentjer Date: Sun, 17 Jul 2011 09:02:36 +0300 Subject: [PATCH 15/51] Ticket 964: rename of reply? --- .../scala/akka/actor/actor/ActorRefSpec.scala | 4 ++-- .../actor/supervisor/SupervisorSpec.scala | 4 ++-- .../akka/actor/supervisor/Ticket669Spec.scala | 4 ++-- .../scala/akka/dispatch/ActorModelSpec.scala | 4 ++-- .../test/scala/akka/dispatch/FutureSpec.scala | 10 ++++---- .../dispatch/PriorityDispatcherSpec.scala | 2 +- .../test/scala/akka/routing/RoutingSpec.scala | 4 ++-- .../scala/akka/ticket/Ticket703Spec.scala | 2 +- .../src/main/scala/akka/actor/ActorRef.scala | 24 ++++++++++++------- .../src/main/scala/akka/routing/Pool.scala | 2 +- .../scala/akka/camel/ConsumerScalaTest.scala | 4 ++-- akka-docs/scala/actors.rst | 4 ++-- akka-docs/scala/fault-tolerance.rst | 8 +++---- .../src/main/scala/akka/agent/Agent.scala | 4 ++-- 14 files changed, 44 insertions(+), 36 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRefSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRefSpec.scala index 28c68b15eb..95f5f29937 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRefSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/ActorRefSpec.scala @@ -305,8 +305,8 @@ class ActorRefSpec extends WordSpec with MustMatchers { val ref = Actor.actorOf( new Actor { def receive = { - case 5 ⇒ self reply_? "five" - case null ⇒ self reply_? "null" + case 5 ⇒ self tryReply "five" + case null ⇒ self tryReply "null" } }).start() diff --git a/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorSpec.scala index d82905b8cf..46573f7799 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorSpec.scala @@ -41,7 +41,7 @@ object SupervisorSpec { def receive = { case Ping ⇒ messageLog.put(PingMessage) - self.reply_?(PongMessage) + self.tryReply(PongMessage) case Die ⇒ throw new RuntimeException(ExceptionMessage) } @@ -361,7 +361,7 @@ class SupervisorSpec extends WordSpec with MustMatchers with BeforeAndAfterEach if (inits.get % 2 == 0) throw new IllegalStateException("Don't wanna!") def receive = { - case Ping ⇒ self.reply_?(PongMessage) + case Ping ⇒ self.tryReply(PongMessage) case Die ⇒ throw new Exception("expected") } }) diff --git a/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala b/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala index bddad26176..0976063b3b 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala @@ -63,11 +63,11 @@ object Ticket669Spec { } override def preRestart(reason: scala.Throwable) { - self.reply_?("failure1") + self.tryReply("failure1") } override def postStop() { - self.reply_?("failure2") + self.tryReply("failure2") } } } diff --git a/akka-actor-tests/src/test/scala/akka/dispatch/ActorModelSpec.scala b/akka-actor-tests/src/test/scala/akka/dispatch/ActorModelSpec.scala index 62297ca495..327d6dda10 100644 --- a/akka-actor-tests/src/test/scala/akka/dispatch/ActorModelSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/dispatch/ActorModelSpec.scala @@ -20,7 +20,7 @@ object ActorModelSpec { sealed trait ActorModelMessage - case class Reply_?(expect: Any) extends ActorModelMessage + case class TryReply(expect: Any) extends ActorModelMessage case class Reply(expect: Any) extends ActorModelMessage @@ -73,7 +73,7 @@ object ActorModelSpec { case Wait(time) ⇒ ack; Thread.sleep(time); busy.switchOff() case WaitAck(time, l) ⇒ ack; Thread.sleep(time); l.countDown(); busy.switchOff() case Reply(msg) ⇒ ack; self.reply(msg); busy.switchOff() - case Reply_?(msg) ⇒ ack; self.reply_?(msg); busy.switchOff() + case TryReply(msg) ⇒ ack; self.tryReply(msg); busy.switchOff() case Forward(to, msg) ⇒ ack; to.forward(msg); busy.switchOff() case CountDown(latch) ⇒ ack; latch.countDown(); busy.switchOff() case Increment(count) ⇒ ack; count.incrementAndGet(); busy.switchOff() diff --git a/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala b/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala index b0766121bb..238a1cc612 100644 --- a/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala @@ -176,7 +176,7 @@ class FutureSpec extends JUnitSuite { def shouldFoldResults { val actors = (1 to 10).toList map { _ ⇒ actorOf(new Actor { - def receive = { case (add: Int, wait: Int) ⇒ Thread.sleep(wait); self reply_? add } + def receive = { case (add: Int, wait: Int) ⇒ Thread.sleep(wait); self tryReply add } }).start() } val timeout = 10000 @@ -204,7 +204,7 @@ class FutureSpec extends JUnitSuite { def shouldFoldResultsByComposing { val actors = (1 to 10).toList map { _ ⇒ actorOf(new Actor { - def receive = { case (add: Int, wait: Int) ⇒ Thread.sleep(wait); self reply_? add } + def receive = { case (add: Int, wait: Int) ⇒ Thread.sleep(wait); self tryReply add } }).start() } def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) ⇒ actor.?((idx, idx * 200), 10000).mapTo[Int] } @@ -219,7 +219,7 @@ class FutureSpec extends JUnitSuite { case (add: Int, wait: Int) ⇒ Thread.sleep(wait) if (add == 6) throw new IllegalArgumentException("shouldFoldResultsWithException: expected") - self reply_? add + self tryReply add } }).start() } @@ -237,7 +237,7 @@ class FutureSpec extends JUnitSuite { def shouldReduceResults { val actors = (1 to 10).toList map { _ ⇒ actorOf(new Actor { - def receive = { case (add: Int, wait: Int) ⇒ Thread.sleep(wait); self reply_? add } + def receive = { case (add: Int, wait: Int) ⇒ Thread.sleep(wait); self tryReply add } }).start() } val timeout = 10000 @@ -253,7 +253,7 @@ class FutureSpec extends JUnitSuite { case (add: Int, wait: Int) ⇒ Thread.sleep(wait) if (add == 6) throw new IllegalArgumentException("shouldFoldResultsWithException: expected") - self reply_? add + self tryReply add } }).start() } diff --git a/akka-actor-tests/src/test/scala/akka/dispatch/PriorityDispatcherSpec.scala b/akka-actor-tests/src/test/scala/akka/dispatch/PriorityDispatcherSpec.scala index 5ddd9fa411..c2fbc2d09c 100644 --- a/akka-actor-tests/src/test/scala/akka/dispatch/PriorityDispatcherSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/dispatch/PriorityDispatcherSpec.scala @@ -33,7 +33,7 @@ class PriorityDispatcherSpec extends WordSpec with MustMatchers { def receive = { case i: Int ⇒ acc = i :: acc - case 'Result ⇒ self reply_? acc + case 'Result ⇒ self tryReply acc } }).start() diff --git a/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala b/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala index b6d7777a95..84c7c3ea4f 100644 --- a/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala @@ -192,7 +192,7 @@ class RoutingSpec extends WordSpec with MustMatchers { case _ ⇒ count.incrementAndGet latch.countDown() - self reply_? "success" + self tryReply "success" } }).start() @@ -241,7 +241,7 @@ class RoutingSpec extends WordSpec with MustMatchers { def receive = { case req: String ⇒ { sleepFor(10 millis) - self.reply_?("Response") + self.tryReply("Response") } } }) diff --git a/akka-actor-tests/src/test/scala/akka/ticket/Ticket703Spec.scala b/akka-actor-tests/src/test/scala/akka/ticket/Ticket703Spec.scala index fd9bc4d1f7..849070752b 100644 --- a/akka-actor-tests/src/test/scala/akka/ticket/Ticket703Spec.scala +++ b/akka-actor-tests/src/test/scala/akka/ticket/Ticket703Spec.scala @@ -24,7 +24,7 @@ class Ticket703Spec extends WordSpec with MustMatchers { def receive = { case req: String ⇒ Thread.sleep(6000L) - self.reply_?("Response") + self.tryReply("Response") } }) }).start() diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index 084ca12994..24fe2b373b 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -12,8 +12,6 @@ import akka.util._ import akka.serialization.{Serializer, Serialization} import ReflectiveAccess._ import ClusterModule._ -import DeploymentConfig.{TransactionLog ⇒ TransactionLogConfig, _} - import java.net.InetSocketAddress import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.{ScheduledFuture, ConcurrentHashMap, TimeUnit} @@ -23,6 +21,7 @@ import scala.reflect.BeanProperty import scala.collection.immutable.Stack import scala.annotation.tailrec import java.lang.IllegalStateException +import akka.actor.DeploymentConfig.ReplicationScheme private[akka] object ActorRefInternals { @@ -280,6 +279,7 @@ trait ActorRef extends ActorRefShared with ForwardableChannel with java.lang.Com *

* Throws an IllegalStateException if unable to determine what to reply to. */ + @deprecated("will be removed in 2.0, use reply instead", "1.2") def replyUnsafe(message: AnyRef) { reply(message) } @@ -291,7 +291,8 @@ trait ActorRef extends ActorRefShared with ForwardableChannel with java.lang.Com *

* Returns true if reply was sent, and false if unable to determine what to reply to. */ - def replySafe(message: AnyRef): Boolean = reply_?(message) + @deprecated("will be removed in 2.0, use tryReply instead", "1.2") + def replySafe(message: AnyRef): Boolean = tryReply(message) /** * Sets the dispatcher for this actor. Needs to be invoked before the actor is started. @@ -473,7 +474,7 @@ class LocalActorRef private[akka](private[this] val actorFactory: () ⇒ Actor, Serialization.serializerFor(this.getClass).fold(x ⇒ serializerErrorDueTo(x.toString), s ⇒ s) private lazy val replicationScheme: ReplicationScheme = - DeploymentConfig.replicationSchemeFor(Deployer.deploymentFor(address)).getOrElse(Transient) + DeploymentConfig.replicationSchemeFor(Deployer.deploymentFor(address)).getOrElse(DeploymentConfig.Transient) private lazy val isReplicated: Boolean = DeploymentConfig.isReplicated(replicationScheme) @@ -1230,19 +1231,26 @@ trait ScalaActorRef extends ActorRefShared with ForwardableChannel { /** * Use self.reply(..) to reply with a message to the original sender of the message currently - * being processed. + * being processed. This method fails if the original sender of the message could not be determined with an + * IllegalStateException. + * + * If you don't want deal with this IllegalStateException, but just a boolean, just use the tryReply(...) + * version. + * *

* Throws an IllegalStateException if unable to determine what to reply to. */ def reply(message: Any) = channel.!(message)(this) /** - * Use reply_?(..) to reply with a message to the original sender of the message currently - * being processed. + * Use tryReply(..) to try reply with a message to the original sender of the message currently + * being processed. This method *

* Returns true if reply was sent, and false if unable to determine what to reply to. + * + * If you would rather have an exception, check the reply(..) version. */ - def reply_?(message: Any): Boolean = channel.safe_!(message)(this) + def tryReply(message: Any): Boolean = channel.safe_!(message)(this) } case class SerializedActorRef(uuid: Uuid, diff --git a/akka-actor/src/main/scala/akka/routing/Pool.scala b/akka-actor/src/main/scala/akka/routing/Pool.scala index ef6db353a4..6398ef2241 100644 --- a/akka-actor/src/main/scala/akka/routing/Pool.scala +++ b/akka-actor/src/main/scala/akka/routing/Pool.scala @@ -123,7 +123,7 @@ trait DefaultActorPool extends ActorPool { this: Actor with ActorPoolSupervision protected def _route(): Receive = { // for testing... case Stat ⇒ - self reply_? Stats(_delegates length) + self tryReply Stats(_delegates length) case MaximumNumberOfRestartsWithinTimeRangeReached(victim, _, _, _) ⇒ _delegates = _delegates filterNot { _.uuid == victim.uuid } case Death(victim, _) => diff --git a/akka-camel/src/test/scala/akka/camel/ConsumerScalaTest.scala b/akka-camel/src/test/scala/akka/camel/ConsumerScalaTest.scala index 61909b0db0..a6a6971d98 100644 --- a/akka-camel/src/test/scala/akka/camel/ConsumerScalaTest.scala +++ b/akka-camel/src/test/scala/akka/camel/ConsumerScalaTest.scala @@ -252,11 +252,11 @@ object ConsumerScalaTest { } override def preRestart(reason: scala.Throwable) { - self.reply_?("pr") + self.tryReply("pr") } override def postStop { - self.reply_?("ps") + self.tryReply("ps") } } diff --git a/akka-docs/scala/actors.rst b/akka-docs/scala/actors.rst index 20ceda4285..96db03ac11 100644 --- a/akka-docs/scala/actors.rst +++ b/akka-docs/scala/actors.rst @@ -335,13 +335,13 @@ If you want to send a message back to the original sender of the message you jus In this case the ``result`` will be send back to the Actor that sent the ``request``. -The ``reply`` method throws an ``IllegalStateException`` if unable to determine what to reply to, e.g. the sender is not an actor. You can also use the more forgiving ``reply_?`` method which returns ``true`` if reply was sent, and ``false`` if unable to determine what to reply to. +The ``reply`` method throws an ``IllegalStateException`` if unable to determine what to reply to, e.g. the sender is not an actor. You can also use the more forgiving ``tryReply`` method which returns ``true`` if reply was sent, and ``false`` if unable to determine what to reply to. .. code-block:: scala case request => val result = process(request) - if (self.reply_?(result)) ...// success + if (self.tryReply(result)) ...// success else ... // handle failure Summary of reply semantics and options diff --git a/akka-docs/scala/fault-tolerance.rst b/akka-docs/scala/fault-tolerance.rst index c7ac83fd7e..b610bff96f 100644 --- a/akka-docs/scala/fault-tolerance.rst +++ b/akka-docs/scala/fault-tolerance.rst @@ -322,16 +322,16 @@ Supervised actors have the option to reply to the initial sender within preResta } override def preRestart(reason: scala.Throwable) { - self.reply_?(reason.getMessage) + self.tryReply(reason.getMessage) } override def postStop() { - self.reply_?("stopped by supervisor") + self.tryReply("stopped by supervisor") } } -- A reply within preRestart or postRestart must be a safe reply via `self.reply_?` because an unsafe self.reply will throw an exception when the actor is restarted without having failed. This can be the case in context of AllForOne restart strategies. -- A reply within postStop must be a safe reply via `self.reply_?` because an unsafe self.reply will throw an exception when the actor has been stopped by the application (and not by a supervisor) after successful execution of receive (or no execution at all). +- A reply within preRestart or postRestart must be a safe reply via `self.tryReply` because an unsafe self.reply will throw an exception when the actor is restarted without having failed. This can be the case in context of AllForOne restart strategies. +- A reply within postStop must be a safe reply via `self.tryReply` because an unsafe self.reply will throw an exception when the actor has been stopped by the application (and not by a supervisor) after successful execution of receive (or no execution at all). Handling too many actor restarts within a specific time limit ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/akka-stm/src/main/scala/akka/agent/Agent.scala b/akka-stm/src/main/scala/akka/agent/Agent.scala index fb525cc376..3a97263369 100644 --- a/akka-stm/src/main/scala/akka/agent/Agent.scala +++ b/akka-stm/src/main/scala/akka/agent/Agent.scala @@ -283,7 +283,7 @@ class AgentUpdater[T](agent: Agent[T]) extends Actor { def receive = { case update: Update[T] ⇒ - self.reply_?(atomic(txFactory) { agent.ref alter update.function }) + self.tryReply(atomic(txFactory) { agent.ref alter update.function }) case Get ⇒ self reply agent.get case _ ⇒ () } @@ -299,7 +299,7 @@ class ThreadBasedAgentUpdater[T](agent: Agent[T]) extends Actor { def receive = { case update: Update[T] ⇒ try { - self.reply_?(atomic(txFactory) { agent.ref alter update.function }) + self.tryReply(atomic(txFactory) { agent.ref alter update.function }) } finally { agent.resume self.stop() From 5635c9f76a5950d6231c40c3e705648d9a5f9158 Mon Sep 17 00:00:00 2001 From: Peter Veentjer Date: Mon, 18 Jul 2011 17:55:48 +0300 Subject: [PATCH 16/51] ticket 974 --- .../src/main/scala/akka/actor/Deployer.scala | 2 +- .../scala/akka/config/Configuration.scala | 19 ++++++++++++------- .../deployment/DeploymentMultiJvmNode1.conf | 2 +- .../deployment/DeploymentMultiJvmNode2.conf | 2 +- .../MigrationAutomaticMultiJvmNode1.conf | 2 +- .../MigrationAutomaticMultiJvmNode2.conf | 2 +- .../MigrationAutomaticMultiJvmNode3.conf | 2 +- ...LogWriteBehindNoSnapshotMultiJvmNode1.conf | 2 +- ...LogWriteBehindNoSnapshotMultiJvmNode2.conf | 2 +- ...onLogWriteBehindSnapshotMultiJvmNode1.conf | 2 +- ...onLogWriteBehindSnapshotMultiJvmNode2.conf | 2 +- ...LogWriteBehindNoSnapshotMultiJvmNode1.conf | 2 +- ...LogWriteBehindNoSnapshotMultiJvmNode2.conf | 2 +- ...ogWriteThroughNoSnapshotMultiJvmNode1.conf | 2 +- ...ogWriteThroughNoSnapshotMultiJvmNode2.conf | 2 +- ...nLogWriteThroughSnapshotMultiJvmNode1.conf | 2 +- ...nLogWriteThroughSnapshotMultiJvmNode2.conf | 2 +- .../BadAddressDirectRoutingMultiJvmNode1.conf | 2 +- ...ngleReplicaDirectRoutingMultiJvmNode1.conf | 2 +- .../homenode/HomeNodeMultiJvmNode1.conf | 2 +- .../homenode/HomeNodeMultiJvmNode2.conf | 2 +- .../RoundRobin1ReplicaMultiJvmNode1.conf | 2 +- .../RoundRobin2ReplicasMultiJvmNode1.conf | 2 +- .../RoundRobin2ReplicasMultiJvmNode2.conf | 2 +- .../RoundRobin3ReplicasMultiJvmNode1.conf | 2 +- .../RoundRobin3ReplicasMultiJvmNode2.conf | 2 +- .../RoundRobin3ReplicasMultiJvmNode3.conf | 2 +- .../RoundRobinFailoverMultiJvmNode1.conf | 2 +- .../RoundRobinFailoverMultiJvmNode2.conf | 2 +- .../RoundRobinFailoverMultiJvmNode3.conf | 2 +- .../RoundRobinFailoverMultiJvmNode4.conf | 2 +- config/akka-reference.conf | 2 +- 32 files changed, 43 insertions(+), 38 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/Deployer.scala b/akka-actor/src/main/scala/akka/actor/Deployer.scala index c754d1733d..cf4a015cd3 100644 --- a/akka-actor/src/main/scala/akka/actor/Deployer.scala +++ b/akka-actor/src/main/scala/akka/actor/Deployer.scala @@ -207,7 +207,7 @@ object Deployer { val replicas = { if (router == Direct) Replicate(1) else { - clusteredConfig.getAny("replicas", "0") match { + clusteredConfig.getAny("replication-factor", "0") match { case "auto" ⇒ AutoReplicate case "0" ⇒ NoReplicas case nrOfReplicas: String ⇒ diff --git a/akka-actor/src/main/scala/akka/config/Configuration.scala b/akka-actor/src/main/scala/akka/config/Configuration.scala index 8213d853eb..a683c14e42 100644 --- a/akka-actor/src/main/scala/akka/config/Configuration.scala +++ b/akka-actor/src/main/scala/akka/config/Configuration.scala @@ -64,7 +64,6 @@ class Configuration(val map: Map[String, Any]) { private def outputIfDesiredAndReturnInput[T](key: String, t: T): T = { if (Configuration.outputConfigSources) println("Akka config is using default value for: " + key) - t } @@ -149,10 +148,11 @@ class Configuration(val map: Map[String, Any]) { getDouble(key).getOrElse(outputIfDesiredAndReturnInput(key, defaultValue)) def getBoolean(key: String): Option[Boolean] = { - getString(key) flatMap { s ⇒ - val isTrue = trueValues.contains(s) - if (!isTrue && !falseValues.contains(s)) None - else Some(isTrue) + getString(key) flatMap { + s ⇒ + val isTrue = trueValues.contains(s) + if (!isTrue && !falseValues.contains(s)) None + else Some(isTrue) } } @@ -165,18 +165,23 @@ class Configuration(val map: Map[String, Any]) { getBoolean(key, defaultValue) def apply(key: String): String = getString(key) match { - case None ⇒ throw new ConfigurationException("undefined config: " + key) + case None ⇒ throw new ConfigurationException("undefined config: " + key) case Some(v) ⇒ v } def apply(key: String, defaultValue: String) = getString(key, defaultValue) + def apply(key: String, defaultValue: Int) = getInt(key, defaultValue) + def apply(key: String, defaultValue: Long) = getLong(key, defaultValue) + def apply(key: String, defaultValue: Boolean) = getBool(key, defaultValue) def getSection(name: String): Option[Configuration] = { val l = name.length + 1 - val m = map.collect { case (k, v) if k.startsWith(name) ⇒ (k.substring(l), v) } + val m = map.collect { + case (k, v) if k.startsWith(name) && !k.equals("replication-factor") ⇒ (k.substring(l), v) + } if (m.isEmpty) None else Some(new Configuration(m)) } diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/deployment/DeploymentMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/deployment/DeploymentMultiJvmNode1.conf index e23553c931..9c4b6e6c48 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/deployment/DeploymentMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/deployment/DeploymentMultiJvmNode1.conf @@ -1,4 +1,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" -akka.actor.deployment.service-hello.clustered.replicas = 1 +akka.actor.deployment.service-hello.clustered.replication-factor = 1 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/deployment/DeploymentMultiJvmNode2.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/deployment/DeploymentMultiJvmNode2.conf index e23553c931..9c4b6e6c48 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/deployment/DeploymentMultiJvmNode2.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/deployment/DeploymentMultiJvmNode2.conf @@ -1,4 +1,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" -akka.actor.deployment.service-hello.clustered.replicas = 1 +akka.actor.deployment.service-hello.clustered.replication-factor = 1 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode1.conf index a17a4d98ab..8308c61bfa 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode1.conf @@ -1,4 +1,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.hello-world.clustered.replication-factor = 1 \ No newline at end of file diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode2.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode2.conf index a17a4d98ab..8308c61bfa 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode2.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode2.conf @@ -1,4 +1,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.hello-world.clustered.replication-factor = 1 \ No newline at end of file diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode3.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode3.conf index a17a4d98ab..8308c61bfa 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode3.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/migration/automatic/MigrationAutomaticMultiJvmNode3.conf @@ -1,4 +1,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.hello-world.clustered.replication-factor = 1 \ No newline at end of file diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode1.conf index 8a5bd70eec..370167dcad 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode1.conf @@ -1,7 +1,7 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 +akka.actor.deployment.hello-world.clustered.replication-factor = 1 akka.actor.deployment.hello-world.clustered.replication.storage = "transaction-log" akka.actor.deployment.hello-world.clustered.replication.strategy = "write-behind" akka.cluster.replication.snapshot-frequency = 1000 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode2.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode2.conf index 8a5bd70eec..370167dcad 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode2.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode2.conf @@ -1,7 +1,7 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 +akka.actor.deployment.hello-world.clustered.replication-factor = 1 akka.actor.deployment.hello-world.clustered.replication.storage = "transaction-log" akka.actor.deployment.hello-world.clustered.replication.strategy = "write-behind" akka.cluster.replication.snapshot-frequency = 1000 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/snapshot/ReplicationTransactionLogWriteBehindSnapshotMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/snapshot/ReplicationTransactionLogWriteBehindSnapshotMultiJvmNode1.conf index 84969a04e5..97a0fb3687 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/snapshot/ReplicationTransactionLogWriteBehindSnapshotMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/snapshot/ReplicationTransactionLogWriteBehindSnapshotMultiJvmNode1.conf @@ -1,7 +1,7 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 +akka.actor.deployment.hello-world.clustered.replication-factor = 1 akka.actor.deployment.hello-world.clustered.replication.storage = "transaction-log" akka.actor.deployment.hello-world.clustered.replication.strategy = "write-behind" akka.cluster.replication.snapshot-frequency = 7 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/snapshot/ReplicationTransactionLogWriteBehindSnapshotMultiJvmNode2.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/snapshot/ReplicationTransactionLogWriteBehindSnapshotMultiJvmNode2.conf index 84969a04e5..97a0fb3687 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/snapshot/ReplicationTransactionLogWriteBehindSnapshotMultiJvmNode2.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writebehind/snapshot/ReplicationTransactionLogWriteBehindSnapshotMultiJvmNode2.conf @@ -1,7 +1,7 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 +akka.actor.deployment.hello-world.clustered.replication-factor = 1 akka.actor.deployment.hello-world.clustered.replication.storage = "transaction-log" akka.actor.deployment.hello-world.clustered.replication.strategy = "write-behind" akka.cluster.replication.snapshot-frequency = 7 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode1.conf index 211cdbd6ee..42e57847b5 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode1.conf @@ -1,7 +1,7 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 +akka.actor.deployment.hello-world.clustered.replication-factor = 1 akka.actor.deployment.hello-world.clustered.replication.storage = "transaction-log" akka.actor.deployment.hello-world.clustered.replication.strategy = "write-through" diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode2.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode2.conf index 567b03b9cb..cc2fb1ef3b 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode2.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteBehindNoSnapshotMultiJvmNode2.conf @@ -1,7 +1,7 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 +akka.actor.deployment.hello-world.clustered.replication-factor = 1 akka.actor.deployment.hello-world.clustered.replication.storage = "transaction-log" akka.actor.deployment.hello-world.clustered.replication.strategy = "write-through" akka.cluster.replication.snapshot-frequency = 1000 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteThroughNoSnapshotMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteThroughNoSnapshotMultiJvmNode1.conf index 211cdbd6ee..42e57847b5 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteThroughNoSnapshotMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteThroughNoSnapshotMultiJvmNode1.conf @@ -1,7 +1,7 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 +akka.actor.deployment.hello-world.clustered.replication-factor = 1 akka.actor.deployment.hello-world.clustered.replication.storage = "transaction-log" akka.actor.deployment.hello-world.clustered.replication.strategy = "write-through" diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteThroughNoSnapshotMultiJvmNode2.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteThroughNoSnapshotMultiJvmNode2.conf index 567b03b9cb..cc2fb1ef3b 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteThroughNoSnapshotMultiJvmNode2.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/nosnapshot/ReplicationTransactionLogWriteThroughNoSnapshotMultiJvmNode2.conf @@ -1,7 +1,7 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 +akka.actor.deployment.hello-world.clustered.replication-factor = 1 akka.actor.deployment.hello-world.clustered.replication.storage = "transaction-log" akka.actor.deployment.hello-world.clustered.replication.strategy = "write-through" akka.cluster.replication.snapshot-frequency = 1000 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/snapshot/ReplicationTransactionLogWriteThroughSnapshotMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/snapshot/ReplicationTransactionLogWriteThroughSnapshotMultiJvmNode1.conf index 58c66d3e42..c38191ce28 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/snapshot/ReplicationTransactionLogWriteThroughSnapshotMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/snapshot/ReplicationTransactionLogWriteThroughSnapshotMultiJvmNode1.conf @@ -1,7 +1,7 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 +akka.actor.deployment.hello-world.clustered.replication-factor = 1 akka.actor.deployment.hello-world.clustered.replication.storage = "transaction-log" akka.actor.deployment.hello-world.clustered.replication.strategy = "write-through" akka.cluster.replication.snapshot-frequency = 7 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/snapshot/ReplicationTransactionLogWriteThroughSnapshotMultiJvmNode2.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/snapshot/ReplicationTransactionLogWriteThroughSnapshotMultiJvmNode2.conf index 58c66d3e42..c38191ce28 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/snapshot/ReplicationTransactionLogWriteThroughSnapshotMultiJvmNode2.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/replication/transactionlog/writethrough/snapshot/ReplicationTransactionLogWriteThroughSnapshotMultiJvmNode2.conf @@ -1,7 +1,7 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.hello-world.router = "direct" -akka.actor.deployment.hello-world.clustered.replicas = 1 +akka.actor.deployment.hello-world.clustered.replication-factor = 1 akka.actor.deployment.hello-world.clustered.replication.storage = "transaction-log" akka.actor.deployment.hello-world.clustered.replication.strategy = "write-through" akka.cluster.replication.snapshot-frequency = 7 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/direct/bad_address/BadAddressDirectRoutingMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/direct/bad_address/BadAddressDirectRoutingMultiJvmNode1.conf index 1345a2287c..e12f87e912 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/direct/bad_address/BadAddressDirectRoutingMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/direct/bad_address/BadAddressDirectRoutingMultiJvmNode1.conf @@ -2,4 +2,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" akka.actor.deployment.service-hello.clustered.home = "node:node1" -akka.actor.deployment.service-hello.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.service-hello.clustered.replication-factor = 1 \ No newline at end of file diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/direct/single_replica/SingleReplicaDirectRoutingMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/direct/single_replica/SingleReplicaDirectRoutingMultiJvmNode1.conf index 2a3d9ba765..0a47105d03 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/direct/single_replica/SingleReplicaDirectRoutingMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/direct/single_replica/SingleReplicaDirectRoutingMultiJvmNode1.conf @@ -1,4 +1,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "direct" -akka.actor.deployment.service-hello.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.service-hello.clustered.replication-factor = 1 \ No newline at end of file diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/homenode/HomeNodeMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/homenode/HomeNodeMultiJvmNode1.conf index d7e17c84d8..366cf9111c 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/homenode/HomeNodeMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/homenode/HomeNodeMultiJvmNode1.conf @@ -2,4 +2,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" akka.actor.deployment.service-hello.clustered.preferred-nodes = ["node:node1"] -akka.actor.deployment.service-hello.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.service-hello.clustered.replication-factor = 1 \ No newline at end of file diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/homenode/HomeNodeMultiJvmNode2.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/homenode/HomeNodeMultiJvmNode2.conf index d7e17c84d8..366cf9111c 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/homenode/HomeNodeMultiJvmNode2.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/homenode/HomeNodeMultiJvmNode2.conf @@ -2,4 +2,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" akka.actor.deployment.service-hello.clustered.preferred-nodes = ["node:node1"] -akka.actor.deployment.service-hello.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.service-hello.clustered.replication-factor = 1 \ No newline at end of file diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_1_replica/RoundRobin1ReplicaMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_1_replica/RoundRobin1ReplicaMultiJvmNode1.conf index dcbd276918..0fb82878ea 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_1_replica/RoundRobin1ReplicaMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_1_replica/RoundRobin1ReplicaMultiJvmNode1.conf @@ -1,4 +1,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" -akka.actor.deployment.service-hello.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.service-hello.clustered.replication-factor = 1 \ No newline at end of file diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_2_replicas/RoundRobin2ReplicasMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_2_replicas/RoundRobin2ReplicasMultiJvmNode1.conf index 09f4cfc93a..f4a6f8868c 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_2_replicas/RoundRobin2ReplicasMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_2_replicas/RoundRobin2ReplicasMultiJvmNode1.conf @@ -2,4 +2,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" akka.actor.deployment.service-hello.clustered.preferred-nodes = ["node:node1","node:node2"] -akka.actor.deployment.service-hello.clustered.replicas = 2 +akka.actor.deployment.service-hello.clustered.replication-factor = 2 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_2_replicas/RoundRobin2ReplicasMultiJvmNode2.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_2_replicas/RoundRobin2ReplicasMultiJvmNode2.conf index 09f4cfc93a..f4a6f8868c 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_2_replicas/RoundRobin2ReplicasMultiJvmNode2.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_2_replicas/RoundRobin2ReplicasMultiJvmNode2.conf @@ -2,4 +2,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" akka.actor.deployment.service-hello.clustered.preferred-nodes = ["node:node1","node:node2"] -akka.actor.deployment.service-hello.clustered.replicas = 2 +akka.actor.deployment.service-hello.clustered.replication-factor = 2 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode1.conf index 75249c7713..2217a81073 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode1.conf @@ -1,4 +1,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" -akka.actor.deployment.service-hello.clustered.replicas = 3 +akka.actor.deployment.service-hello.clustered.replication-factor = 3 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode2.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode2.conf index 75249c7713..4be28d60a2 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode2.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode2.conf @@ -1,4 +1,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" -akka.actor.deployment.service-hello.clustered.replicas = 3 +akka.actor.deployment.service-hello.clustered.repliction-factor = 3 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode3.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode3.conf index 75249c7713..2217a81073 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode3.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_3_replicas/RoundRobin3ReplicasMultiJvmNode3.conf @@ -1,4 +1,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" -akka.actor.deployment.service-hello.clustered.replicas = 3 +akka.actor.deployment.service-hello.clustered.replication-factor = 3 diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode1.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode1.conf index d7e17c84d8..366cf9111c 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode1.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode1.conf @@ -2,4 +2,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" akka.actor.deployment.service-hello.clustered.preferred-nodes = ["node:node1"] -akka.actor.deployment.service-hello.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.service-hello.clustered.replication-factor = 1 \ No newline at end of file diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode2.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode2.conf index d7e17c84d8..366cf9111c 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode2.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode2.conf @@ -2,4 +2,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" akka.actor.deployment.service-hello.clustered.preferred-nodes = ["node:node1"] -akka.actor.deployment.service-hello.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.service-hello.clustered.replication-factor = 1 \ No newline at end of file diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode3.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode3.conf index d7e17c84d8..366cf9111c 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode3.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode3.conf @@ -2,4 +2,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" akka.actor.deployment.service-hello.clustered.preferred-nodes = ["node:node1"] -akka.actor.deployment.service-hello.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.service-hello.clustered.replication-factor = 1 \ No newline at end of file diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode4.conf b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode4.conf index d7e17c84d8..366cf9111c 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode4.conf +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/roundrobin_failover/RoundRobinFailoverMultiJvmNode4.conf @@ -2,4 +2,4 @@ akka.enabled-modules = ["cluster"] akka.event-handler-level = "WARNING" akka.actor.deployment.service-hello.router = "round-robin" akka.actor.deployment.service-hello.clustered.preferred-nodes = ["node:node1"] -akka.actor.deployment.service-hello.clustered.replicas = 1 \ No newline at end of file +akka.actor.deployment.service-hello.clustered.replication-factor = 1 \ No newline at end of file diff --git a/config/akka-reference.conf b/config/akka-reference.conf index eb8b8262c0..028866b37c 100644 --- a/config/akka-reference.conf +++ b/config/akka-reference.conf @@ -55,7 +55,7 @@ akka { # available: "host:", "ip:" and "node:" # default is "host:localhost" - replicas = 3 # number of actor instances in the cluster + replication-factor = 3 # number of actor instances in the cluster # available: positive integer (0-N) or the string "auto" for auto-scaling # if "auto" is used then 'home' has no meaning # default is '0', meaning no replicas; From a145e0773cafee3825eaece65065238dd15c4c68 Mon Sep 17 00:00:00 2001 From: Peter Veentjer Date: Mon, 18 Jul 2011 18:18:55 +0300 Subject: [PATCH 17/51] ticket 974, part 2 --- .../scala/akka/actor/actor/DeployerSpec.scala | 2 +- .../src/main/scala/akka/actor/Actor.scala | 2 +- .../src/main/scala/akka/actor/Deployer.scala | 14 +++++------ .../scala/akka/actor/DeploymentConfig.scala | 23 ++++++------------- 4 files changed, 16 insertions(+), 25 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/DeployerSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/DeployerSpec.scala index 3ae5ea2397..e35d358492 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/actor/DeployerSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/DeployerSpec.scala @@ -20,7 +20,7 @@ class DeployerSpec extends WordSpec with MustMatchers { LeastCPU, Clustered( Vector(Node("node1")), - Replicate(3), + ReplicationFactor(3), Replication( TransactionLog, WriteThrough))))) diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index 27095a580e..02906471a3 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -462,7 +462,7 @@ object Actor extends ListenerManagement { "Remote server is not running") val isHomeNode = DeploymentConfig.isHomeNode(preferredHomeNodes) - val nrOfReplicas = DeploymentConfig.replicaValueFor(replicas) + val nrOfReplicas = replicas.factor def serializerErrorDueTo(reason: String) = throw new akka.config.ConfigurationException( "Could not create Serializer for actor [" + address + "] due to: " + reason) diff --git a/akka-actor/src/main/scala/akka/actor/Deployer.scala b/akka-actor/src/main/scala/akka/actor/Deployer.scala index cf4a015cd3..91f27204d7 100644 --- a/akka-actor/src/main/scala/akka/actor/Deployer.scala +++ b/akka-actor/src/main/scala/akka/actor/Deployer.scala @@ -204,15 +204,15 @@ object Deployer { // -------------------------------- // akka.actor.deployment.

.clustered.replicas // -------------------------------- - val replicas = { - if (router == Direct) Replicate(1) + val replicationFactor = { + if (router == Direct) ReplicationFactor(1) else { clusteredConfig.getAny("replication-factor", "0") match { - case "auto" ⇒ AutoReplicate - case "0" ⇒ NoReplicas + case "auto" ⇒ AutoReplicationFactor + case "0" ⇒ ZeroReplicationFactor case nrOfReplicas: String ⇒ try { - Replicate(nrOfReplicas.toInt) + ReplicationFactor(nrOfReplicas.toInt) } catch { case e: NumberFormatException ⇒ throw new ConfigurationException( @@ -229,7 +229,7 @@ object Deployer { // -------------------------------- clusteredConfig.getSection("replication") match { case None ⇒ - Some(Deploy(address, router, Clustered(preferredNodes, replicas, Transient))) + Some(Deploy(address, router, Clustered(preferredNodes, replicationFactor, Transient))) case Some(replicationConfig) ⇒ val storage = replicationConfig.getString("storage", "transaction-log") match { @@ -248,7 +248,7 @@ object Deployer { ".clustered.replication.strategy] needs to be either [\"write-through\"] or [\"write-behind\"] - was [" + unknown + "]") } - Some(Deploy(address, router, Clustered(preferredNodes, replicas, Replication(storage, strategy)))) + Some(Deploy(address, router, Clustered(preferredNodes, replicationFactor, Replication(storage, strategy)))) } } } diff --git a/akka-actor/src/main/scala/akka/actor/DeploymentConfig.scala b/akka-actor/src/main/scala/akka/actor/DeploymentConfig.scala index bc058e87f0..fc21fc7a23 100644 --- a/akka-actor/src/main/scala/akka/actor/DeploymentConfig.scala +++ b/akka-actor/src/main/scala/akka/actor/DeploymentConfig.scala @@ -53,7 +53,7 @@ object DeploymentConfig { sealed trait Scope case class Clustered( preferredNodes: Iterable[Home] = Vector(Host("localhost")), - replicas: Replicas = NoReplicas, + replicas: ReplicationFactor = ZeroReplicationFactor, replication: ReplicationScheme = Transient) extends Scope // For Java API @@ -73,18 +73,17 @@ object DeploymentConfig { // -------------------------------- // --- Replicas // -------------------------------- - sealed trait Replicas - case class Replicate(factor: Int) extends Replicas { - if (factor < 1) throw new IllegalArgumentException("Replicas factor can not be negative or zero") + sealed case class ReplicationFactor(val factor: Int) { + if (factor < 0) throw new IllegalArgumentException("replication-factor can not be negative") } // For Java API - case class AutoReplicate() extends Replicas - case class NoReplicas() extends Replicas + case class AutoReplicationFactor() extends ReplicationFactor(-1) + case class ZeroReplicationFactor() extends ReplicationFactor(0) // For Scala API - case object AutoReplicate extends Replicas - case object NoReplicas extends Replicas + case object AutoReplicationFactor extends ReplicationFactor(-1) + case object ZeroReplicationFactor extends ReplicationFactor(0) // -------------------------------- // --- Replication @@ -141,14 +140,6 @@ object DeploymentConfig { def isHomeNode(homes: Iterable[Home]): Boolean = homes exists (home ⇒ nodeNameFor(home) == Config.nodename) - def replicaValueFor(replicas: Replicas): Int = replicas match { - case Replicate(replicas) ⇒ replicas - case AutoReplicate ⇒ -1 - case AutoReplicate() ⇒ -1 - case NoReplicas ⇒ 0 - case NoReplicas() ⇒ 0 - } - def routerTypeFor(routing: Routing): RouterType = routing match { case Direct ⇒ RouterType.Direct case Direct() ⇒ RouterType.Direct From e06983e989134915b16b9855e47302138a762045 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 19 Jul 2011 14:20:18 +0200 Subject: [PATCH 18/51] Optimizing serialization of TypedActor messages by adding an identifier to all Serializers so they can be fetched through that at the other end --- .../main/scala/akka/testing/Serializers.scala | 6 +++ .../akka/actor/actor/TypedActorSpec.scala | 9 +++- .../src/main/scala/akka/actor/Actor.scala | 5 +- .../src/main/scala/akka/actor/ActorRef.scala | 2 +- .../main/scala/akka/actor/TypedActor.scala | 34 ++++++------ .../scala/akka/serialization/Format.scala | 3 ++ .../akka/serialization/Serialization.scala | 53 +++++++++++-------- .../scala/akka/serialization/Serializer.scala | 27 ++++++++-- 8 files changed, 89 insertions(+), 50 deletions(-) diff --git a/akka-actor-tests/src/main/scala/akka/testing/Serializers.scala b/akka-actor-tests/src/main/scala/akka/testing/Serializers.scala index b3836bc201..6412619963 100644 --- a/akka-actor-tests/src/main/scala/akka/testing/Serializers.scala +++ b/akka-actor-tests/src/main/scala/akka/testing/Serializers.scala @@ -14,6 +14,8 @@ import sjson.json._ class ProtobufSerializer extends Serializer { val ARRAY_OF_BYTE_ARRAY = Array[Class[_]](classOf[Array[Byte]]) + def identifier = 2:Byte + def toBinary(obj: AnyRef): Array[Byte] = { if (!obj.isInstanceOf[Message]) throw new IllegalArgumentException( "Can't serialize a non-protobuf message using protobuf [" + obj + "]") @@ -31,6 +33,8 @@ object ProtobufSerializer extends ProtobufSerializer class JavaJSONSerializer extends Serializer { private val mapper = new ObjectMapper + def identifier = 3:Byte + def toBinary(obj: AnyRef): Array[Byte] = { val bos = new ByteArrayOutputStream val out = new ObjectOutputStream(bos) @@ -54,6 +58,8 @@ object JavaJSONSerializer extends JavaJSONSerializer class SJSONSerializer extends Serializer { + def identifier = 4:Byte + def toBinary(obj: AnyRef): Array[Byte] = sjson.json.Serializer.SJSON.out(obj) diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/TypedActorSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/TypedActorSpec.scala index 31c1e5fbc5..7c09de930e 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/actor/TypedActorSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/TypedActorSpec.scala @@ -39,6 +39,8 @@ object TypedActorSpec { def incr() def read(): Int + + def testMethodCallSerialization(foo: Foo, s: String, i: Int): Unit = throw new IllegalStateException("expected") } class Bar extends Foo with Serializable { @@ -307,7 +309,7 @@ class TypedActorSpec extends WordSpec with MustMatchers with BeforeAndAfterEach "be able to serialize and deserialize invocations' parameters" in { import java.io._ val someFoo: Foo = new Bar - val m = MethodCall(classOf[Foo].getDeclaredMethod("futureComposePigdogFrom", Array[Class[_]](classOf[Foo]): _*), Array[AnyRef](someFoo)) + val m = MethodCall(classOf[Foo].getDeclaredMethod("testMethodCallSerialization", Array[Class[_]](classOf[Foo], classOf[String], classOf[Int]): _*), Array[AnyRef](someFoo, null, 1.asInstanceOf[AnyRef])) val baos = new ByteArrayOutputStream(8192 * 4) val out = new ObjectOutputStream(baos) @@ -319,9 +321,12 @@ class TypedActorSpec extends WordSpec with MustMatchers with BeforeAndAfterEach val mNew = in.readObject().asInstanceOf[MethodCall] mNew.method must be(m.method) - mNew.parameters must have size 1 + mNew.parameters must have size 3 mNew.parameters(0) must not be null mNew.parameters(0).getClass must be === classOf[Bar] + mNew.parameters(1) must be(null) + mNew.parameters(2) must not be null + mNew.parameters(2).asInstanceOf[Int] must be === 1 } } } diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index 02906471a3..d5b83b0960 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -464,11 +464,8 @@ object Actor extends ListenerManagement { val isHomeNode = DeploymentConfig.isHomeNode(preferredHomeNodes) val nrOfReplicas = replicas.factor - def serializerErrorDueTo(reason: String) = throw new akka.config.ConfigurationException( - "Could not create Serializer for actor [" + address + "] due to: " + reason) - val serializer: Serializer = - Serialization.serializerFor(this.getClass).fold(x ⇒ serializerErrorDueTo(x.toString), s ⇒ s) + Serialization.serializerFor(this.getClass) def storeActorAndGetClusterRef(replicationScheme: ReplicationScheme, serializer: Serializer): ActorRef = { // add actor to cluster registry (if not already added) diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index 24fe2b373b..efdf9dc269 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -471,7 +471,7 @@ class LocalActorRef private[akka](private[this] val actorFactory: () ⇒ Actor, "]") private val serializer: Serializer = - Serialization.serializerFor(this.getClass).fold(x ⇒ serializerErrorDueTo(x.toString), s ⇒ s) + try { Serialization.serializerFor(this.getClass) } catch { case e: Exception => serializerErrorDueTo(e.toString)} private lazy val replicationScheme: ReplicationScheme = DeploymentConfig.replicationSchemeFor(Deployer.deploymentFor(address)).getOrElse(DeploymentConfig.Transient) diff --git a/akka-actor/src/main/scala/akka/actor/TypedActor.scala b/akka-actor/src/main/scala/akka/actor/TypedActor.scala index 1511419184..9ffff54456 100644 --- a/akka-actor/src/main/scala/akka/actor/TypedActor.scala +++ b/akka-actor/src/main/scala/akka/actor/TypedActor.scala @@ -10,8 +10,8 @@ import akka.dispatch.{ MessageDispatcher, Dispatchers, Future, FutureTimeoutExce import java.lang.reflect.{ InvocationTargetException, Method, InvocationHandler, Proxy } import akka.util.{ Duration } import java.util.concurrent.atomic.{ AtomicReference ⇒ AtomVar } -import akka.serialization.Serialization import com.sun.xml.internal.ws.developer.MemberSubmissionAddressing.Validation +import akka.serialization.{Serializer, Serialization} //TODO Document this class, not only in Scaladoc, but also in a dedicated typed-actor.rst, for both java and scala /** @@ -89,33 +89,35 @@ object TypedActor { } } catch { case i: InvocationTargetException ⇒ throw i.getTargetException } - private def writeReplace(): AnyRef = { - val serializedParameters: Array[(Array[Byte],String)] = parameters match { - case null => null - case a if a.length == 0 => Array[(Array[Byte],String)]() - case a => a.map( { - case null => null - case value => Serialization.serializerFor(value.getClass).fold(throw _, s => (s.toBinary(value), s.getClass.getName)) - }) - } - new SerializedMethodCall(method.getDeclaringClass, method.getName, method.getParameterTypes, serializedParameters) + private def writeReplace(): AnyRef = parameters match { + case null => SerializedMethodCall(method.getDeclaringClass, method.getName, method.getParameterTypes, null, null) + case ps if ps.length == 0 => SerializedMethodCall(method.getDeclaringClass, method.getName, method.getParameterTypes, Array[Serializer.Identifier](), Array[Array[Byte]]()) + case ps => + val serializers: Array[Serializer] = ps map Serialization.findSerializerFor + val serializedParameters: Array[Array[Byte]] = Array.ofDim[Array[Byte]](serializers.length) + for(i <- 0 until serializers.length) + serializedParameters(i) = serializers(i) toBinary parameters(i) //Mutable for the sake of sanity + + SerializedMethodCall(method.getDeclaringClass, method.getName, method.getParameterTypes, serializers.map(_.identifier), serializedParameters) } } /** * Represents the serialized form of a MethodCall, uses readResolve and writeReplace to marshall the call */ - case class SerializedMethodCall(ownerType: Class[_], methodName: String, parameterTypes: Array[Class[_]], serializedParameters: Array[(Array[Byte],String)]) { + case class SerializedMethodCall(ownerType: Class[_], methodName: String, parameterTypes: Array[Class[_]], serializerIdentifiers: Array[Serializer.Identifier], serializedParameters: Array[Array[Byte]]) { //TODO implement writeObject and readObject to serialize //TODO Possible optimization is to special encode the parameter-types to conserve space private def readResolve(): AnyRef = { MethodCall(ownerType.getDeclaredMethod(methodName, parameterTypes: _*), serializedParameters match { case null => null case a if a.length == 0 => Array[AnyRef]() - case a => a.map( { - case null => null - case (bytes, serializerFQN) => Serialization.serializerOf(serializerFQN).fold(throw _, _.fromBinary(bytes)) - }) + case a => + val deserializedParameters: Array[AnyRef] = Array.ofDim[AnyRef](a.length) //Mutable for the sake of sanity + for(i <- 0 until a.length) + deserializedParameters(i) = Serialization.serializerByIdentity(serializerIdentifiers(i)).fromBinary(serializedParameters(i)) + + deserializedParameters }) } } diff --git a/akka-actor/src/main/scala/akka/serialization/Format.scala b/akka-actor/src/main/scala/akka/serialization/Format.scala index 85dc0abec0..d53a852379 100644 --- a/akka-actor/src/main/scala/akka/serialization/Format.scala +++ b/akka-actor/src/main/scala/akka/serialization/Format.scala @@ -43,6 +43,9 @@ import java.io.{ ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, B * in.close() * obj * } + * + * def identifier: Byte = 111 //Pick a number and hope no one has chosen the same :-) 0 - 16 is reserved for Akka internals + * * } * * val defaultSerializerName = Default.getClass.getName diff --git a/akka-actor/src/main/scala/akka/serialization/Serialization.scala b/akka-actor/src/main/scala/akka/serialization/Serialization.scala index 49dd527be6..e065bbc24c 100644 --- a/akka-actor/src/main/scala/akka/serialization/Serialization.scala +++ b/akka-actor/src/main/scala/akka/serialization/Serialization.scala @@ -19,27 +19,26 @@ case class NoSerializerFoundException(m: String) extends AkkaException(m) * locating a Serializer for a particular class as defined in the mapping in the 'akka.conf' file. */ object Serialization { + //TODO document me - def serialize(o: AnyRef): Either[Exception, Array[Byte]] = serializerFor(o.getClass) match { - case Left(ex) ⇒ Left(ex) - case Right(serializer) ⇒ Right(serializer.toBinary(o)) - } + def serialize(o: AnyRef): Either[Exception, Array[Byte]] = + try { Right(findSerializerFor(o).toBinary(o)) } catch { case e: Exception => Left(e) } + //TODO document me def deserialize( bytes: Array[Byte], clazz: Class[_], classLoader: Option[ClassLoader]): Either[Exception, AnyRef] = - serializerFor(clazz) match { - case Left(e) ⇒ Left(e) - case Right(serializer) ⇒ Right(serializer.fromBinary(bytes, Some(clazz), classLoader)) - } + try { Right(serializerFor(clazz).fromBinary(bytes, Some(clazz), classLoader)) } catch { case e: Exception => Left(e) } + + def findSerializerFor(o: AnyRef): Serializer = o match { + case null => NullSerializer + case other => serializerFor(other.getClass) + } + //TODO document me - //TODO memoize the lookups - def serializerFor(clazz: Class[_]): Either[Exception, Serializer] = //TODO fall back on BestMatchClass THEN default - getClassFor(serializerMap.get(clazz.getName).getOrElse(serializers("default"))) match { - case Right(serializer) ⇒ Right(serializer.newInstance.asInstanceOf[Serializer]) - case Left(e) => Left(e) - } + def serializerFor(clazz: Class[_]): Serializer = //TODO fall back on BestMatchClass THEN default AND memoize the lookups + serializerMap.get(clazz.getName).getOrElse(serializers("default")) /** * Tries to load the specified Serializer by the FQN @@ -64,16 +63,18 @@ object Serialization { } /** - * A Map of serializer from alias to implementation (FQN of a class implementing akka.serialization.Serializer) - * By default always contains the following mapping: "default" -> "akka.serialization.JavaSerializer" + * A Map of serializer from alias to implementation (class implementing akka.serialization.Serializer) + * By default always contains the following mapping: "default" -> akka.serialization.JavaSerializer * But "default" can be overridden in config */ - val serializers: Map[String, String] = config.getSection("akka.actor.serializers") map { - _.map.foldLeft(Map("default" -> "akka.serialization.JavaSerializer")) { - case (result, (k: String, v: String)) => result + (k -> v) - case (result, _) => result - } - } getOrElse Map("default" -> "akka.serialization.JavaSerializer") + val serializers: Map[String, Serializer] = + config.getSection("akka.actor.serializers") + .map(_.map) + .getOrElse(Map()) + .foldLeft(Map[String, Serializer]("default" -> akka.serialization.JavaSerializer)) { + case (result, (k: String, v: String)) => result + (k -> serializerOf(v).fold(throw _, identity)) + case (result, _) => result + } /** * bindings is a Map whose keys = FQN of class that is serializable and values = the alias of the serializer to be used @@ -88,5 +89,11 @@ object Serialization { /** * serializerMap is a Map whose keys = FQN of class that is serializable and values = the FQN of the serializer to be used for that class */ - val serializerMap: Map[String, String] = bindings mapValues serializers + val serializerMap: Map[String, Serializer] = bindings mapValues serializers + + /** + * Maps from a Serializer.Identifier (Byte) to a Serializer instance (optimization) + */ + val serializerByIdentity: Map[Serializer.Identifier, Serializer] = + Map(NullSerializer.identifier -> NullSerializer) ++ serializers map { case (_, v) => (v.identifier,v) } } diff --git a/akka-actor/src/main/scala/akka/serialization/Serializer.scala b/akka-actor/src/main/scala/akka/serialization/Serializer.scala index e79b2bcd37..835cf9fa7a 100644 --- a/akka-actor/src/main/scala/akka/serialization/Serializer.scala +++ b/akka-actor/src/main/scala/akka/serialization/Serializer.scala @@ -6,14 +6,29 @@ package akka.serialization import java.io.{ ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, ByteArrayInputStream } import akka.util.ClassLoaderObjectInputStream -import akka.actor.ActorRef + +object Serializer { + val defaultSerializerName = JavaSerializer.getClass.getName + type Identifier = Byte +} trait Serializer extends scala.Serializable { + /** + * Completely unique Byte value to identify this implementation of Serializer, used to optimize network traffic + * Values from 0 to 16 is reserved for Akka internal usage + */ + def identifier: Serializer.Identifier def toBinary(o: AnyRef): Array[Byte] def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]] = None, classLoader: Option[ClassLoader] = None): AnyRef } +object JavaSerializer extends JavaSerializer +object NullSerializer extends NullSerializer + class JavaSerializer extends Serializer { + + def identifier = 1:Byte + def toBinary(o: AnyRef): Array[Byte] = { val bos = new ByteArrayOutputStream val out = new ObjectOutputStream(bos) @@ -33,7 +48,11 @@ class JavaSerializer extends Serializer { } } -object JavaSerializer extends JavaSerializer -object Serializer { - val defaultSerializerName = JavaSerializer.getClass.getName +class NullSerializer extends Serializer { + + val nullAsBytes = Array[Byte]() + + def identifier = 0:Byte + def toBinary(o: AnyRef) = nullAsBytes + def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]] = None, classLoader: Option[ClassLoader] = None): AnyRef = null } From e9f4c3ea46bae3d1f43448e38418b68ded723004 Mon Sep 17 00:00:00 2001 From: Peter Veentjer Date: Tue, 19 Jul 2011 16:06:29 +0300 Subject: [PATCH 19/51] ticket 974: Fix of the ambiguity problem in the Configuration.scala --- akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala | 1 + akka-actor/src/main/scala/akka/config/Configuration.scala | 3 ++- config/akka-reference.conf | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala b/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala index e7234509d7..37545a6181 100644 --- a/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala @@ -36,6 +36,7 @@ class ConfigSpec extends WordSpec with MustMatchers { getInt("akka.actor.timeout") must equal(Some(5)) getInt("akka.actor.throughput") must equal(Some(5)) getInt("akka.actor.throughput-deadline-time") must equal(Some(-1)) + getInt("akka.actor.deployment.service-ping.clustered.replication-factor") must equal(Some(3)) getString("akka.cluster.layer") must equal(Some("akka.remote.netty.NettyRemoteSupport")) getInt("akka.cluster.server.port") must equal(Some(2552)) diff --git a/akka-actor/src/main/scala/akka/config/Configuration.scala b/akka-actor/src/main/scala/akka/config/Configuration.scala index a683c14e42..b32c4eeb72 100644 --- a/akka-actor/src/main/scala/akka/config/Configuration.scala +++ b/akka-actor/src/main/scala/akka/config/Configuration.scala @@ -179,8 +179,9 @@ class Configuration(val map: Map[String, Any]) { def getSection(name: String): Option[Configuration] = { val l = name.length + 1 + val pattern = name+"." val m = map.collect { - case (k, v) if k.startsWith(name) && !k.equals("replication-factor") ⇒ (k.substring(l), v) + case (k, v) if k.startsWith(pattern) ⇒ (k.substring(l), v) } if (m.isEmpty) None else Some(new Configuration(m)) diff --git a/config/akka-reference.conf b/config/akka-reference.conf index 028866b37c..218a824220 100644 --- a/config/akka-reference.conf +++ b/config/akka-reference.conf @@ -55,7 +55,7 @@ akka { # available: "host:", "ip:" and "node:" # default is "host:localhost" - replication-factor = 3 # number of actor instances in the cluster + replication-factor = 3 # number of actor instances in the cluster # available: positive integer (0-N) or the string "auto" for auto-scaling # if "auto" is used then 'home' has no meaning # default is '0', meaning no replicas; From 4e6dd9e74e13aba812299502e0d092f6360a2565 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 19 Jul 2011 15:30:35 +0200 Subject: [PATCH 20/51] The Unb0rkening --- .../cluster/api/registry/RegistryStoreMultiJvmSpec.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/api/registry/RegistryStoreMultiJvmSpec.scala b/akka-cluster/src/multi-jvm/scala/akka/cluster/api/registry/RegistryStoreMultiJvmSpec.scala index ae0eadd97f..349626445c 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/api/registry/RegistryStoreMultiJvmSpec.scala +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/api/registry/RegistryStoreMultiJvmSpec.scala @@ -57,16 +57,14 @@ class RegistryStoreMultiJvmNode1 extends MasterClusterTestNode { } barrier("store-1-in-node-1", NrOfNodes) { - val serializer = Serialization.serializerFor(classOf[HelloWorld1]).fold(x ⇒ fail("No serializer found"), s ⇒ s) - node.store("hello-world-1", classOf[HelloWorld1], serializer) + node.store("hello-world-1", classOf[HelloWorld1], Serialization.serializerFor(classOf[HelloWorld1])) } barrier("use-1-in-node-2", NrOfNodes) { } barrier("store-2-in-node-1", NrOfNodes) { - val serializer = Serialization.serializerFor(classOf[HelloWorld1]).fold(x ⇒ fail("No serializer found"), s ⇒ s) - node.store("hello-world-2", classOf[HelloWorld1], false, serializer) + node.store("hello-world-2", classOf[HelloWorld1], false, Serialization.serializerFor(classOf[HelloWorld1])) } barrier("use-2-in-node-2", NrOfNodes) { From bb558c03f4f003d3452e6c696780f0bb1cd36a7f Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 19 Jul 2011 17:17:04 +0200 Subject: [PATCH 21/51] Switching to Serializer.Identifier for storing within ZK --- .../scala/akka/serialization/Serializer.scala | 2 +- .../src/main/scala/akka/cluster/Cluster.scala | 25 +++++-------------- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/akka-actor/src/main/scala/akka/serialization/Serializer.scala b/akka-actor/src/main/scala/akka/serialization/Serializer.scala index 835cf9fa7a..44ecffc2e8 100644 --- a/akka-actor/src/main/scala/akka/serialization/Serializer.scala +++ b/akka-actor/src/main/scala/akka/serialization/Serializer.scala @@ -8,7 +8,7 @@ import java.io.{ ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, B import akka.util.ClassLoaderObjectInputStream object Serializer { - val defaultSerializerName = JavaSerializer.getClass.getName + val defaultSerializerName = classOf[JavaSerializer].getName type Identifier = Byte } diff --git a/akka-cluster/src/main/scala/akka/cluster/Cluster.scala b/akka-cluster/src/main/scala/akka/cluster/Cluster.scala index 9a26ad985b..5f5d4f4771 100644 --- a/akka-cluster/src/main/scala/akka/cluster/Cluster.scala +++ b/akka-cluster/src/main/scala/akka/cluster/Cluster.scala @@ -703,8 +703,6 @@ class DefaultClusterNode private[akka]( serializeMailbox: Boolean, serializer: Serializer): ClusterNode = if (isConnected.isOn) { - val serializerClassName = serializer.getClass.getName - EventHandler.debug(this, "Storing actor with address [%s] in cluster".format(actorAddress)) @@ -739,9 +737,9 @@ class DefaultClusterNode private[akka]( // create ADDRESS -> SERIALIZER CLASS NAME mapping try { - zkClient.createPersistent(actorAddressRegistrySerializerPathFor(actorAddress), serializerClassName) + zkClient.createPersistent(actorAddressRegistrySerializerPathFor(actorAddress), serializer.identifier.toString) } catch { - case e: ZkNodeExistsException ⇒ zkClient.writeData(actorAddressRegistrySerializerPathFor(actorAddress), serializerClassName) + case e: ZkNodeExistsException ⇒ zkClient.writeData(actorAddressRegistrySerializerPathFor(actorAddress), serializer.identifier.toString) } // create ADDRESS -> NODE mapping @@ -1084,21 +1082,10 @@ class DefaultClusterNode private[akka]( /** * Returns Serializer for actor with specific address. */ - def serializerForActor(actorAddress: String): Serializer = { - val serializerClassName = - try { - zkClient.readData(actorAddressRegistrySerializerPathFor(actorAddress), new Stat).asInstanceOf[String] - } catch { - case e: ZkNoNodeException ⇒ throw new IllegalStateException("No serializer found for actor with address [%s]".format(actorAddress)) - } - - ReflectiveAccess.getClassFor(serializerClassName) match { - // FIXME need to pass in a user provide class loader? Now using default in ReflectiveAccess. - case Right(clazz) ⇒ clazz.newInstance.asInstanceOf[Serializer] - case Left(error) ⇒ - EventHandler.error(error, this, "Could not load serializer class [%s] due to: %s".format(serializerClassName, error.toString)) - throw error - } + def serializerForActor(actorAddress: String): Serializer = try { + Serialization.serializerByIdentity(zkClient.readData(actorAddressRegistrySerializerPathFor(actorAddress), new Stat).asInstanceOf[String].toByte) + } catch { + case e: ZkNoNodeException ⇒ throw new IllegalStateException("No serializer found for actor with address [%s]".format(actorAddress)) } /** From fe1051af30ac2a34b040d0ec428d18242eaed462 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 19 Jul 2011 19:28:17 +0200 Subject: [PATCH 22/51] Adding some ScalaDoc to the Serializer --- .../main/scala/akka/serialization/Serializer.scala | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/akka-actor/src/main/scala/akka/serialization/Serializer.scala b/akka-actor/src/main/scala/akka/serialization/Serializer.scala index 44ecffc2e8..aa57c4b47d 100644 --- a/akka-actor/src/main/scala/akka/serialization/Serializer.scala +++ b/akka-actor/src/main/scala/akka/serialization/Serializer.scala @@ -12,13 +12,24 @@ object Serializer { type Identifier = Byte } +/** + * A Serializer represents a bimap between an object and an array of bytes representing that object + */ trait Serializer extends scala.Serializable { /** * Completely unique Byte value to identify this implementation of Serializer, used to optimize network traffic * Values from 0 to 16 is reserved for Akka internal usage */ def identifier: Serializer.Identifier + + /** + * Serializes the given object into an Array of Byte + */ def toBinary(o: AnyRef): Array[Byte] + + /** + * Produces an object from an array of bytes, with an optional type-hint and a classloader to load the class into + */ def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]] = None, classLoader: Option[ClassLoader] = None): AnyRef } From 3bc7db0ddeedaa83f698025dafc67e7ea86065ea Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 19 Jul 2011 19:28:46 +0200 Subject: [PATCH 23/51] Closing ticket #1030, removing lots of warnings --- .../src/main/scala/akka/actor/ActorRef.scala | 2 +- .../scala/akka/dispatch/Dispatchers.scala | 15 ++++++----- .../src/main/scala/akka/dispatch/Future.scala | 14 +++++----- .../main/scala/akka/event/EventHandler.scala | 4 +-- .../src/main/scala/akka/routing/Pool.scala | 2 +- .../src/main/scala/akka/cluster/Cluster.scala | 12 ++++----- .../remote/netty/NettyRemoteSupport.scala | 26 +++++++++---------- .../serialization/SerializationProtocol.scala | 4 +-- .../src/main/scala/akka/agent/Agent.scala | 8 +++--- .../scala/akka/testkit/TestActorRef.scala | 6 ++--- 10 files changed, 46 insertions(+), 47 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index efdf9dc269..948c90ecbe 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -1011,7 +1011,7 @@ private[akka] case class RemoteActorRef private[akka]( case _ ⇒ None } val chFuture = channel match { - case f: Promise[Any] ⇒ Some(f) + case f: Promise[_] ⇒ Some(f.asInstanceOf[Promise[Any]]) case _ ⇒ None } val future = Actor.remote.send[Any](message, chSender, chFuture, remoteAddress, timeout, false, this, loader) diff --git a/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala b/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala index 9af29eed98..64c0c5afb2 100644 --- a/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala +++ b/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala @@ -197,14 +197,15 @@ object Dispatchers { case "GlobalDispatcher" ⇒ GlobalDispatcherConfigurator case fqn ⇒ ReflectiveAccess.getClassFor[MessageDispatcherConfigurator](fqn) match { - case r: Right[_, Class[MessageDispatcherConfigurator]] ⇒ - ReflectiveAccess.createInstance[MessageDispatcherConfigurator](r.b, Array[Class[_]](), Array[AnyRef]()) match { - case r: Right[Exception, MessageDispatcherConfigurator] ⇒ r.b - case l: Left[Exception, MessageDispatcherConfigurator] ⇒ - throw new IllegalArgumentException("Cannot instantiate MessageDispatcherConfigurator type [%s], make sure it has a default no-args constructor" format fqn, l.a) + case Right(clazz) ⇒ + ReflectiveAccess.createInstance[MessageDispatcherConfigurator](clazz, Array[Class[_]](), Array[AnyRef]()) match { + case Right(configurator) ⇒ configurator + case Left(exception)⇒ + throw new IllegalArgumentException( + "Cannot instantiate MessageDispatcherConfigurator type [%s], make sure it has a default no-args constructor" format fqn, exception) } - case l: Left[Exception, _] ⇒ - throw new IllegalArgumentException("Unknown MessageDispatcherConfigurator type [%s]" format fqn, l.a) + case Left(exception) ⇒ + throw new IllegalArgumentException("Unknown MessageDispatcherConfigurator type [%s]" format fqn, exception) } } map { _ configure cfg diff --git a/akka-actor/src/main/scala/akka/dispatch/Future.scala b/akka-actor/src/main/scala/akka/dispatch/Future.scala index 8705d3da4e..5c858a0905 100644 --- a/akka-actor/src/main/scala/akka/dispatch/Future.scala +++ b/akka-actor/src/main/scala/akka/dispatch/Future.scala @@ -90,8 +90,8 @@ object Futures { val aggregate: Future[T] ⇒ Unit = f ⇒ if (done.isOff && !result.isCompleted) { //TODO: This is an optimization, is it premature? f.value.get match { - case r: Right[Throwable, T] ⇒ - val added = results add r.b + case Right(value) ⇒ + val added = results add value if (added && results.size == allDone) { //Only one thread can get here if (done.switchOn) { try { @@ -109,9 +109,9 @@ object Futures { } } } - case l: Left[Throwable, T] ⇒ + case Left(exception) ⇒ if (done.switchOn) { - result completeWithException l.a + result completeWithException exception results.clear } } @@ -148,10 +148,8 @@ object Futures { val seedFold: Future[T] ⇒ Unit = f ⇒ { if (seedFound.compareAndSet(false, true)) { //Only the first completed should trigger the fold f.value.get match { - case r: Right[Throwable, T] ⇒ - result.completeWith(fold(r.b, timeout)(futures.filterNot(_ eq f))(op)) - case l: Left[Throwable, T] ⇒ - result.completeWithException(l.a) + case Right(value) ⇒ result.completeWith(fold(value, timeout)(futures.filterNot(_ eq f))(op)) + case Left(exception) ⇒ result.completeWithException(exception) } } } diff --git a/akka-actor/src/main/scala/akka/event/EventHandler.scala b/akka-actor/src/main/scala/akka/event/EventHandler.scala index 134543e284..0a0e00e2cc 100644 --- a/akka-actor/src/main/scala/akka/event/EventHandler.scala +++ b/akka-actor/src/main/scala/akka/event/EventHandler.scala @@ -112,8 +112,8 @@ object EventHandler extends ListenerManagement { defaultListeners foreach { listenerName ⇒ try { ReflectiveAccess.getClassFor[Actor](listenerName) match { - case r: Right[_, Class[Actor]] ⇒ addListener(Actor.localActorOf(r.b).start()) - case l: Left[Exception, _] ⇒ throw l.a + case Right(actorClass) ⇒ addListener(Actor.localActorOf(actorClass).start()) + case Left(exception) ⇒ throw exception } } catch { case e: Exception ⇒ diff --git a/akka-actor/src/main/scala/akka/routing/Pool.scala b/akka-actor/src/main/scala/akka/routing/Pool.scala index 6398ef2241..6bfd4c18b3 100644 --- a/akka-actor/src/main/scala/akka/routing/Pool.scala +++ b/akka-actor/src/main/scala/akka/routing/Pool.scala @@ -265,7 +265,7 @@ trait MailboxPressureCapacitor { */ trait ActiveFuturesPressureCapacitor { def pressure(delegates: Seq[ActorRef]): Int = - delegates count { _.channel.isInstanceOf[Promise[Any]] } + delegates count { _.channel.isInstanceOf[Promise[_]] } } /** diff --git a/akka-cluster/src/main/scala/akka/cluster/Cluster.scala b/akka-cluster/src/main/scala/akka/cluster/Cluster.scala index 5f5d4f4771..25cb290f05 100644 --- a/akka-cluster/src/main/scala/akka/cluster/Cluster.scala +++ b/akka-cluster/src/main/scala/akka/cluster/Cluster.scala @@ -1917,7 +1917,7 @@ class RemoteClusterDaemon(cluster: ClusterNode) extends Actor { self.dispatcher = computeGridDispatcher def receive = { - case f: Function0[Unit] ⇒ try { + case f: Function0[_] ⇒ try { f() } finally { self.stop() @@ -1930,7 +1930,7 @@ class RemoteClusterDaemon(cluster: ClusterNode) extends Actor { self.dispatcher = computeGridDispatcher def receive = { - case f: Function0[Any] ⇒ try { + case f: Function0[_] ⇒ try { self.reply(f()) } finally { self.stop() @@ -1943,8 +1943,8 @@ class RemoteClusterDaemon(cluster: ClusterNode) extends Actor { self.dispatcher = computeGridDispatcher def receive = { - case (fun: Function[Any, Unit], param: Any) ⇒ try { - fun(param) + case (fun: Function[_, _], param: Any) ⇒ try { + fun.asInstanceOf[Any => Unit].apply(param) } finally { self.stop() } @@ -1956,8 +1956,8 @@ class RemoteClusterDaemon(cluster: ClusterNode) extends Actor { self.dispatcher = computeGridDispatcher def receive = { - case (fun: Function[Any, Unit], param: Any) ⇒ try { - self.reply(fun(param)) + case (fun: Function[_, _], param: Any) ⇒ try { + self.reply(fun.asInstanceOf[Any => Any](param)) } finally { self.stop() } diff --git a/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala b/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala index e79e426d94..a339a1b8b6 100644 --- a/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala +++ b/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala @@ -88,14 +88,14 @@ trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagem lock.readLock.lock try { val c = remoteClients.get(key) match { - case s: Some[RemoteClient] ⇒ s.get + case Some(client) ⇒ client case None ⇒ lock.readLock.unlock lock.writeLock.lock //Lock upgrade, not supported natively try { try { remoteClients.get(key) match { //Recheck for addition, race between upgrades - case s: Some[RemoteClient] ⇒ s.get //If already populated by other writer + case Some(client) ⇒ client //If already populated by other writer case None ⇒ //Populate map val client = new ActiveRemoteClient(this, address, loader, self.notifyListeners _) client.connect() @@ -111,15 +111,15 @@ trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagem def shutdownClientConnection(address: InetSocketAddress): Boolean = lock withWriteGuard { remoteClients.remove(Address(address)) match { - case s: Some[RemoteClient] ⇒ s.get.shutdown() - case None ⇒ false + case Some(client) ⇒ client.shutdown() + case None ⇒ false } } def restartClientConnection(address: InetSocketAddress): Boolean = lock withReadGuard { remoteClients.get(Address(address)) match { - case s: Some[RemoteClient] ⇒ s.get.connect(reconnectIfAlreadyConnected = true) - case None ⇒ false + case Some(client) ⇒ client.connect(reconnectIfAlreadyConnected = true) + case None ⇒ false } } @@ -632,12 +632,12 @@ trait NettyRemoteServerModule extends RemoteServerModule { self: RemoteModule private[akka] val currentServer = new AtomicReference[Option[NettyRemoteServer]](None) def address = currentServer.get match { - case s: Some[NettyRemoteServer] ⇒ s.get.address - case None ⇒ ReflectiveAccess.RemoteModule.configDefaultAddress + case Some(server) ⇒ server.address + case None ⇒ ReflectiveAccess.RemoteModule.configDefaultAddress } def name = currentServer.get match { - case s: Some[NettyRemoteServer] ⇒ s.get.name + case Some(server) ⇒ server.name case None ⇒ val a = ReflectiveAccess.RemoteModule.configDefaultAddress "NettyRemoteServer@" + a.getAddress.getHostAddress + ":" + a.getPort @@ -920,15 +920,15 @@ class RemoteServerHandler( request.getActorInfo.getTimeout, new ActorPromise(request.getActorInfo.getTimeout). onComplete(_.value.get match { - case l: Left[Throwable, Any] ⇒ write(channel, createErrorReplyMessage(l.a, request)) - case r: Right[Throwable, Any] ⇒ + case Left(exception) ⇒ write(channel, createErrorReplyMessage(exception, request)) + case r: Right[_,_] ⇒ val messageBuilder = RemoteActorSerialization.createRemoteMessageProtocolBuilder( Some(actorRef), Right(request.getUuid), actorInfo.getAddress, actorInfo.getTimeout, - r, - true, + r.asInstanceOf[Either[Throwable,Any]], + isOneWay = true, Some(actorRef)) // FIXME lift in the supervisor uuid management into toh createRemoteMessageProtocolBuilder method diff --git a/akka-cluster/src/main/scala/akka/serialization/SerializationProtocol.scala b/akka-cluster/src/main/scala/akka/serialization/SerializationProtocol.scala index e86665295b..d8b1293bc6 100644 --- a/akka-cluster/src/main/scala/akka/serialization/SerializationProtocol.scala +++ b/akka-cluster/src/main/scala/akka/serialization/SerializationProtocol.scala @@ -95,10 +95,10 @@ object ActorSerialization { if (actorRef.mailbox eq null) throw new IllegalActorStateException("Can't serialize an actor that has not been started.") val messages = actorRef.mailbox match { - case q: java.util.Queue[MessageInvocation] ⇒ + case q: java.util.Queue[_] ⇒ val l = new scala.collection.mutable.ListBuffer[MessageInvocation] val it = q.iterator - while (it.hasNext == true) l += it.next + while (it.hasNext) l += it.next.asInstanceOf[MessageInvocation] l } diff --git a/akka-stm/src/main/scala/akka/agent/Agent.scala b/akka-stm/src/main/scala/akka/agent/Agent.scala index 3a97263369..dca421c941 100644 --- a/akka-stm/src/main/scala/akka/agent/Agent.scala +++ b/akka-stm/src/main/scala/akka/agent/Agent.scala @@ -282,8 +282,8 @@ class AgentUpdater[T](agent: Agent[T]) extends Actor { val txFactory = TransactionFactory(familyName = "AgentUpdater", readonly = false) def receive = { - case update: Update[T] ⇒ - self.tryReply(atomic(txFactory) { agent.ref alter update.function }) + case update: Update[_] ⇒ + self.tryReply(atomic(txFactory) { agent.ref alter update.function.asInstanceOf[T => T] }) case Get ⇒ self reply agent.get case _ ⇒ () } @@ -298,8 +298,8 @@ class ThreadBasedAgentUpdater[T](agent: Agent[T]) extends Actor { val txFactory = TransactionFactory(familyName = "ThreadBasedAgentUpdater", readonly = false) def receive = { - case update: Update[T] ⇒ try { - self.tryReply(atomic(txFactory) { agent.ref alter update.function }) + case update: Update[_] ⇒ try { + self.tryReply(atomic(txFactory) { agent.ref alter update.function.asInstanceOf[T => T] }) } finally { agent.resume self.stop() diff --git a/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala b/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala index 6920faea64..116450665a 100644 --- a/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala +++ b/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala @@ -70,12 +70,12 @@ object TestActorRef { import ReflectiveAccess.{ createInstance, noParams, noArgs } createInstance[T](manifest[T].erasure, noParams, noArgs) match { - case r: Right[_, T] ⇒ r.b - case l: Left[Exception, _] ⇒ throw new ActorInitializationException( + case Right(value) ⇒ value + case Left(exception) ⇒ throw new ActorInitializationException( "Could not instantiate Actor" + "\nMake sure Actor is NOT defined inside a class/trait," + "\nif so put it outside the class/trait, f.e. in a companion object," + - "\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'.", l.a) + "\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'.", exception) } }, address) } From 9c5b789b83730e3b0855d05f747bf8b301ff2626 Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Tue, 19 Jul 2011 15:35:49 +0200 Subject: [PATCH 24/51] Ticket 1002: group conf settings --- akka-sbt-plugin/build.sbt | 3 -- .../src/main/scala/AkkaKernelPlugin.scala | 51 +++++++++++-------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/akka-sbt-plugin/build.sbt b/akka-sbt-plugin/build.sbt index e01a2e9809..b7fa421544 100644 --- a/akka-sbt-plugin/build.sbt +++ b/akka-sbt-plugin/build.sbt @@ -9,6 +9,3 @@ version := "2.0-SNAPSHOT" publishMavenStyle := true -publishTo := Some("Typesafe Publish Repo" at "http://repo.typesafe.com/typesafe/maven-releases/") - -credentials += Credentials(Path.userHome / ".ivy2" / "typesafe-credentials") diff --git a/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala b/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala index 65f24ae9d8..e91816a1bb 100644 --- a/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala +++ b/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala @@ -10,19 +10,29 @@ import java.io.File object AkkaMicrokernelPlugin extends Plugin { + case class DistConfig( + outputDirectory: File, + configSourceDirs: Seq[File], + distJvmOptions: String, + distMainClass: String, + libFilter: File ⇒ Boolean, + additionalLibs: Seq[File]) + val Dist = config("dist") extend (Runtime) val dist = TaskKey[File]("dist", "Builds an Akka microkernel directory") // TODO how to reuse keyword "clean" here instead (dist:clean) val distClean = TaskKey[File]("clean-dist", "Removes Akka microkernel directory") + val outputDirectory = SettingKey[File]("output-directory") val configSourceDirs = TaskKey[Seq[File]]("config-source-directories", "Configuration files are copied from these directories") - val distJvmOptions = SettingKey[String]("jvm-options", "JVM parameters to use in start script") + val distJvmOptions = SettingKey[String]("kernel-jvm-options", "JVM parameters to use in start script") val distMainClass = SettingKey[String]("kernel-main-class", "Kernel main class to use in start script") val libFilter = SettingKey[File ⇒ Boolean]("lib-filter", "Filter of dependency jar files") val additionalLibs = TaskKey[Seq[File]]("additional-libs", "Additional dependency jar files") + val distConfig = TaskKey[DistConfig]("dist-config") override lazy val settings = inConfig(Dist)(Seq( @@ -36,32 +46,29 @@ object AkkaMicrokernelPlugin extends Plugin { distJvmOptions := "-Xms1024M -Xmx1024M -Xss1M -XX:MaxPermSize=256M -XX:+UseParallelGC", distMainClass := "akka.kernel.Main", libFilter := { f ⇒ true }, - additionalLibs <<= defaultAdditionalLibs)) ++ + additionalLibs <<= defaultAdditionalLibs, + distConfig <<= (outputDirectory, configSourceDirs, distJvmOptions, distMainClass, libFilter, additionalLibs) map DistConfig)) ++ Seq( dist <<= (dist in Dist).identity) private def distTask: Initialize[Task[File]] = - (outputDirectory, sourceDirectory, crossTarget, dependencyClasspath, - configSourceDirs, distJvmOptions, distMainClass, libFilter, streams) map { - (outDir, src, tgt, cp, configSrc, jvmOptions, mainClass, libFilt, s) ⇒ - val log = s.log - val distBinPath = outDir / "bin" - val distConfigPath = outDir / "config" - val distDeployPath = outDir / "deploy" - val distLibPath = outDir / "lib" - // TODO how do I grab the additionalLibs setting? Can't add it in input tuple, limitation of number of elements in map of tuple. - val addLibs = Seq.empty[File] + (distConfig, sourceDirectory, crossTarget, dependencyClasspath, streams) map { (conf, src, tgt, cp, s) ⇒ + val log = s.log + val distBinPath = conf.outputDirectory / "bin" + val distConfigPath = conf.outputDirectory / "config" + val distDeployPath = conf.outputDirectory / "deploy" + val distLibPath = conf.outputDirectory / "lib" - log.info("Creating distribution %s ..." format outDir) - IO.createDirectory(outDir) - Scripts(jvmOptions, mainClass).writeScripts(distBinPath) - copyDirectories(configSrc, distConfigPath) - copyJars(tgt, distDeployPath) - copyFiles(libFiles(cp, libFilt), distLibPath) - copyFiles(addLibs, distLibPath) - log.info("Distribution created.") - outDir - } + log.info("Creating distribution %s ..." format conf.outputDirectory) + IO.createDirectory(conf.outputDirectory) + Scripts(conf.distJvmOptions, conf.distMainClass).writeScripts(distBinPath) + copyDirectories(conf.configSourceDirs, distConfigPath) + copyJars(tgt, distDeployPath) + copyFiles(libFiles(cp, conf.libFilter), distLibPath) + copyFiles(conf.additionalLibs, distLibPath) + log.info("Distribution created.") + conf.outputDirectory + } private def distCleanTask: Initialize[Task[File]] = (outputDirectory, streams) map { (outDir, s) ⇒ From e0ae830fbb697c8a4ab6d06b20f6998c58d5672e Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Tue, 19 Jul 2011 15:45:45 +0200 Subject: [PATCH 25/51] Ticket 1002: Fixed dist:clean --- akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala b/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala index e91816a1bb..033bdadc79 100644 --- a/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala +++ b/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala @@ -4,6 +4,7 @@ import sbt._ import sbt.Keys._ +import sbt.Keys._ import sbt.classpath.ClasspathUtilities import sbt.Project.Initialize import java.io.File @@ -21,7 +22,7 @@ object AkkaMicrokernelPlugin extends Plugin { val Dist = config("dist") extend (Runtime) val dist = TaskKey[File]("dist", "Builds an Akka microkernel directory") // TODO how to reuse keyword "clean" here instead (dist:clean) - val distClean = TaskKey[File]("clean-dist", "Removes Akka microkernel directory") + val distClean = TaskKey[Unit]("clean", "Removes Akka microkernel directory") val outputDirectory = SettingKey[File]("output-directory") val configSourceDirs = TaskKey[Seq[File]]("config-source-directories", @@ -70,12 +71,11 @@ object AkkaMicrokernelPlugin extends Plugin { conf.outputDirectory } - private def distCleanTask: Initialize[Task[File]] = + private def distCleanTask: Initialize[Task[Unit]] = (outputDirectory, streams) map { (outDir, s) ⇒ val log = s.log log.info("Cleaning " + outDir) IO.delete(outDir) - outDir } def defaultConfigSourceDirs = (sourceDirectory, unmanagedResourceDirectories) map { (src, resources) ⇒ From 741b8ccf95bd8e1d35f0e846cf3afdb63f65a794 Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Tue, 19 Jul 2011 16:06:06 +0200 Subject: [PATCH 26/51] Ticket 1002: Only dist for kernel projects --- .../src/main/scala/AkkaKernelPlugin.scala | 52 +++++++++++-------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala b/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala index 033bdadc79..db2ca5bf13 100644 --- a/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala +++ b/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala @@ -53,36 +53,46 @@ object AkkaMicrokernelPlugin extends Plugin { dist <<= (dist in Dist).identity) private def distTask: Initialize[Task[File]] = - (distConfig, sourceDirectory, crossTarget, dependencyClasspath, streams) map { (conf, src, tgt, cp, s) ⇒ - val log = s.log - val distBinPath = conf.outputDirectory / "bin" - val distConfigPath = conf.outputDirectory / "config" - val distDeployPath = conf.outputDirectory / "deploy" - val distLibPath = conf.outputDirectory / "lib" - - log.info("Creating distribution %s ..." format conf.outputDirectory) - IO.createDirectory(conf.outputDirectory) - Scripts(conf.distJvmOptions, conf.distMainClass).writeScripts(distBinPath) - copyDirectories(conf.configSourceDirs, distConfigPath) - copyJars(tgt, distDeployPath) - copyFiles(libFiles(cp, conf.libFilter), distLibPath) - copyFiles(conf.additionalLibs, distLibPath) - log.info("Distribution created.") + (distConfig, sourceDirectory, crossTarget, dependencyClasspath, allDependencies, streams) map { (conf, src, tgt, cp, deps, s) ⇒ + + if (isKernelProject(deps)) { + val log = s.log + val distBinPath = conf.outputDirectory / "bin" + val distConfigPath = conf.outputDirectory / "config" + val distDeployPath = conf.outputDirectory / "deploy" + val distLibPath = conf.outputDirectory / "lib" + + log.info("Creating distribution %s ..." format conf.outputDirectory) + IO.createDirectory(conf.outputDirectory) + Scripts(conf.distJvmOptions, conf.distMainClass).writeScripts(distBinPath) + copyDirectories(conf.configSourceDirs, distConfigPath) + copyJars(tgt, distDeployPath) + copyFiles(libFiles(cp, conf.libFilter), distLibPath) + copyFiles(conf.additionalLibs, distLibPath) + log.info("Distribution created.") + } conf.outputDirectory } private def distCleanTask: Initialize[Task[Unit]] = - (outputDirectory, streams) map { (outDir, s) ⇒ - val log = s.log - log.info("Cleaning " + outDir) - IO.delete(outDir) + (outputDirectory, allDependencies, streams) map { (outDir, deps, s) ⇒ + + if (isKernelProject(deps)) { + val log = s.log + log.info("Cleaning " + outDir) + IO.delete(outDir) + } } - def defaultConfigSourceDirs = (sourceDirectory, unmanagedResourceDirectories) map { (src, resources) ⇒ + def isKernelProject(dependencies: Seq[ModuleID]): Boolean = { + dependencies.exists(moduleId => moduleId.organization == "se.scalablesolutions.akka" && moduleId.name == "akka-kernel") + } + + private def defaultConfigSourceDirs = (sourceDirectory, unmanagedResourceDirectories) map { (src, resources) ⇒ Seq(src / "main" / "config") ++ resources } - def defaultAdditionalLibs = (libraryDependencies) map { (libs) ⇒ + private def defaultAdditionalLibs = (libraryDependencies) map { (libs) ⇒ Seq.empty[File] } From 48b772c2adf5ec0fd5ac6246b06230d3dac278e0 Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Tue, 19 Jul 2011 20:49:17 +0200 Subject: [PATCH 27/51] Ticket 1002: Include target jars from dependent subprojects --- .../src/main/scala/AkkaKernelPlugin.scala | 81 +++++++++++++++++-- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala b/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala index db2ca5bf13..2f00de19dc 100644 --- a/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala +++ b/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala @@ -4,10 +4,12 @@ import sbt._ import sbt.Keys._ -import sbt.Keys._ +import sbt.Load.BuildStructure import sbt.classpath.ClasspathUtilities import sbt.Project.Initialize +import sbt.CommandSupport._ import java.io.File +import scala.collection.mutable.{ Set => MutableSet } object AkkaMicrokernelPlugin extends Plugin { @@ -21,7 +23,6 @@ object AkkaMicrokernelPlugin extends Plugin { val Dist = config("dist") extend (Runtime) val dist = TaskKey[File]("dist", "Builds an Akka microkernel directory") - // TODO how to reuse keyword "clean" here instead (dist:clean) val distClean = TaskKey[Unit]("clean", "Removes Akka microkernel directory") val outputDirectory = SettingKey[File]("output-directory") @@ -53,22 +54,29 @@ object AkkaMicrokernelPlugin extends Plugin { dist <<= (dist in Dist).identity) private def distTask: Initialize[Task[File]] = - (distConfig, sourceDirectory, crossTarget, dependencyClasspath, allDependencies, streams) map { (conf, src, tgt, cp, deps, s) ⇒ + (distConfig, sourceDirectory, crossTarget, dependencyClasspath, projectDependencies, allDependencies, buildStructure, state, streams) map { + (conf, src, tgt, cp, projDeps, allDeps, buildStruct, st, s) ⇒ - if (isKernelProject(deps)) { + if (isKernelProject(allDeps)) { val log = s.log val distBinPath = conf.outputDirectory / "bin" val distConfigPath = conf.outputDirectory / "config" val distDeployPath = conf.outputDirectory / "deploy" val distLibPath = conf.outputDirectory / "lib" - + + val subProjectDependencies: Set[SubProjectInfo] = allSubProjectDependencies(projDeps, buildStruct, st) + log.info("Creating distribution %s ..." format conf.outputDirectory) IO.createDirectory(conf.outputDirectory) Scripts(conf.distJvmOptions, conf.distMainClass).writeScripts(distBinPath) copyDirectories(conf.configSourceDirs, distConfigPath) copyJars(tgt, distDeployPath) + copyFiles(libFiles(cp, conf.libFilter), distLibPath) copyFiles(conf.additionalLibs, distLibPath) + for (subTarget <- subProjectDependencies.map(_.target)) { + copyJars(subTarget, distLibPath) + } log.info("Distribution created.") } conf.outputDirectory @@ -89,7 +97,7 @@ object AkkaMicrokernelPlugin extends Plugin { } private def defaultConfigSourceDirs = (sourceDirectory, unmanagedResourceDirectories) map { (src, resources) ⇒ - Seq(src / "main" / "config") ++ resources + Seq(src / "config", src / "main" / "config") ++ resources } private def defaultAdditionalLibs = (libraryDependencies) map { (libs) ⇒ @@ -163,6 +171,67 @@ object AkkaMicrokernelPlugin extends Plugin { val (libs, directories) = classpath.map(_.data).partition(ClasspathUtilities.isArchive) libs.map(_.asFile).filter(libFilter) } + + private def allSubProjectDependencies(projDeps: Seq[ModuleID], buildStruct: BuildStructure, state: State): Set[SubProjectInfo] = { + val buildUnit = buildStruct.units(buildStruct.root) + val uri = buildStruct.root + val allProjects = buildUnit.defined.map { + case (id, proj) => (ProjectRef(uri, id) -> proj) + } + + val projDepsNames = projDeps.map(_.name) + def include(project: ResolvedProject): Boolean = projDepsNames.exists(_ == project.id) + val subProjects: Seq[SubProjectInfo] = allProjects.collect { + case (projRef, project) if include(project) => projectInfo(projRef, project, buildStruct, state, allProjects) + }.toList + + val allSubProjects = subProjects.map(_.recursiveSubProjects).flatten.toSet + allSubProjects +} + + private def projectInfo(projectRef: ProjectRef, project: ResolvedProject, buildStruct: BuildStructure, state: State, + allProjects: Map[ProjectRef, ResolvedProject]): SubProjectInfo = { + + def optionalSetting[A](key: ScopedSetting[A]) = key in projectRef get buildStruct.data + + def setting[A](key: ScopedSetting[A], errorMessage: => String) = { + optionalSetting(key) getOrElse { + logger(state).error(errorMessage); + throw new IllegalArgumentException() + } + } + + def evaluateTask[T](taskKey: sbt.Project.ScopedKey[sbt.Task[T]]) = { + EvaluateTask.evaluateTask(buildStruct, taskKey, state, projectRef, false, EvaluateTask.SystemProcessors) + } + + val projDeps: Seq[ModuleID] = evaluateTask(Keys.projectDependencies) match { + case Some(Value(moduleIds)) => moduleIds + case _ => Seq.empty + } + + val projDepsNames = projDeps.map(_.name) + def include(project: ResolvedProject): Boolean = projDepsNames.exists(_ == project.id) + val subProjects = allProjects.collect { + case (projRef, proj) if include(proj) => projectInfo(projRef, proj, buildStruct, state, allProjects) + }.toList + + val target = setting(Keys.crossTarget, "Missing crossTarget directory") + SubProjectInfo(project.id, target, subProjects) + } + + private case class SubProjectInfo(id: String, target: File, subProjects: Seq[SubProjectInfo]) { + + def recursiveSubProjects: Set[SubProjectInfo] = { + val flatSubProjects = for { + x <- subProjects + y <- x.recursiveSubProjects + } yield y + + flatSubProjects.toSet + this + } + + } } From 5592cce5fa48afa7ca84184842e7b198c13308c8 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 19 Jul 2011 21:39:42 +0200 Subject: [PATCH 28/51] Testing out scalariform for SBT 0.10 --- project/AkkaBuild.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index 2f507c9432..b05bc5b6b6 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -1,6 +1,8 @@ import sbt._ import Keys._ import MultiJvmPlugin.{ MultiJvm, extraOptions } +import com.github.oforero.sbtformatter.SbtFormatter._ +import com.github.oforero.sbtformatter.SbtFormatterSettings._ object AkkaBuild extends Build { lazy val buildSettings = Seq( @@ -273,7 +275,7 @@ object AkkaBuild extends Build { override lazy val settings = super.settings ++ buildSettings ++ Publish.versionSettings - lazy val baseSettings = Defaults.defaultSettings ++ Publish.settings + lazy val baseSettings = Defaults.defaultSettings ++ Publish.settings ++ formatterPreferences ++ formatterTasks lazy val parentSettings = baseSettings ++ Seq( publishArtifact in Compile := false From df3d536b9cff7a1399ff1957276efdf5b52de5c2 Mon Sep 17 00:00:00 2001 From: Roland Date: Tue, 19 Jul 2011 16:20:43 -0400 Subject: [PATCH 29/51] improve docs for dispatcher throughput --- akka-docs/scala/dispatchers.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/akka-docs/scala/dispatchers.rst b/akka-docs/scala/dispatchers.rst index 4f385364a2..abcfd6d9bf 100644 --- a/akka-docs/scala/dispatchers.rst +++ b/akka-docs/scala/dispatchers.rst @@ -93,7 +93,7 @@ You can also set the rejection policy that should be used, e.g. what should be d * java.util.concurrent.ThreadPoolExecutor.DiscardPolicy - discards the message (throws it away) * java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy - discards the oldest message in the mailbox (throws it away) -You cane read more about these policies `here `_. +You can read more about these policies `here `_. Here is an example: @@ -104,7 +104,7 @@ Here is an example: import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy class MyActor extends Actor { - self.dispatcher = Dispatchers.newDispatcher(name) + self.dispatcher = Dispatchers.newDispatcher(name, throughput = 15) .withNewThreadPoolWithLinkedBlockingQueueWithCapacity(100) .setCorePoolSize(16) .setMaxPoolSize(128) @@ -114,8 +114,14 @@ Here is an example: ... } -This 'Dispatcher' allows you to define the 'throughput' it should have. This defines the number of messages for a specific Actor the dispatcher should process in one single sweep. -Setting this to a higher number will increase throughput but lower fairness, and vice versa. If you don't specify it explicitly then it uses the default value defined in the 'akka.conf' configuration file: +The standard :class:`Dispatcher` allows you to define the ``throughput`` it +should have, as shown above. This defines the number of messages for a specific +Actor the dispatcher should process in one single sweep; in other words, the +dispatcher will bunch up to ``throughput`` message invocations together when +having elected an actor to run. Setting this to a higher number will increase +throughput but lower fairness, and vice versa. If you don't specify it +explicitly then it uses the default value defined in the 'akka.conf' +configuration file: .. code-block:: ruby From 0fe749f1af9547852cd8fee3e3c243cf931cb233 Mon Sep 17 00:00:00 2001 From: Roland Date: Mon, 11 Jul 2011 22:00:17 +0200 Subject: [PATCH 30/51] add @experimental annotation in akka package --- .../src/main/scala/akka/experimental.scala | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 akka-actor/src/main/scala/akka/experimental.scala diff --git a/akka-actor/src/main/scala/akka/experimental.scala b/akka-actor/src/main/scala/akka/experimental.scala new file mode 100644 index 0000000000..cfc976551a --- /dev/null +++ b/akka-actor/src/main/scala/akka/experimental.scala @@ -0,0 +1,20 @@ +/** + * Copyright (C) 2009-2011 Scalable Solutions AB + */ + +package akka + +import annotation.target._ + +/** + * This annotation marks a feature which is not yet considered stable and may + * change or be removed in a future release. + * + * @author Roland Kuhn + * @since 1.2 + */ +@getter +@setter +@beanGetter +@beanSetter +final class experimental(since: String) extends annotation.StaticAnnotation From 6222e5db18e93518a5eaae7320850299a7b83086 Mon Sep 17 00:00:00 2001 From: Roland Date: Tue, 19 Jul 2011 17:09:45 -0400 Subject: [PATCH 31/51] mark Actor.freshInstance as @experimental --- akka-actor/src/main/scala/akka/actor/Actor.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index 3d2f49b9d1..b981c954ce 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -5,6 +5,7 @@ package akka.actor import DeploymentConfig._ +import akka.experimental import akka.dispatch._ import akka.config._ import Config._ @@ -677,6 +678,7 @@ trait Actor { * Warning: Propagating state from a crashed actor carries the risk * of proliferating the cause of the error. Consider let-it-crash first. */ + @experimental("1.2") def freshInstance(): Option[Actor] = None /** From cc9b3685fed98f1631fa129a23625c9ca619ae26 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 19 Jul 2011 23:27:42 +0200 Subject: [PATCH 32/51] Adding Scalariform plugin --- project/AkkaBuild.scala | 3 +++ project/plugins/project/BuildPlugin.scala | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 project/plugins/project/BuildPlugin.scala diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index b05bc5b6b6..314de39a4b 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -303,6 +303,9 @@ object AkkaBuild extends Build { // disable parallel tests parallelExecution in Test := false, + //Explicitly set sourceFileEncoding to "UTF-8" for scalariform + sourceFileEncoding := "UTF-8", + // for excluding tests in jenkins builds (-Dakka.test.exclude=TimingSpec) testExcludes := akkaTestExcludes, testOptions in Test <++= testExcludes map { _.map(exclude => Tests.Filter(test => !test.contains(exclude))) } diff --git a/project/plugins/project/BuildPlugin.scala b/project/plugins/project/BuildPlugin.scala new file mode 100644 index 0000000000..3648f1e926 --- /dev/null +++ b/project/plugins/project/BuildPlugin.scala @@ -0,0 +1,11 @@ +import sbt._ +import Keys._ + +object PluginDef extends Build { + + lazy val formatterPlugin = ProjectRef( uri("git://github.com/viktorklang/sbt-cool-plugins.git"), "Formatter") + + lazy override val projects = Seq(root) + + lazy val root = Project("plugins", file(".")) dependsOn (formatterPlugin) +} \ No newline at end of file From bf7882cf15a7f3f5dfea789a0f21dfd0eb4e2f2d Mon Sep 17 00:00:00 2001 From: Peter Veentjer Date: Wed, 20 Jul 2011 11:14:51 +0300 Subject: [PATCH 33/51] ticket 885 --- .../scala/akka/actor/actor/ClusterSpec.scala | 59 +++++++++++++++++++ .../scala/akka/actor/actor/DeployerSpec.scala | 1 + .../test/scala/akka/config/ConfigSpec.scala | 1 - .../src/main/scala/akka/actor/Deployer.scala | 2 - .../scala/akka/actor/DeploymentConfig.scala | 1 - 5 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 akka-actor-tests/src/test/scala/akka/actor/actor/ClusterSpec.scala diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/ClusterSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/ClusterSpec.scala new file mode 100644 index 0000000000..9569e1bed5 --- /dev/null +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/ClusterSpec.scala @@ -0,0 +1,59 @@ +package akka.actor.actor + +import org.scalatest.WordSpec +import org.scalatest.matchers.MustMatchers +import akka.config.Config + +class ClusterSpec extends WordSpec with MustMatchers { + + "A Deployer" must { + "be able to parse 'akka.actor.cluster._' config elements" in { + import Config.config._ + + //akka.cluster + getString("akka.cluster.name") must equal(Some("test-cluster")) + getString("akka.cluster.zookeeper-server-addresses") must equal(Some("localhost:2181")) + getInt("akka.cluster.server.port") must equal(Some(2552)) + getInt("akka.cluster.max-time-to-wait-until-connected") must equal(Some(30)) + getInt("akka.cluster.session-timeout") must equal(Some(60)) + getInt("akka.cluster.connection-timeout") must equal(Some(60)) + getBool("akka.cluster.use-compression") must equal(Some(false)) + getInt("akka.cluster.connection-timeout") must equal(Some(60)) + getInt("akka.cluster.remote-daemon-ack-timeout") must equal(Some(30)) + getBool("akka.cluster.include-ref-node-in-replica-set") must equal(Some(true)) + getString("akka.cluster.compression-scheme") must equal(Some("zlib")) + getInt("akka.cluster.zlib-compression-level") must equal(Some(6)) + getString("akka.cluster.layer") must equal(Some("akka.remote.netty.NettyRemoteSupport")) + getString("akka.cluster.secure-cookie") must equal(Some("")) + getString("akka.cluster.log-directory") must equal(Some("_akka_cluster")) + + //akka.cluster.replication + getString("akka.cluster.replication.digest-type") must equal(Some("MAC")) + getString("akka.cluster.replication.password") must equal(Some("secret")) + getInt("akka.cluster.replication.ensemble-size") must equal(Some(3)) + getInt("akka.cluster.replication.quorum-size") must equal(Some(2)) + getInt("akka.cluster.replication.snapshot-frequency") must equal(Some(1000)) + getInt("akka.cluster.replication.timeout") must equal(Some(30)) + + //akka.cluster.server + getInt("akka.cluster.server.port") must equal(Some(2552)) + getInt("akka.cluster.server.message-frame-size") must equal(Some(1048576)) + getInt("akka.cluster.server.connection-timeout") must equal(Some(1)) + getBool("akka.cluster.server.require-cookie") must equal(Some(false)) + getBool("akka.cluster.server.untrusted-mode") must equal(Some(false)) + getInt("akka.cluster.server.backlog") must equal(Some(4096)) + getInt("akka.cluster.server.execution-pool-keepalive") must equal(Some(60)) + getInt("akka.cluster.server.execution-pool-size") must equal(Some(16)) + getInt("akka.cluster.server.max-channel-memory-size") must equal(Some(0)) + getInt("akka.cluster.server.max-total-memory-size") must equal(Some(0)) + + //akka.cluster.client + getBool("akka.cluster.client.buffering.retry-message-send-on-failure") must equal(Some(true)) + getInt("akka.cluster.client.buffering.capacity") must equal(Some(-1)) + getInt("akka.cluster.client.reconnect-delay") must equal(Some(5)) + getInt("akka.cluster.client.read-timeout") must equal(Some(10)) + getInt("akka.cluster.client.reap-futures-delay") must equal(Some(5)) + getInt("akka.cluster.client.reconnection-time-window") must equal(Some(600)) + } + } +} diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/DeployerSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/DeployerSpec.scala index e35d358492..423098a49a 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/actor/DeployerSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/DeployerSpec.scala @@ -14,6 +14,7 @@ class DeployerSpec extends WordSpec with MustMatchers { "be able to parse 'akka.actor.deployment._' config elements" in { val deployment = Deployer.lookupInConfig("service-ping") deployment must be('defined) + deployment must equal(Some( Deploy( "service-ping", diff --git a/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala b/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala index 37545a6181..e7234509d7 100644 --- a/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/config/ConfigSpec.scala @@ -36,7 +36,6 @@ class ConfigSpec extends WordSpec with MustMatchers { getInt("akka.actor.timeout") must equal(Some(5)) getInt("akka.actor.throughput") must equal(Some(5)) getInt("akka.actor.throughput-deadline-time") must equal(Some(-1)) - getInt("akka.actor.deployment.service-ping.clustered.replication-factor") must equal(Some(3)) getString("akka.cluster.layer") must equal(Some("akka.remote.netty.NettyRemoteSupport")) getInt("akka.cluster.server.port") must equal(Some(2552)) diff --git a/akka-actor/src/main/scala/akka/actor/Deployer.scala b/akka-actor/src/main/scala/akka/actor/Deployer.scala index 91f27204d7..3e98716722 100644 --- a/akka-actor/src/main/scala/akka/actor/Deployer.scala +++ b/akka-actor/src/main/scala/akka/actor/Deployer.scala @@ -11,9 +11,7 @@ import java.util.concurrent.ConcurrentHashMap import akka.event.EventHandler import akka.actor.DeploymentConfig._ import akka.config.{ ConfigurationException, Config } -import akka.routing.RouterType import akka.util.ReflectiveAccess._ -import akka.serialization._ import akka.AkkaException /** diff --git a/akka-actor/src/main/scala/akka/actor/DeploymentConfig.scala b/akka-actor/src/main/scala/akka/actor/DeploymentConfig.scala index fc21fc7a23..f5206b7668 100644 --- a/akka-actor/src/main/scala/akka/actor/DeploymentConfig.scala +++ b/akka-actor/src/main/scala/akka/actor/DeploymentConfig.scala @@ -6,7 +6,6 @@ package akka.actor import akka.config.Config import akka.routing.RouterType -import akka.serialization.Serializer /** * Module holding the programmatic deployment configuration classes. From 79d585ec9624ccd21e51325e35d00bc861f4706e Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Wed, 20 Jul 2011 12:07:45 +0200 Subject: [PATCH 34/51] Moving the config of the Scalariform --- project/AkkaBuild.scala | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index 314de39a4b..95eb39811c 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -275,7 +275,24 @@ object AkkaBuild extends Build { override lazy val settings = super.settings ++ buildSettings ++ Publish.versionSettings - lazy val baseSettings = Defaults.defaultSettings ++ Publish.settings ++ formatterPreferences ++ formatterTasks + lazy val baseSettings = Defaults.defaultSettings ++ Publish.settings ++ Seq( + sourceFileEncoding := "UTF-8", + alignSingleLineCaseStatementsMaxArrowIndent := 2000, + alignParameters := true, + alignSingleLineCaseStatements := true, + compactStringConcatenation := false, + indentPackageBlocks := true, + formatXml := true, + preserveSpaceBeforeArguments := true, + doubleIndentClassDeclaration := false, + rewriteArrowSymbols := true, + spaceInsideBrackets := false, + spaceInsideParentheses := false, + spaceBeforeColon:= false, + preserveDanglingCloseParenthesis := false, + indentSpaces := 2, + indentLocalDefs := false + ) ++ formatterTasks lazy val parentSettings = baseSettings ++ Seq( publishArtifact in Compile := false @@ -303,9 +320,6 @@ object AkkaBuild extends Build { // disable parallel tests parallelExecution in Test := false, - //Explicitly set sourceFileEncoding to "UTF-8" for scalariform - sourceFileEncoding := "UTF-8", - // for excluding tests in jenkins builds (-Dakka.test.exclude=TimingSpec) testExcludes := akkaTestExcludes, testOptions in Test <++= testExcludes map { _.map(exclude => Tests.Filter(test => !test.contains(exclude))) } From b23a8fffeb9bbcd4ff80dc55509c8bf7cde5d423 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Wed, 20 Jul 2011 15:58:28 +0200 Subject: [PATCH 35/51] removing replySafe and replyUnsafe in favor of the unified reply/tryReply --- .../java/akka/actor/JavaAPITestActor.java | 2 +- .../src/main/scala/akka/actor/ActorRef.scala | 50 ++++++------------- .../main/scala/akka/actor/UntypedActor.scala | 4 +- .../akka/camel/SampleUntypedConsumer.java | 2 +- .../camel/SampleUntypedConsumerBlocking.java | 2 +- .../intro/getting-started-first-java.rst | 6 +-- akka-docs/java/fault-tolerance.rst | 10 ++-- akka-docs/java/serialization.rst | 6 +-- akka-docs/java/transactors.rst | 2 +- akka-docs/java/untyped-actors.rst | 14 +++--- akka-docs/modules/camel.rst | 12 ++--- .../java/sample/camel/UntypedConsumer1.java | 2 +- .../camel/SampleRemoteUntypedConsumer.java | 2 +- .../test/java/akka/spring/foo/PongActor.java | 2 +- .../example/UntypedCoordinatedCounter.java | 2 +- .../transactor/example/UntypedCounter.java | 2 +- .../test/UntypedCoordinatedCounter.java | 2 +- .../akka/transactor/test/UntypedCounter.java | 2 +- .../java/akka/tutorial/first/java/Pi.java | 2 +- .../java/akka/tutorial/java/second/Pi.java | 2 +- 20 files changed, 54 insertions(+), 74 deletions(-) diff --git a/akka-actor-tests/src/test/java/akka/actor/JavaAPITestActor.java b/akka-actor-tests/src/test/java/akka/actor/JavaAPITestActor.java index fe729970cc..172dd6c6e9 100644 --- a/akka-actor-tests/src/test/java/akka/actor/JavaAPITestActor.java +++ b/akka-actor-tests/src/test/java/akka/actor/JavaAPITestActor.java @@ -2,6 +2,6 @@ package akka.actor; public class JavaAPITestActor extends UntypedActor { public void onReceive(Object msg) { - getContext().replySafe("got it!"); + getContext().tryReply("got it!"); } } diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index 3eeecb98f6..5a459cab3b 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -273,26 +273,29 @@ trait ActorRef extends ActorRefShared with ForwardableChannel with java.lang.Com } /** - * Akka Java API.

- * Use getContext().replyUnsafe(..) to reply with a message to the original sender of the message currently - * being processed. + * Akka Scala & Java API + * Use self.reply(..) to reply with a message to the original sender of the message currently + * being processed. This method fails if the original sender of the message could not be determined with an + * IllegalStateException. + * + * If you don't want deal with this IllegalStateException, but just a boolean, just use the tryReply(...) + * version. + * *

* Throws an IllegalStateException if unable to determine what to reply to. */ - @deprecated("will be removed in 2.0, use reply instead", "1.2") - def replyUnsafe(message: AnyRef) { - reply(message) - } + def reply(message: Any) = channel.!(message)(this) /** - * Akka Java API.

- * Use getContext().replySafe(..) to reply with a message to the original sender of the message currently - * being processed. + * Akka Scala & Java API + * Use tryReply(..) to try reply with a message to the original sender of the message currently + * being processed. This method *

* Returns true if reply was sent, and false if unable to determine what to reply to. + * + * If you would rather have an exception, check the reply(..) version. */ - @deprecated("will be removed in 2.0, use tryReply instead", "1.2") - def replySafe(message: AnyRef): Boolean = tryReply(message) + def tryReply(message: Any): Boolean = channel.safe_!(message)(this) /** * Sets the dispatcher for this actor. Needs to be invoked before the actor is started. @@ -1242,29 +1245,6 @@ trait ScalaActorRef extends ActorRefShared with ForwardableChannel { } else throw new ActorInitializationException( "Actor has not been started, you need to invoke 'actor.start()' before using it") } - - /** - * Use self.reply(..) to reply with a message to the original sender of the message currently - * being processed. This method fails if the original sender of the message could not be determined with an - * IllegalStateException. - * - * If you don't want deal with this IllegalStateException, but just a boolean, just use the tryReply(...) - * version. - * - *

- * Throws an IllegalStateException if unable to determine what to reply to. - */ - def reply(message: Any) = channel.!(message)(this) - - /** - * Use tryReply(..) to try reply with a message to the original sender of the message currently - * being processed. This method - *

- * Returns true if reply was sent, and false if unable to determine what to reply to. - * - * If you would rather have an exception, check the reply(..) version. - */ - def tryReply(message: Any): Boolean = channel.safe_!(message)(this) } case class SerializedActorRef(uuid: Uuid, diff --git a/akka-actor/src/main/scala/akka/actor/UntypedActor.scala b/akka-actor/src/main/scala/akka/actor/UntypedActor.scala index f84cfbf20a..a89a9bccc0 100644 --- a/akka-actor/src/main/scala/akka/actor/UntypedActor.scala +++ b/akka-actor/src/main/scala/akka/actor/UntypedActor.scala @@ -19,8 +19,8 @@ import akka.japi.{ Creator, Procedure } * String msg = (String)message; * * if (msg.equals("UseReply")) { - * // Reply to original sender of message using the 'replyUnsafe' method - * getContext().replyUnsafe(msg + ":" + getContext().getUuid()); + * // Reply to original sender of message using the 'reply' method + * getContext().reply(msg + ":" + getContext().getUuid()); * * } else if (msg.equals("UseSender") && getContext().getSender().isDefined()) { * // Reply to original sender of message using the sender reference diff --git a/akka-camel/src/test/java/akka/camel/SampleUntypedConsumer.java b/akka-camel/src/test/java/akka/camel/SampleUntypedConsumer.java index 99300836c1..3576e472bd 100644 --- a/akka-camel/src/test/java/akka/camel/SampleUntypedConsumer.java +++ b/akka-camel/src/test/java/akka/camel/SampleUntypedConsumer.java @@ -15,7 +15,7 @@ public class SampleUntypedConsumer extends UntypedConsumerActor { Message msg = (Message)message; String body = msg.getBodyAs(String.class); String header = msg.getHeaderAs("test", String.class); - getContext().replySafe(String.format("%s %s", body, header)); + getContext().tryReply(String.format("%s %s", body, header)); } } diff --git a/akka-camel/src/test/java/akka/camel/SampleUntypedConsumerBlocking.java b/akka-camel/src/test/java/akka/camel/SampleUntypedConsumerBlocking.java index b5b22a04ae..03f7f0648f 100644 --- a/akka-camel/src/test/java/akka/camel/SampleUntypedConsumerBlocking.java +++ b/akka-camel/src/test/java/akka/camel/SampleUntypedConsumerBlocking.java @@ -17,7 +17,7 @@ public class SampleUntypedConsumerBlocking extends UntypedConsumerActor { Message msg = (Message)message; String body = msg.getBodyAs(String.class); String header = msg.getHeaderAs("test", String.class); - getContext().replySafe(String.format("%s %s", body, header)); + getContext().tryReply(String.format("%s %s", body, header)); } } diff --git a/akka-docs/intro/getting-started-first-java.rst b/akka-docs/intro/getting-started-first-java.rst index a0fc3eeaac..17cab7cf41 100644 --- a/akka-docs/intro/getting-started-first-java.rst +++ b/akka-docs/intro/getting-started-first-java.rst @@ -291,13 +291,13 @@ Now we can create the worker actor. This is done by extending in the ``UntypedA double result = calculatePiFor(work.getStart(), work.getNrOfElements()); // reply with the result - getContext().replyUnsafe(new Result(result)); + getContext().reply(new Result(result)); } else throw new IllegalArgumentException("Unknown message [" + message + "]"); } } -As you can see we have now created an ``UntypedActor`` with a ``onReceive`` method as a handler for the ``Work`` message. In this handler we invoke the ``calculatePiFor(..)`` method, wrap the result in a ``Result`` message and send it back to the original sender using ``getContext().replyUnsafe(..)``. In Akka the sender reference is implicitly passed along with the message so that the receiver can always reply or store away the sender reference for future use. +As you can see we have now created an ``UntypedActor`` with a ``onReceive`` method as a handler for the ``Work`` message. In this handler we invoke the ``calculatePiFor(..)`` method, wrap the result in a ``Result`` message and send it back to the original sender using ``getContext().reply(..)``. In Akka the sender reference is implicitly passed along with the message so that the receiver can always reply or store away the sender reference for future use. The only thing missing in our ``Worker`` actor is the implementation on the ``calculatePiFor(..)`` method:: @@ -587,7 +587,7 @@ Before we package it up and run it, let's take a look at the full code now, with double result = calculatePiFor(work.getStart(), work.getNrOfElements()) // reply with the result - getContext().replyUnsafe(new Result(result)); + getContext().reply(new Result(result)); } else throw new IllegalArgumentException("Unknown message [" + message + "]"); } diff --git a/akka-docs/java/fault-tolerance.rst b/akka-docs/java/fault-tolerance.rst index 512e914d2b..087f6cb0be 100644 --- a/akka-docs/java/fault-tolerance.rst +++ b/akka-docs/java/fault-tolerance.rst @@ -342,22 +342,22 @@ Supervised actors have the option to reply to the initial sender within preResta // do something that may throw an exception // ... - getContext().replySafe("ok"); + getContext().tryReply("ok"); } @Override public void preRestart(Throwable reason) { - getContext().replySafe(reason.getMessage()); + getContext().tryReply(reason.getMessage()); } @Override public void postStop() { - getContext().replySafe("stopped by supervisor"); + getContext().tryReply("stopped by supervisor"); } } -- A reply within preRestart or postRestart must be a safe reply via getContext().replySafe() because a getContext().replyUnsafe() will throw an exception when the actor is restarted without having failed. This can be the case in context of AllForOne restart strategies. -- A reply within postStop must be a safe reply via getContext().replySafe() because a getContext().replyUnsafe() will throw an exception when the actor has been stopped by the application (and not by a supervisor) after successful execution of receive (or no execution at all). +- A reply within preRestart or postRestart must be a safe reply via getContext().tryReply() because a getContext().reply() will throw an exception when the actor is restarted without having failed. This can be the case in context of AllForOne restart strategies. +- A reply within postStop must be a safe reply via getContext().tryReply() because a getContext().reply() will throw an exception when the actor has been stopped by the application (and not by a supervisor) after successful execution of receive (or no execution at all). Handling too many actor restarts within a specific time limit ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/akka-docs/java/serialization.rst b/akka-docs/java/serialization.rst index 0a41941ba5..aff5db501c 100644 --- a/akka-docs/java/serialization.rst +++ b/akka-docs/java/serialization.rst @@ -20,7 +20,7 @@ Step 1: Define the Actor public class SerializationTestActor extends UntypedActor { public void onReceive(Object msg) { - getContext().replySafe("got it!"); + getContext().tryReply("got it!"); } } @@ -101,10 +101,10 @@ Step 1: Define the Actor public void onReceive(Object msg) { if (msg.equals("hello")) { count = count + 1; - getContext().replyUnsafe("world " + count); + getContext().reply("world " + count); } else if (msg instanceof String) { count = count + 1; - getContext().replyUnsafe("hello " + msg + " " + count); + getContext().reply("hello " + msg + " " + count); } else { throw new IllegalArgumentException("invalid message type"); } diff --git a/akka-docs/java/transactors.rst b/akka-docs/java/transactors.rst index b724ef89b6..3655bd290f 100644 --- a/akka-docs/java/transactors.rst +++ b/akka-docs/java/transactors.rst @@ -95,7 +95,7 @@ Here is an example of coordinating two simple counter UntypedActors so that they }); } } else if (incoming.equals("GetCount")) { - getContext().replyUnsafe(count.get()); + getContext().reply(count.get()); } } } diff --git a/akka-docs/java/untyped-actors.rst b/akka-docs/java/untyped-actors.rst index 3e95cf4aae..fd6912be11 100644 --- a/akka-docs/java/untyped-actors.rst +++ b/akka-docs/java/untyped-actors.rst @@ -247,10 +247,10 @@ which you do by Channel.sendOneWay(msg) We recommend that you as first choice use the channel abstraction instead of the other ways described in the following sections. -Reply using the 'replySafe' and 'replyUnsafe' methods +Reply using the 'tryReply' and 'reply' methods ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you want to send a message back to the original sender of the message you just received then you can use the 'getContext().replyUnsafe(..)' method. +If you want to send a message back to the original sender of the message you just received then you can use the 'getContext().reply(..)' method. .. code-block:: java @@ -258,15 +258,15 @@ If you want to send a message back to the original sender of the message you jus if (message instanceof String) { String msg = (String)message; if (msg.equals("Hello")) { - // Reply to original sender of message using the 'replyUnsafe' method - getContext().replyUnsafe(msg + " from " + getContext().getUuid()); + // Reply to original sender of message using the 'reply' method + getContext().reply(msg + " from " + getContext().getUuid()); } } } In this case we will a reply back to the Actor that sent the message. -The 'replyUnsafe' method throws an 'IllegalStateException' if unable to determine what to reply to, e.g. the sender has not been passed along with the message when invoking one of 'send*' methods. You can also use the more forgiving 'replySafe' method which returns 'true' if reply was sent, and 'false' if unable to determine what to reply to. +The 'reply' method throws an 'IllegalStateException' if unable to determine what to reply to, e.g. the sender has not been passed along with the message when invoking one of 'send*' methods. You can also use the more forgiving 'tryReply' method which returns 'true' if reply was sent, and 'false' if unable to determine what to reply to. .. code-block:: java @@ -274,8 +274,8 @@ The 'replyUnsafe' method throws an 'IllegalStateException' if unable to determin if (message instanceof String) { String msg = (String)message; if (msg.equals("Hello")) { - // Reply to original sender of message using the 'replyUnsafe' method - if (getContext().replySafe(msg + " from " + getContext().getUuid())) ... // success + // Reply to original sender of message using the 'reply' method + if (getContext().tryReply(msg + " from " + getContext().getUuid())) ... // success else ... // handle failure } } diff --git a/akka-docs/modules/camel.rst b/akka-docs/modules/camel.rst index 9b0d2ca3d3..b1bf200e91 100644 --- a/akka-docs/modules/camel.rst +++ b/akka-docs/modules/camel.rst @@ -246,7 +246,7 @@ from localhost on port 8877. public void onReceive(Object message) { Message msg = (Message)message; String body = msg.getBodyAs(String.class); - getContext().replySafe(String.format("Hello %s", body)); + getContext().tryReply(String.format("Hello %s", body)); } } @@ -659,10 +659,10 @@ acknowledgement). public void onReceive(Object message) { // ... - getContext().replyUnsafe(ack()) // on success + getContext().reply(ack()) // on success // ... val e: Exception = ... - getContext().replyUnsafe(new Failure(e)) // on failure + getContext().reply(new Failure(e)) // on failure } } @@ -855,7 +855,7 @@ following consumer actor class. } public void onReceive(Object message) { - getContext().replySafe("response from remote actor 1"); + getContext().tryReply("response from remote actor 1"); } } @@ -1423,7 +1423,7 @@ For initiating a a two-way message exchange, one of the public class SampleUntypedActor extends UntypedActor { public void onReceive(Object msg) { - getContext().replySafe(CamelContextManager.getMandatoryTemplate().requestBody("direct:news", msg)); + getContext().tryReply(CamelContextManager.getMandatoryTemplate().requestBody("direct:news", msg)); } } @@ -1995,7 +1995,7 @@ ends at the target actor. public void onReceive(Object message) { Message msg = (Message) message; String body = msg.getBodyAs(String.class); - getContext().replySafe(String.format("Hello %s", body)); + getContext().tryReply(String.format("Hello %s", body)); } } diff --git a/akka-samples/akka-sample-camel/src/main/java/sample/camel/UntypedConsumer1.java b/akka-samples/akka-sample-camel/src/main/java/sample/camel/UntypedConsumer1.java index 39d910fc28..b84792ed89 100644 --- a/akka-samples/akka-sample-camel/src/main/java/sample/camel/UntypedConsumer1.java +++ b/akka-samples/akka-sample-camel/src/main/java/sample/camel/UntypedConsumer1.java @@ -15,6 +15,6 @@ public class UntypedConsumer1 extends UntypedConsumerActor { public void onReceive(Object message) { Message msg = (Message)message; String body = msg.getBodyAs(String.class); - getContext().replySafe(String.format("received %s", body)); + getContext().tryReply(String.format("received %s", body)); } } diff --git a/akka-samples/akka-sample-camel/src/test/java/sample/camel/SampleRemoteUntypedConsumer.java b/akka-samples/akka-sample-camel/src/test/java/sample/camel/SampleRemoteUntypedConsumer.java index 5dea328e59..04f414a89b 100644 --- a/akka-samples/akka-sample-camel/src/test/java/sample/camel/SampleRemoteUntypedConsumer.java +++ b/akka-samples/akka-sample-camel/src/test/java/sample/camel/SampleRemoteUntypedConsumer.java @@ -15,7 +15,7 @@ public class SampleRemoteUntypedConsumer extends UntypedConsumerActor { Message msg = (Message)message; String body = msg.getBodyAs(String.class); String header = msg.getHeaderAs("test", String.class); - getContext().replySafe(String.format("%s %s", body, header)); + getContext().tryReply(String.format("%s %s", body, header)); } } diff --git a/akka-spring/src/test/java/akka/spring/foo/PongActor.java b/akka-spring/src/test/java/akka/spring/foo/PongActor.java index d4f19078a6..575327572a 100644 --- a/akka-spring/src/test/java/akka/spring/foo/PongActor.java +++ b/akka-spring/src/test/java/akka/spring/foo/PongActor.java @@ -10,7 +10,7 @@ public class PongActor extends UntypedActor { public void onReceive(Object message) throws Exception { if (message instanceof String) { System.out.println("Pongeceived String message: " + message); - getContext().replyUnsafe(message + " from " + getContext().getUuid()); + getContext().reply(message + " from " + getContext().getUuid()); } else { throw new IllegalArgumentException("Unknown message: " + message); } diff --git a/akka-stm/src/test/java/akka/transactor/example/UntypedCoordinatedCounter.java b/akka-stm/src/test/java/akka/transactor/example/UntypedCoordinatedCounter.java index 0fd24ac9a7..167db3a3c4 100644 --- a/akka-stm/src/test/java/akka/transactor/example/UntypedCoordinatedCounter.java +++ b/akka-stm/src/test/java/akka/transactor/example/UntypedCoordinatedCounter.java @@ -32,7 +32,7 @@ public class UntypedCoordinatedCounter extends UntypedActor { } else if (incoming instanceof String) { String message = (String) incoming; if (message.equals("GetCount")) { - getContext().replyUnsafe(count.get()); + getContext().reply(count.get()); } } } diff --git a/akka-stm/src/test/java/akka/transactor/example/UntypedCounter.java b/akka-stm/src/test/java/akka/transactor/example/UntypedCounter.java index 56cc12f6c2..54f03eb809 100644 --- a/akka-stm/src/test/java/akka/transactor/example/UntypedCounter.java +++ b/akka-stm/src/test/java/akka/transactor/example/UntypedCounter.java @@ -26,7 +26,7 @@ public class UntypedCounter extends UntypedTransactor { @Override public boolean normally(Object message) { if ("GetCount".equals(message)) { - getContext().replyUnsafe(count.get()); + getContext().reply(count.get()); return true; } else return false; } diff --git a/akka-stm/src/test/java/akka/transactor/test/UntypedCoordinatedCounter.java b/akka-stm/src/test/java/akka/transactor/test/UntypedCoordinatedCounter.java index 3fc2ca502b..24a720dba8 100644 --- a/akka-stm/src/test/java/akka/transactor/test/UntypedCoordinatedCounter.java +++ b/akka-stm/src/test/java/akka/transactor/test/UntypedCoordinatedCounter.java @@ -57,7 +57,7 @@ public class UntypedCoordinatedCounter extends UntypedActor { } else if (incoming instanceof String) { String message = (String) incoming; if (message.equals("GetCount")) { - getContext().replyUnsafe(count.get()); + getContext().reply(count.get()); } } } diff --git a/akka-stm/src/test/java/akka/transactor/test/UntypedCounter.java b/akka-stm/src/test/java/akka/transactor/test/UntypedCounter.java index 325b06ba73..65923e7f4b 100644 --- a/akka-stm/src/test/java/akka/transactor/test/UntypedCounter.java +++ b/akka-stm/src/test/java/akka/transactor/test/UntypedCounter.java @@ -70,7 +70,7 @@ public class UntypedCounter extends UntypedTransactor { @Override public boolean normally(Object message) { if ("GetCount".equals(message)) { - getContext().replyUnsafe(count.get()); + getContext().reply(count.get()); return true; } else return false; } diff --git a/akka-tutorials/akka-tutorial-first/src/main/java/akka/tutorial/first/java/Pi.java b/akka-tutorials/akka-tutorial-first/src/main/java/akka/tutorial/first/java/Pi.java index fc950ff2ff..2bf9a3bc73 100644 --- a/akka-tutorials/akka-tutorial-first/src/main/java/akka/tutorial/first/java/Pi.java +++ b/akka-tutorials/akka-tutorial-first/src/main/java/akka/tutorial/first/java/Pi.java @@ -76,7 +76,7 @@ public class Pi { double result = calculatePiFor(work.getStart(), work.getNrOfElements()); // reply with the result - getContext().replyUnsafe(new Result(result)); + getContext().reply(new Result(result)); } else throw new IllegalArgumentException("Unknown message [" + message + "]"); } diff --git a/akka-tutorials/akka-tutorial-second/src/main/java/akka/tutorial/java/second/Pi.java b/akka-tutorials/akka-tutorial-second/src/main/java/akka/tutorial/java/second/Pi.java index baa75fc501..91c7829278 100644 --- a/akka-tutorials/akka-tutorial-second/src/main/java/akka/tutorial/java/second/Pi.java +++ b/akka-tutorials/akka-tutorial-second/src/main/java/akka/tutorial/java/second/Pi.java @@ -73,7 +73,7 @@ public class Pi { public void onReceive(Object message) { if (message instanceof Work) { Work work = (Work) message; - getContext().replyUnsafe(new Result(calculatePiFor(work.getArg(), work.getNrOfElements()))); // perform the work + getContext().reply(new Result(calculatePiFor(work.getArg(), work.getNrOfElements()))); // perform the work } else throw new IllegalArgumentException("Unknown message [" + message + "]"); } } From 078886237a8f7787939197f5a66755a20c629587 Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Thu, 21 Jul 2011 09:51:36 +0200 Subject: [PATCH 36/51] Ticket 1002: dist dependsOn packageBin --- akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala b/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala index 2f00de19dc..03f431ee6d 100644 --- a/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala +++ b/akka-sbt-plugin/src/main/scala/AkkaKernelPlugin.scala @@ -36,6 +36,8 @@ object AkkaMicrokernelPlugin extends Plugin { val additionalLibs = TaskKey[Seq[File]]("additional-libs", "Additional dependency jar files") val distConfig = TaskKey[DistConfig]("dist-config") + val distNeedsPackageBin = dist <<= dist.dependsOn(packageBin in Compile) + override lazy val settings = inConfig(Dist)(Seq( dist <<= packageBin.identity, @@ -51,14 +53,14 @@ object AkkaMicrokernelPlugin extends Plugin { additionalLibs <<= defaultAdditionalLibs, distConfig <<= (outputDirectory, configSourceDirs, distJvmOptions, distMainClass, libFilter, additionalLibs) map DistConfig)) ++ Seq( - dist <<= (dist in Dist).identity) + dist <<= (dist in Dist).identity, distNeedsPackageBin) private def distTask: Initialize[Task[File]] = - (distConfig, sourceDirectory, crossTarget, dependencyClasspath, projectDependencies, allDependencies, buildStructure, state, streams) map { - (conf, src, tgt, cp, projDeps, allDeps, buildStruct, st, s) ⇒ + (distConfig, sourceDirectory, crossTarget, dependencyClasspath, projectDependencies, allDependencies, buildStructure, state) map { + (conf, src, tgt, cp, projDeps, allDeps, buildStruct, st) ⇒ if (isKernelProject(allDeps)) { - val log = s.log + val log = logger(st) val distBinPath = conf.outputDirectory / "bin" val distConfigPath = conf.outputDirectory / "config" val distDeployPath = conf.outputDirectory / "deploy" From 0fa3ed169973c0340e2161bca79a106a7db33be6 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Thu, 21 Jul 2011 14:08:38 +0200 Subject: [PATCH 37/51] Forward porting fix for #1034 --- .../src/main/scala/akka/actor/ActorRef.scala | 7 +++++++ .../akka/remote/netty/NettyRemoteSupport.scala | 17 ++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index 5a459cab3b..2f5a650c1f 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -242,6 +242,13 @@ trait ActorRef extends ActorRefShared with ForwardableChannel with java.lang.Com */ def ask(message: AnyRef): Future[AnyRef] = ask(message, timeout, null) + /** + * Akka Java API.

+ * @see ask(message: AnyRef, sender: ActorRef): Future[_] + * Uses the specified timeout (milliseconds) + */ + def ask(message: AnyRef, timeout: Long): Future[Any] = ask(message, timeout, null) + /** * Akka Java API.

* @see ask(message: AnyRef, sender: ActorRef): Future[_] diff --git a/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala b/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala index a339a1b8b6..36e9546d1e 100644 --- a/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala +++ b/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala @@ -462,14 +462,17 @@ class ActiveRemoteClientHandler( case arp: AkkaRemoteProtocol if arp.hasMessage ⇒ val reply = arp.getMessage val replyUuid = uuidFrom(reply.getActorInfo.getUuid.getHigh, reply.getActorInfo.getUuid.getLow) - val future = futures.remove(replyUuid).asInstanceOf[Promise[Any]] + futures.remove(replyUuid).asInstanceOf[Promise[Any]] match { + case null => + client.notifyListeners(RemoteClientError(new IllegalActorStateException("Future mapped to UUID " + replyUuid + " does not exist"), client.module, client.remoteAddress)) - if (reply.hasMessage) { - if (future eq null) throw new IllegalActorStateException("Future mapped to UUID " + replyUuid + " does not exist") - val message = MessageSerializer.deserialize(reply.getMessage) - future.completeWithResult(message) - } else { - future.completeWithException(parseException(reply, client.loader)) + case future => + if (reply.hasMessage) { + val message = MessageSerializer.deserialize(reply.getMessage) + future.completeWithResult(message) + } else { + future.completeWithException(parseException(reply, client.loader)) + } } case other ⇒ throw new RemoteClientException("Unknown message received in remote client handler: " + other, client.module, client.remoteAddress) From c0c60478df5ce867bd30af06136866e3895fa77a Mon Sep 17 00:00:00 2001 From: Peter Veentjer Date: Thu, 21 Jul 2011 16:57:58 +0300 Subject: [PATCH 38/51] ticket 917 --- .../main/scala/akka/event/EventHandler.scala | 41 +-- .../remote/BootableRemoteActorService.scala | 6 + .../remote/netty/NettyRemoteSupport.scala | 299 +++++++++++------- .../serialization/SerializationProtocol.scala | 14 +- 4 files changed, 231 insertions(+), 129 deletions(-) diff --git a/akka-actor/src/main/scala/akka/event/EventHandler.scala b/akka-actor/src/main/scala/akka/event/EventHandler.scala index 0a0e00e2cc..4b1fc2e1aa 100644 --- a/akka-actor/src/main/scala/akka/event/EventHandler.scala +++ b/akka-actor/src/main/scala/akka/event/EventHandler.scala @@ -8,7 +8,7 @@ import akka.actor._ import akka.dispatch.Dispatchers import akka.config.Config._ import akka.config.ConfigurationException -import akka.util.{ ListenerManagement, ReflectiveAccess } +import akka.util.{ListenerManagement, ReflectiveAccess} import akka.serialization._ import akka.AkkaException @@ -26,7 +26,7 @@ import akka.AkkaException * case EventHandler.Info(instance, message) ⇒ ... * case EventHandler.Debug(instance, message) ⇒ ... * case genericEvent ⇒ ... - * } + * } * }) * * EventHandler.addListener(eventHandlerListener) @@ -95,10 +95,10 @@ object EventHandler extends ListenerManagement { @volatile var level: Int = config.getString("akka.event-handler-level", "INFO") match { - case "ERROR" ⇒ ErrorLevel + case "ERROR" ⇒ ErrorLevel case "WARNING" ⇒ WarningLevel - case "INFO" ⇒ InfoLevel - case "DEBUG" ⇒ DebugLevel + case "INFO" ⇒ InfoLevel + case "DEBUG" ⇒ DebugLevel case unknown ⇒ throw new ConfigurationException( "Configuration option 'akka.event-handler-level' is invalid [" + unknown + "]") } @@ -106,21 +106,22 @@ object EventHandler extends ListenerManagement { def start() { try { val defaultListeners = config.getList("akka.event-handlers") match { - case Nil ⇒ "akka.event.EventHandler$DefaultListener" :: Nil + case Nil ⇒ "akka.event.EventHandler$DefaultListener" :: Nil case listeners ⇒ listeners } - defaultListeners foreach { listenerName ⇒ - try { - ReflectiveAccess.getClassFor[Actor](listenerName) match { - case Right(actorClass) ⇒ addListener(Actor.localActorOf(actorClass).start()) - case Left(exception) ⇒ throw exception + defaultListeners foreach { + listenerName ⇒ + try { + ReflectiveAccess.getClassFor[Actor](listenerName) match { + case Right(actorClass) ⇒ addListener(Actor.localActorOf(actorClass).start()) + case Left(exception) ⇒ throw exception + } + } catch { + case e: Exception ⇒ + throw new ConfigurationException( + "Event Handler specified in config can't be loaded [" + listenerName + + "] due to [" + e.toString + "]", e) } - } catch { - case e: Exception ⇒ - throw new ConfigurationException( - "Event Handler specified in config can't be loaded [" + listenerName + - "] due to [" + e.toString + "]", e) - } } info(this, "Starting up EventHandler") } catch { @@ -145,7 +146,7 @@ object EventHandler extends ListenerManagement { notifyListeners(event) } - def notify[T <: Event: ClassManifest](event: ⇒ T) { + def notify[T <: Event : ClassManifest](event: ⇒ T) { if (level >= levelFor(classManifest[T].erasure.asInstanceOf[Class[_ <: Event]])) notifyListeners(event) } @@ -181,6 +182,7 @@ object EventHandler extends ListenerManagement { if (level >= InfoLevel) notifyListeners(Info(instance, message)) } + def debug(instance: AnyRef, message: ⇒ String) { if (level >= DebugLevel) notifyListeners(Debug(instance, message)) } @@ -194,7 +196,7 @@ object EventHandler extends ListenerManagement { def isDebugEnabled = level >= DebugLevel def stackTraceFor(e: Throwable) = { - import java.io.{ StringWriter, PrintWriter } + import java.io.{StringWriter, PrintWriter} val sw = new StringWriter val pw = new PrintWriter(sw) e.printStackTrace(pw) @@ -210,6 +212,7 @@ object EventHandler extends ListenerManagement { } class DefaultListener extends Actor { + import java.text.SimpleDateFormat import java.util.Date diff --git a/akka-cluster/src/main/scala/akka/remote/BootableRemoteActorService.scala b/akka-cluster/src/main/scala/akka/remote/BootableRemoteActorService.scala index 95492a30f5..f214e12f52 100644 --- a/akka-cluster/src/main/scala/akka/remote/BootableRemoteActorService.scala +++ b/akka-cluster/src/main/scala/akka/remote/BootableRemoteActorService.scala @@ -6,6 +6,7 @@ package akka.remote import akka.actor.{ Actor, BootableActorLoaderService } import akka.util.{ ReflectiveAccess, Bootable } +import akka.event.EventHandler /** * This bundle/service is responsible for booting up and shutting down the remote actors facility. @@ -23,14 +24,19 @@ trait BootableRemoteActorService extends Bootable { abstract override def onLoad() { if (ReflectiveAccess.ClusterModule.isEnabled && RemoteServerSettings.isRemotingEnabled) { + EventHandler.info(this, "Initializing Remote Actors Service...") startRemoteService() + EventHandler.info(this, "Remote Actors Service initialized") } super.onLoad() } abstract override def onUnload() { + EventHandler.info(this, "Shutting down Remote Actors Service") + Actor.remote.shutdown() if (remoteServerThread.isAlive) remoteServerThread.join(1000) + EventHandler.info(this, "Remote Actors Service has been shut down") super.onUnload() } } diff --git a/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala b/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala index a339a1b8b6..98b560e0a9 100644 --- a/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala +++ b/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala @@ -4,24 +4,22 @@ package akka.remote.netty -import akka.dispatch.{ ActorPromise, DefaultPromise, Promise, Future } -import akka.remote.{ MessageSerializer, RemoteClientSettings, RemoteServerSettings } +import akka.dispatch.{ActorPromise, DefaultPromise, Promise} +import akka.remote.{MessageSerializer, RemoteClientSettings, RemoteServerSettings} import akka.remote.protocol.RemoteProtocol._ import akka.serialization.RemoteActorSerialization import akka.serialization.RemoteActorSerialization._ import akka.remoteinterface._ import akka.actor.{ - PoisonPill, - LocalActorRef, - Actor, - RemoteActorRef, - ActorRef, - IllegalActorStateException, - RemoteActorSystemMessage, - uuidFrom, - Uuid, - Death, - LifeCycleMessage +PoisonPill, +Actor, +RemoteActorRef, +ActorRef, +IllegalActorStateException, +RemoteActorSystemMessage, +uuidFrom, +Uuid, +LifeCycleMessage } import akka.actor.Actor._ import akka.config.Config @@ -30,23 +28,22 @@ import akka.util._ import akka.event.EventHandler import org.jboss.netty.channel._ -import org.jboss.netty.channel.group.{ DefaultChannelGroup, ChannelGroup, ChannelGroupFuture } +import org.jboss.netty.channel.group.{DefaultChannelGroup, ChannelGroup, ChannelGroupFuture} import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory -import org.jboss.netty.bootstrap.{ ServerBootstrap, ClientBootstrap } -import org.jboss.netty.handler.codec.frame.{ LengthFieldBasedFrameDecoder, LengthFieldPrepender } -import org.jboss.netty.handler.codec.compression.{ ZlibDecoder, ZlibEncoder } -import org.jboss.netty.handler.codec.protobuf.{ ProtobufDecoder, ProtobufEncoder } -import org.jboss.netty.handler.timeout.{ ReadTimeoutHandler, ReadTimeoutException } -import org.jboss.netty.handler.execution.{ OrderedMemoryAwareThreadPoolExecutor, ExecutionHandler } -import org.jboss.netty.util.{ TimerTask, Timeout, HashedWheelTimer } +import org.jboss.netty.bootstrap.{ServerBootstrap, ClientBootstrap} +import org.jboss.netty.handler.codec.frame.{LengthFieldBasedFrameDecoder, LengthFieldPrepender} +import org.jboss.netty.handler.codec.compression.{ZlibDecoder, ZlibEncoder} +import org.jboss.netty.handler.codec.protobuf.{ProtobufDecoder, ProtobufEncoder} +import org.jboss.netty.handler.timeout.{ReadTimeoutHandler, ReadTimeoutException} +import org.jboss.netty.handler.execution.{OrderedMemoryAwareThreadPoolExecutor, ExecutionHandler} +import org.jboss.netty.util.{TimerTask, Timeout, HashedWheelTimer} import scala.collection.mutable.HashMap import scala.collection.JavaConversions._ import java.net.InetSocketAddress -import java.lang.reflect.InvocationTargetException -import java.util.concurrent.atomic.{ AtomicReference, AtomicBoolean } +import java.util.concurrent.atomic.{AtomicReference, AtomicBoolean} import java.util.concurrent._ import akka.AkkaException @@ -66,7 +63,8 @@ object RemoteEncoder { } } -trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagement ⇒ +trait NettyRemoteClientModule extends RemoteClientModule { + self: ListenerManagement ⇒ private val remoteClients = new HashMap[Address, RemoteClient] private val remoteActors = new Index[Address, Uuid] private val lock = new ReadWriteGuard @@ -82,7 +80,7 @@ trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagem withClientFor(remoteAddress, loader)(_.send[T](message, senderOption, senderFuture, remoteAddress, timeout, isOneWay, actorRef)) private[akka] def withClientFor[T]( - address: InetSocketAddress, loader: Option[ClassLoader])(fun: RemoteClient ⇒ T): T = { + address: InetSocketAddress, loader: Option[ClassLoader])(fun: RemoteClient ⇒ T): T = { // loader.foreach(MessageSerializer.setClassLoader(_)) val key = Address(address) lock.readLock.lock @@ -94,7 +92,8 @@ trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagem lock.writeLock.lock //Lock upgrade, not supported natively try { try { - remoteClients.get(key) match { //Recheck for addition, race between upgrades + remoteClients.get(key) match { + //Recheck for addition, race between upgrades case Some(client) ⇒ client //If already populated by other writer case None ⇒ //Populate map val client = new ActiveRemoteClient(this, address, loader, self.notifyListeners _) @@ -102,24 +101,30 @@ trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagem remoteClients += key -> client client } - } finally { lock.readLock.lock } //downgrade - } finally { lock.writeLock.unlock } + } finally { + lock.readLock.lock + } //downgrade + } finally { + lock.writeLock.unlock + } } fun(c) - } finally { lock.readLock.unlock } + } finally { + lock.readLock.unlock + } } def shutdownClientConnection(address: InetSocketAddress): Boolean = lock withWriteGuard { remoteClients.remove(Address(address)) match { case Some(client) ⇒ client.shutdown() - case None ⇒ false + case None ⇒ false } } def restartClientConnection(address: InetSocketAddress): Boolean = lock withReadGuard { remoteClients.get(Address(address)) match { case Some(client) ⇒ client.connect(reconnectIfAlreadyConnected = true) - case None ⇒ false + case None ⇒ false } } @@ -133,7 +138,9 @@ trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagem } def shutdownRemoteClients() = lock withWriteGuard { - remoteClients.foreach({ case (addr, client) ⇒ client.shutdown() }) + remoteClients.foreach({ + case (addr, client) ⇒ client.shutdown() + }) remoteClients.clear() } } @@ -143,9 +150,9 @@ trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagem * ActiveRemoteClient, but others could be feasible, like a PassiveRemoteClient that * reuses an already established connection. */ -abstract class RemoteClient private[akka] ( - val module: NettyRemoteClientModule, - val remoteAddress: InetSocketAddress) { +abstract class RemoteClient private[akka]( + val module: NettyRemoteClientModule, + val remoteAddress: InetSocketAddress) { val useTransactionLog = config.getBool("akka.cluster.client.buffering.retry-message-send-on-failure", true) val transactionLogCapacity = config.getInt("akka.cluster.client.buffering.capacity", -1) @@ -189,13 +196,13 @@ abstract class RemoteClient private[akka] ( * Converts the message to the wireprotocol and sends the message across the wire */ def send[T]( - message: Any, - senderOption: Option[ActorRef], - senderFuture: Option[Promise[T]], - remoteAddress: InetSocketAddress, - timeout: Long, - isOneWay: Boolean, - actorRef: ActorRef): Option[Promise[T]] = + message: Any, + senderOption: Option[ActorRef], + senderFuture: Option[Promise[T]], + remoteAddress: InetSocketAddress, + timeout: Long, + isOneWay: Boolean, + actorRef: ActorRef): Option[Promise[T]] = send(createRemoteMessageProtocolBuilder( Some(actorRef), Left(actorRef.uuid), actorRef.address, timeout, Right(message), isOneWay, senderOption).build, senderFuture) @@ -204,8 +211,8 @@ abstract class RemoteClient private[akka] ( * Sends the message across the wire */ def send[T]( - request: RemoteMessageProtocol, - senderFuture: Option[Promise[T]]): Option[Promise[T]] = { + request: RemoteMessageProtocol, + senderFuture: Option[Promise[T]]): Option[Promise[T]] = { if (isRunning) { EventHandler.debug(this, "Sending to connection [%s] message [\n%s]".format(remoteAddress, request)) @@ -266,20 +273,23 @@ abstract class RemoteClient private[akka] ( } } - private[remote] def sendPendingRequests() = pendingRequests synchronized { // ensure only one thread at a time can flush the log + private[remote] def sendPendingRequests() = pendingRequests synchronized { + // ensure only one thread at a time can flush the log val nrOfMessages = pendingRequests.size if (nrOfMessages > 0) EventHandler.info(this, "Resending [%s] previously failed messages after remote client reconnect" format nrOfMessages) var pendingRequest = pendingRequests.peek while (pendingRequest ne null) { val (isOneWay, futureUuid, message) = pendingRequest - if (isOneWay) { // sendOneWay + if (isOneWay) { + // sendOneWay val future = currentChannel.write(RemoteEncoder.encode(message)) future.awaitUninterruptibly() if (!future.isCancelled && !future.isSuccess) { notifyListeners(RemoteClientWriteFailed(message, future.getCause, module, remoteAddress)) throw future.getCause } - } else { // sendRequestReply + } else { + // sendRequestReply val future = currentChannel.write(RemoteEncoder.encode(message)) future.awaitUninterruptibly() if (future.isCancelled) futures.remove(futureUuid) // Clean up future @@ -300,9 +310,10 @@ abstract class RemoteClient private[akka] ( * * @author Jonas Bonér */ -class ActiveRemoteClient private[akka] ( - module: NettyRemoteClientModule, remoteAddress: InetSocketAddress, - val loader: Option[ClassLoader] = None, notifyListenersFun: (⇒ Any) ⇒ Unit) extends RemoteClient(module, remoteAddress) { +class ActiveRemoteClient private[akka]( + module: NettyRemoteClientModule, remoteAddress: InetSocketAddress, + val loader: Option[ClassLoader] = None, notifyListenersFun: (⇒ Any) ⇒ Unit) extends RemoteClient(module, remoteAddress) { + import RemoteClientSettings._ //FIXME rewrite to a wrapper object (minimize volatile access and maximize encapsulation) @@ -318,6 +329,7 @@ class ActiveRemoteClient private[akka] ( private var reconnectionTimeWindowStart = 0L def notifyListeners(msg: ⇒ Any): Unit = notifyListenersFun(msg) + def currentChannel = connection.getChannel def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean = { @@ -330,15 +342,18 @@ class ActiveRemoteClient private[akka] ( bootstrap.setOption("tcpNoDelay", true) bootstrap.setOption("keepAlive", true) + EventHandler.debug(this, "Starting remote client connection to [%s]".format(remoteAddress)) + + // Wait until the connection attempt succeeds or fails. connection = bootstrap.connect(remoteAddress) openChannels.add(connection.awaitUninterruptibly.getChannel) if (!connection.isSuccess) { notifyListeners(RemoteClientError(connection.getCause, module, remoteAddress)) + EventHandler.error(connection.getCause, "Remote client connection to [%s] has failed".format(remoteAddress), this) false } else { - //Send cookie val handshake = RemoteControlProtocol.newBuilder.setCommandType(CommandType.CONNECT) if (SECURE_COOKIE.nonEmpty) @@ -365,12 +380,16 @@ class ActiveRemoteClient private[akka] ( } match { case true ⇒ true case false if reconnectIfAlreadyConnected ⇒ + EventHandler.debug(this, "Remote client reconnecting to [%s]".format(remoteAddress)) + openChannels.remove(connection.getChannel) connection.getChannel.close connection = bootstrap.connect(remoteAddress) openChannels.add(connection.awaitUninterruptibly.getChannel) // Wait until the connection attempt succeeds or fails. if (!connection.isSuccess) { notifyListeners(RemoteClientError(connection.getCause, module, remoteAddress)) + EventHandler.error(connection.getCause, "Reconnection to [%s] has failed".format(remoteAddress),this) + false } else { //Send cookie @@ -387,6 +406,8 @@ class ActiveRemoteClient private[akka] ( //Please note that this method does _not_ remove the ARC from the NettyRemoteClientModule's map of clients def shutdown() = runSwitch switchOff { + EventHandler.info(this, "Shutting down [%s]".format(name)) + notifyListeners(RemoteClientShutdown(module, remoteAddress)) timer.stop() timer = null @@ -396,6 +417,8 @@ class ActiveRemoteClient private[akka] ( bootstrap = null connection = null pendingRequests.clear() + + EventHandler.info(this, "[%s] has been shut down".format(name)) } private[akka] def isWithinReconnectionTimeWindow: Boolean = { @@ -403,7 +426,11 @@ class ActiveRemoteClient private[akka] ( reconnectionTimeWindowStart = System.currentTimeMillis true } else { - /*Time left > 0*/ (RECONNECTION_TIME_WINDOW - (System.currentTimeMillis - reconnectionTimeWindowStart)) > 0 + val timeLeft = (RECONNECTION_TIME_WINDOW - (System.currentTimeMillis - reconnectionTimeWindowStart)) > 0 + if (timeLeft) { + EventHandler.info(this, "Will try to reconnect to remote server for another [%s] milliseconds".format(timeLeft)) + } + timeLeft } } @@ -414,12 +441,12 @@ class ActiveRemoteClient private[akka] ( * @author Jonas Bonér */ class ActiveRemoteClientPipelineFactory( - name: String, - futures: ConcurrentMap[Uuid, Promise[_]], - bootstrap: ClientBootstrap, - remoteAddress: InetSocketAddress, - timer: HashedWheelTimer, - client: ActiveRemoteClient) extends ChannelPipelineFactory { + name: String, + futures: ConcurrentMap[Uuid, Promise[_]], + bootstrap: ClientBootstrap, + remoteAddress: InetSocketAddress, + timer: HashedWheelTimer, + client: ActiveRemoteClient) extends ChannelPipelineFactory { def getPipeline: ChannelPipeline = { val timeout = new ReadTimeoutHandler(timer, RemoteClientSettings.READ_TIMEOUT.length, RemoteClientSettings.READ_TIMEOUT.unit) @@ -429,7 +456,7 @@ class ActiveRemoteClientPipelineFactory( val protobufEnc = new ProtobufEncoder val (enc, dec) = RemoteServerSettings.COMPRESSION_SCHEME match { case "zlib" ⇒ (new ZlibEncoder(RemoteServerSettings.ZLIB_COMPRESSION_LEVEL) :: Nil, new ZlibDecoder :: Nil) - case _ ⇒ (Nil, Nil) + case _ ⇒ (Nil, Nil) } val remoteClient = new ActiveRemoteClientHandler(name, futures, bootstrap, remoteAddress, timer, client) @@ -443,12 +470,12 @@ class ActiveRemoteClientPipelineFactory( */ @ChannelHandler.Sharable class ActiveRemoteClientHandler( - val name: String, - val futures: ConcurrentMap[Uuid, Promise[_]], - val bootstrap: ClientBootstrap, - val remoteAddress: InetSocketAddress, - val timer: HashedWheelTimer, - val client: ActiveRemoteClient) + val name: String, + val futures: ConcurrentMap[Uuid, Promise[_]], + val bootstrap: ClientBootstrap, + val remoteAddress: InetSocketAddress, + val timer: HashedWheelTimer, + val client: ActiveRemoteClient) extends SimpleChannelUpstreamHandler { override def messageReceived(ctx: ChannelHandlerContext, event: MessageEvent) { @@ -457,11 +484,17 @@ class ActiveRemoteClientHandler( case arp: AkkaRemoteProtocol if arp.hasInstruction ⇒ val rcp = arp.getInstruction rcp.getCommandType match { - case CommandType.SHUTDOWN ⇒ spawn { client.module.shutdownClientConnection(remoteAddress) } + case CommandType.SHUTDOWN ⇒ spawn { + client.module.shutdownClientConnection(remoteAddress) + } } case arp: AkkaRemoteProtocol if arp.hasMessage ⇒ val reply = arp.getMessage val replyUuid = uuidFrom(reply.getActorInfo.getUuid.getHigh, reply.getActorInfo.getUuid.getLow) + + EventHandler.debug(this, "Remote client received RemoteMessageProtocol[\n%s]".format(reply)) + EventHandler.debug(this, "Trying to map back to future: %s".format(replyUuid)) + val future = futures.remove(replyUuid).asInstanceOf[Promise[Any]] if (reply.hasMessage) { @@ -492,13 +525,16 @@ class ActiveRemoteClientHandler( } } }, RemoteClientSettings.RECONNECT_DELAY.toMillis, TimeUnit.MILLISECONDS) - } else spawn { client.module.shutdownClientConnection(remoteAddress) } + } else spawn { + client.module.shutdownClientConnection(remoteAddress) + } } override def channelConnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { try { if (client.useTransactionLog) client.sendPendingRequests() // try to send pending requests (still there after client/server crash ard reconnect client.notifyListeners(RemoteClientConnected(client.module, client.remoteAddress)) + EventHandler.debug(this, "Remote client connected to [%s]".format(ctx.getChannel.getRemoteAddress)) client.resetReconnectionTimeWindow } catch { case e: Throwable ⇒ @@ -510,12 +546,20 @@ class ActiveRemoteClientHandler( override def channelDisconnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { client.notifyListeners(RemoteClientDisconnected(client.module, client.remoteAddress)) + EventHandler.debug(this, "Remote client disconnected from [%s]".format(ctx.getChannel.getRemoteAddress)) } override def exceptionCaught(ctx: ChannelHandlerContext, event: ExceptionEvent) = { + if (event.getCause ne null) + EventHandler.error(event.getCause, "Unexpected exception from downstream in remote client", this) + else + EventHandler.error(this, "Unexpected exception from downstream in remote client: %s".format(event)) + event.getCause match { case e: ReadTimeoutException ⇒ - spawn { client.module.shutdownClientConnection(remoteAddress) } + spawn { + client.module.shutdownClientConnection(remoteAddress) + } case e ⇒ client.notifyListeners(RemoteClientError(e, client.module, client.remoteAddress)) event.getChannel.close //FIXME Is this the correct behavior? @@ -550,17 +594,18 @@ class NettyRemoteSupport extends RemoteSupport with NettyRemoteServerModule with def optimizeLocalScoped_?() = optimizeLocal.get protected[akka] def actorFor( - actorAddress: String, - timeout: Long, - host: String, - port: Int, - loader: Option[ClassLoader]): ActorRef = { + actorAddress: String, + timeout: Long, + host: String, + port: Int, + loader: Option[ClassLoader]): ActorRef = { val homeInetSocketAddress = this.address if (optimizeLocalScoped_?) { if ((host == homeInetSocketAddress.getAddress.getHostAddress || host == homeInetSocketAddress.getHostName) && - port == homeInetSocketAddress.getPort) { //TODO: switch to InetSocketAddress.equals? + port == homeInetSocketAddress.getPort) { + //TODO: switch to InetSocketAddress.equals? val localRef = findActorByAddressOrUuid(actorAddress, actorAddress) if (localRef ne null) return localRef //Code significantly simpler with the return statement } @@ -575,7 +620,9 @@ class NettyRemoteSupport extends RemoteSupport with NettyRemoteServerModule with } class NettyRemoteServer(serverModule: NettyRemoteServerModule, val host: String, val port: Int, val loader: Option[ClassLoader]) { + import RemoteServerSettings._ + val name = "NettyRemoteServer@" + host + ":" + port val address = new InetSocketAddress(host, port) @@ -626,14 +673,14 @@ class NettyRemoteServer(serverModule: NettyRemoteServerModule, val host: String, } } -trait NettyRemoteServerModule extends RemoteServerModule { self: RemoteModule ⇒ - import RemoteServerSettings._ +trait NettyRemoteServerModule extends RemoteServerModule { + self: RemoteModule ⇒ private[akka] val currentServer = new AtomicReference[Option[NettyRemoteServer]](None) def address = currentServer.get match { case Some(server) ⇒ server.address - case None ⇒ ReflectiveAccess.RemoteModule.configDefaultAddress + case None ⇒ ReflectiveAccess.RemoteModule.configDefaultAddress } def name = currentServer.get match { @@ -650,6 +697,8 @@ trait NettyRemoteServerModule extends RemoteServerModule { self: RemoteModule def start(_hostname: String, _port: Int, loader: Option[ClassLoader] = None): RemoteServerModule = guard withGuard { try { _isRunning switchOn { + EventHandler.debug(this, "Starting up remote server on %s:s".format(_hostname, _port)) + currentServer.set(Some(new NettyRemoteServer(this, _hostname, _port, loader))) } } catch { @@ -662,8 +711,11 @@ trait NettyRemoteServerModule extends RemoteServerModule { self: RemoteModule def shutdownServerModule() = guard withGuard { _isRunning switchOff { - currentServer.getAndSet(None) foreach { instance ⇒ - instance.shutdown() + currentServer.getAndSet(None) foreach { + instance ⇒ + EventHandler.debug(this, "Shutting down remote server on %s:%s".format(instance.host, instance.port)) + + instance.shutdown() } } } @@ -707,7 +759,10 @@ trait NettyRemoteServerModule extends RemoteServerModule { self: RemoteModule * Unregister RemoteModule Actor that is registered using its 'id' field (not custom ID). */ def unregister(actorRef: ActorRef): Unit = guard withGuard { + if (_isRunning.isOn) { + EventHandler.debug(this, "Unregister server side remote actor with id [%s]".format(actorRef.uuid)) + actors.remove(actorRef.address, actorRef) actorsByUuid.remove(actorRef.uuid.toString, actorRef) } @@ -719,7 +774,10 @@ trait NettyRemoteServerModule extends RemoteServerModule { self: RemoteModule * NOTE: You need to call this method if you have registered an actor by a custom ID. */ def unregister(id: String): Unit = guard withGuard { + if (_isRunning.isOn) { + EventHandler.debug(this, "Unregister server side remote actor with id [%s]".format(id)) + if (id.startsWith(UUID_PREFIX)) actorsByUuid.remove(id.substring(UUID_PREFIX.length)) else { val actorRef = actors get id @@ -735,7 +793,10 @@ trait NettyRemoteServerModule extends RemoteServerModule { self: RemoteModule * NOTE: You need to call this method if you have registered an actor by a custom ID. */ def unregisterPerSession(id: String): Unit = { + if (_isRunning.isOn) { + EventHandler.info(this, "Unregistering server side remote actor with id [%s]".format(id)) + actorsFactories.remove(id) } } @@ -745,11 +806,12 @@ trait NettyRemoteServerModule extends RemoteServerModule { self: RemoteModule * @author Jonas Bonér */ class RemoteServerPipelineFactory( - val name: String, - val openChannels: ChannelGroup, - val executor: ExecutionHandler, - val loader: Option[ClassLoader], - val server: NettyRemoteServerModule) extends ChannelPipelineFactory { + val name: String, + val openChannels: ChannelGroup, + val executor: ExecutionHandler, + val loader: Option[ClassLoader], + val server: NettyRemoteServerModule) extends ChannelPipelineFactory { + import RemoteServerSettings._ def getPipeline: ChannelPipeline = { @@ -759,7 +821,7 @@ class RemoteServerPipelineFactory( val protobufEnc = new ProtobufEncoder val (enc, dec) = COMPRESSION_SCHEME match { case "zlib" ⇒ (new ZlibEncoder(ZLIB_COMPRESSION_LEVEL) :: Nil, new ZlibDecoder :: Nil) - case _ ⇒ (Nil, Nil) + case _ ⇒ (Nil, Nil) } val authenticator = if (REQUIRE_COOKIE) new RemoteServerAuthenticationHandler(SECURE_COOKIE) :: Nil else Nil val remoteServer = new RemoteServerHandler(name, openChannels, loader, server) @@ -799,10 +861,11 @@ class RemoteServerAuthenticationHandler(secureCookie: Option[String]) extends Si */ @ChannelHandler.Sharable class RemoteServerHandler( - val name: String, - val openChannels: ChannelGroup, - val applicationLoader: Option[ClassLoader], - val server: NettyRemoteServerModule) extends SimpleChannelUpstreamHandler { + val name: String, + val openChannels: ChannelGroup, + val applicationLoader: Option[ClassLoader], + val server: NettyRemoteServerModule) extends SimpleChannelUpstreamHandler { + import RemoteServerSettings._ // applicationLoader.foreach(MessageSerializer.setClassLoader(_)) //TODO: REVISIT: THIS FEELS A BIT DODGY @@ -819,7 +882,7 @@ class RemoteServerHandler( } else if (!future.isSuccess) { val socketAddress = future.getChannel.getRemoteAddress match { case i: InetSocketAddress ⇒ Some(i) - case _ ⇒ None + case _ ⇒ None } server.notifyListeners(RemoteServerWriteFailed(payload, future.getCause, server, socketAddress)) } @@ -835,6 +898,8 @@ class RemoteServerHandler( override def channelConnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { val clientAddress = getClientAddress(ctx) + EventHandler.debug(this,"Remote client [%s] connected to [%s]".format(clientAddress, server.name)) + sessionActors.set(event.getChannel(), new ConcurrentHashMap[String, ActorRef]()) server.notifyListeners(RemoteServerClientConnected(server, clientAddress)) } @@ -842,12 +907,18 @@ class RemoteServerHandler( override def channelDisconnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { val clientAddress = getClientAddress(ctx) + EventHandler.debug(this, "Remote client [%s] disconnected from [%s]".format(clientAddress, server.name)) + // stop all session actors for ( map ← Option(sessionActors.remove(event.getChannel)); actor ← collectionAsScalaIterable(map.values) ) { - try { actor ! PoisonPill } catch { case e: Exception ⇒ } + try { + actor ! PoisonPill + } catch { + case e: Exception ⇒ EventHandler.error(e, "Couldn't stop %s".format(actor),this) + } } server.notifyListeners(RemoteServerClientDisconnected(server, clientAddress)) @@ -855,6 +926,8 @@ class RemoteServerHandler( override def channelClosed(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { val clientAddress = getClientAddress(ctx) + EventHandler.debug("Remote client [%s] channel closed from [%s]".format(clientAddress, server.name),this) + server.notifyListeners(RemoteServerClientClosed(server, clientAddress)) } @@ -870,6 +943,8 @@ class RemoteServerHandler( } override def exceptionCaught(ctx: ChannelHandlerContext, event: ExceptionEvent) = { + EventHandler.error(event.getCause, "Unexpected exception from remote downstream", this) + event.getChannel.close server.notifyListeners(RemoteServerError(event.getCause, server)) } @@ -877,7 +952,7 @@ class RemoteServerHandler( private def getClientAddress(ctx: ChannelHandlerContext): Option[InetSocketAddress] = ctx.getChannel.getRemoteAddress match { case inet: InetSocketAddress ⇒ Some(inet) - case _ ⇒ None + case _ ⇒ None } private def handleRemoteMessageProtocol(request: RemoteMessageProtocol, channel: Channel) = try { @@ -891,8 +966,13 @@ class RemoteServerHandler( private def dispatchToActor(request: RemoteMessageProtocol, channel: Channel) { val actorInfo = request.getActorInfo + + EventHandler.debug(this, "Dispatching to remote actor [%s]".format(actorInfo.getUuid)) + val actorRef = - try { createActor(actorInfo, channel) } catch { + try { + createActor(actorInfo, channel) + } catch { case e: SecurityException ⇒ EventHandler.error(e, this, e.getMessage) write(channel, createErrorReplyMessage(e, request)) @@ -905,7 +985,8 @@ class RemoteServerHandler( if (request.hasSender) Some(RemoteActorSerialization.fromProtobufToRemoteActorRef(request.getSender, applicationLoader)) else None - message match { // first match on system messages + message match { + // first match on system messages case RemoteActorSystemMessage.Stop ⇒ if (UNTRUSTED_MODE) throw new SecurityException("RemoteModule server is operating is untrusted mode, can not stop the actor") else actorRef.stop() @@ -920,22 +1001,22 @@ class RemoteServerHandler( request.getActorInfo.getTimeout, new ActorPromise(request.getActorInfo.getTimeout). onComplete(_.value.get match { - case Left(exception) ⇒ write(channel, createErrorReplyMessage(exception, request)) - case r: Right[_,_] ⇒ - val messageBuilder = RemoteActorSerialization.createRemoteMessageProtocolBuilder( - Some(actorRef), - Right(request.getUuid), - actorInfo.getAddress, - actorInfo.getTimeout, - r.asInstanceOf[Either[Throwable,Any]], - isOneWay = true, - Some(actorRef)) + case Left(exception) ⇒ write(channel, createErrorReplyMessage(exception, request)) + case r: Right[_, _] ⇒ + val messageBuilder = RemoteActorSerialization.createRemoteMessageProtocolBuilder( + Some(actorRef), + Right(request.getUuid), + actorInfo.getAddress, + actorInfo.getTimeout, + r.asInstanceOf[Either[Throwable, Any]], + isOneWay = true, + Some(actorRef)) - // FIXME lift in the supervisor uuid management into toh createRemoteMessageProtocolBuilder method - if (request.hasSupervisorUuid) messageBuilder.setSupervisorUuid(request.getSupervisorUuid) + // FIXME lift in the supervisor uuid management into toh createRemoteMessageProtocolBuilder method + if (request.hasSupervisorUuid) messageBuilder.setSupervisorUuid(request.getSupervisorUuid) - write(channel, RemoteEncoder.encode(messageBuilder.build)) - })) + write(channel, RemoteEncoder.encode(messageBuilder.build)) + })) } } @@ -985,7 +1066,7 @@ class RemoteServerHandler( private def findSessionActor(id: String, channel: Channel): ActorRef = sessionActors.get(channel) match { case null ⇒ null - case map ⇒ map get id + case map ⇒ map get id } private def createErrorReplyMessage(exception: Throwable, request: RemoteMessageProtocol): AkkaRemoteProtocol = { diff --git a/akka-cluster/src/main/scala/akka/serialization/SerializationProtocol.scala b/akka-cluster/src/main/scala/akka/serialization/SerializationProtocol.scala index d8b1293bc6..810f813efb 100644 --- a/akka-cluster/src/main/scala/akka/serialization/SerializationProtocol.scala +++ b/akka-cluster/src/main/scala/akka/serialization/SerializationProtocol.scala @@ -21,6 +21,7 @@ import java.net.InetSocketAddress import com.google.protobuf.ByteString import com.eaio.uuid.UUID +import akka.event.EventHandler /** * Module for local actor serialization. @@ -142,6 +143,8 @@ object ActorSerialization { overriddenUuid: Option[UUID], loader: Option[ClassLoader]): ActorRef = { + EventHandler.debug(this, "Deserializing SerializedActorRefProtocol to LocalActorRef:\n%s".format(protocol)) + val lifeCycle = if (protocol.hasLifeCycle) { protocol.getLifeCycle.getLifeCycle match { @@ -243,11 +246,17 @@ object RemoteActorSerialization { * Deserializes a RemoteActorRefProtocol Protocol Buffers (protobuf) Message into an RemoteActorRef instance. */ private[akka] def fromProtobufToRemoteActorRef(protocol: RemoteActorRefProtocol, loader: Option[ClassLoader]): ActorRef = { - RemoteActorRef( + EventHandler.debug(this, "Deserializing RemoteActorRefProtocol to RemoteActorRef:\n %s".format(protocol)) + + val ref = RemoteActorRef( JavaSerializer.fromBinary(protocol.getInetSocketAddress.toByteArray, Some(classOf[InetSocketAddress]), loader).asInstanceOf[InetSocketAddress], protocol.getAddress, protocol.getTimeout, loader) + + EventHandler.debug(this, "Newly deserialized RemoteActorRef has uuid: %s".format(ref.uuid)) + + ref } /** @@ -263,6 +272,9 @@ object RemoteActorSerialization { case _ ⇒ ReflectiveAccess.RemoteModule.configDefaultAddress } + + EventHandler.debug(this, "Register serialized Actor [%s] as remote @ [%s]".format(actor.uuid, remoteAddress)) + RemoteActorRefProtocol.newBuilder .setInetSocketAddress(ByteString.copyFrom(JavaSerializer.toBinary(remoteAddress))) .setAddress(actor.address) From ecb09351531163bee6fc97a0bc76940aa3fb82b3 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Thu, 21 Jul 2011 17:27:40 +0200 Subject: [PATCH 39/51] Removing superflous fields from LocalActorRef --- .../src/main/scala/akka/actor/ActorRef.scala | 42 +++++++------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index 2f5a650c1f..58a592a7c0 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -21,7 +21,6 @@ import scala.reflect.BeanProperty import scala.collection.immutable.Stack import scala.annotation.tailrec import java.lang.IllegalStateException -import akka.actor.DeploymentConfig.ReplicationScheme private[akka] object ActorRefInternals { @@ -483,27 +482,20 @@ class LocalActorRef private[akka](private[this] val actorFactory: () ⇒ Actor, private val serializer: Serializer = try { Serialization.serializerFor(this.getClass) } catch { case e: Exception => serializerErrorDueTo(e.toString)} - private lazy val replicationScheme: ReplicationScheme = - DeploymentConfig.replicationSchemeFor(Deployer.deploymentFor(address)).getOrElse(DeploymentConfig.Transient) + private lazy val replicationStorage: Option[TransactionLog] = { + import DeploymentConfig._ + val replicationScheme = replicationSchemeFor(Deployer.deploymentFor(address)).getOrElse(Transient) + if(isReplicated(replicationScheme)) { + if (isReplicatedWithTransactionLog(replicationScheme)) { + EventHandler.debug(this, "Creating a transaction log for Actor [%s] with replication strategy [%s]".format(address, replicationScheme)) - private lazy val isReplicated: Boolean = DeploymentConfig.isReplicated(replicationScheme) - - private lazy val isWriteBehindReplication: Boolean = DeploymentConfig.isWriteBehindReplication(replicationScheme) - - private lazy val replicationStorage: Either[TransactionLog, AnyRef] = { - if (DeploymentConfig.isReplicatedWithTransactionLog(replicationScheme)) { - EventHandler.debug(this, - "Creating a transaction log for Actor [%s] with replication strategy [%s]" - .format(address, replicationScheme)) - - Left(transactionLog.newLogFor(_uuid.toString, isWriteBehindReplication, replicationScheme)) - - } else if (DeploymentConfig.isReplicatedWithDataGrid(replicationScheme)) { - throw new ConfigurationException("Replication storage type \"data-grid\" is not yet supported") - - } else { - throw new ConfigurationException("Unknown replication storage type [" + replicationScheme + "]") - } + Some(transactionLog.newLogFor(_uuid.toString, isWriteBehindReplication(replicationScheme), replicationScheme)) //TODO FIXME @jboner shouldn't this be address? + } else if (isReplicatedWithDataGrid(replicationScheme)) { + throw new ConfigurationException("Replication storage type \"data-grid\" is not yet supported") + } else { + throw new ConfigurationException("Unknown replication storage type [" + replicationScheme + "]") + } + } else None } // If it was started inside "newActor", initialize it @@ -597,9 +589,7 @@ class LocalActorRef private[akka](private[this] val actorFactory: () ⇒ Actor, } } //else if (isBeingRestarted) throw new ActorKilledException("Actor [" + toString + "] is being restarted.") - if (isReplicated) { - if (replicationStorage.isLeft) replicationStorage.left.get.delete() - } + if (replicationStorage.isDefined) replicationStorage.get.delete() } } @@ -728,9 +718,7 @@ class LocalActorRef private[akka](private[this] val actorFactory: () ⇒ Actor, } } finally { guard.lock.unlock() - if (isReplicated) { - if (replicationStorage.isLeft) replicationStorage.left.get.recordEntry(messageHandle, this) - } + if (replicationStorage.isDefined) replicationStorage.get.recordEntry(messageHandle, this) } } From 1006fa61db50a9ad56408d5ee152d77747d4083c Mon Sep 17 00:00:00 2001 From: Peter Veentjer Date: Fri, 22 Jul 2011 08:18:34 +0300 Subject: [PATCH 40/51] ticket 1043 --- akka-docs/scala/fault-tolerance.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/akka-docs/scala/fault-tolerance.rst b/akka-docs/scala/fault-tolerance.rst index b610bff96f..507c3a3b88 100644 --- a/akka-docs/scala/fault-tolerance.rst +++ b/akka-docs/scala/fault-tolerance.rst @@ -228,11 +228,11 @@ A child actor can tell the supervising actor to unlink him by sending him the 'U .. code-block:: scala - if (supervisor.isDefined) supervisor.get ! Unlink(this) + if (supervisor.isDefined) supervisor.get ! Unlink(self) // Or shorter using 'foreach': - supervisor.foreach(_ ! Unlink(this)) + supervisor.foreach(_ ! Unlink(self)) The supervising actor's side of things ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From cfa8856fcd663edea16b5a189f6a050b2802a867 Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Wed, 20 Jul 2011 14:06:39 +0200 Subject: [PATCH 41/51] Ticket 981: Adjusted how report files are stored and result logged --- .../common/BenchResultRepository.scala | 43 ++++++++++++++---- .../performance/trading/common/Report.scala | 44 +++++-------------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/BenchResultRepository.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/common/BenchResultRepository.scala index 2f9ea89dd8..c14bb62f18 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/BenchResultRepository.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/common/BenchResultRepository.scala @@ -9,10 +9,10 @@ import java.io.ObjectInputStream import java.io.ObjectOutputStream import java.text.SimpleDateFormat import java.util.Date - import scala.collection.mutable.{ Map ⇒ MutableMap } - import akka.event.EventHandler +import java.io.PrintWriter +import java.io.FileWriter trait BenchResultRepository { def add(stats: Stats) @@ -23,6 +23,10 @@ trait BenchResultRepository { def getWithHistorical(name: String, load: Int): Seq[Stats] + def saveHtmlReport(content: String, name: String): Unit + + def htmlReportUrl(name: String): String + } object BenchResultRepository { @@ -34,8 +38,10 @@ class FileBenchResultRepository extends BenchResultRepository { private val statsByName = MutableMap[String, Seq[Stats]]() private val baselineStats = MutableMap[Key, Stats]() private val historicalStats = MutableMap[Key, Seq[Stats]]() - private val dir = System.getProperty("benchmark.resultDir", "target/benchmark") - private def dirExists: Boolean = new File(dir).exists + private val serDir = System.getProperty("benchmark.resultDir", "target/benchmark") + "/ser" + private def serDirExists: Boolean = new File(serDir).exists + private val htmlDir = System.getProperty("benchmark.resultDir", "target/benchmark") + "/html" + private def htmlDirExists: Boolean = new File(htmlDir).exists protected val maxHistorical = 7 case class Key(name: String, load: Int) @@ -64,10 +70,10 @@ class FileBenchResultRepository extends BenchResultRepository { } private def loadFiles() { - if (dirExists) { + if (serDirExists) { val files = for { - f ← new File(dir).listFiles + f ← new File(serDir).listFiles if f.isFile if f.getName.endsWith(".ser") } yield f @@ -86,11 +92,11 @@ class FileBenchResultRepository extends BenchResultRepository { } private def save(stats: Stats) { - new File(dir).mkdirs - if (!dirExists) return + new File(serDir).mkdirs + if (!serDirExists) return val timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date(stats.timestamp)) val name = stats.name + "--" + timestamp + "--" + stats.load + ".ser" - val f = new File(dir, name) + val f = new File(serDir, name) var out: ObjectOutputStream = null try { out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(f))) @@ -127,5 +133,24 @@ class FileBenchResultRepository extends BenchResultRepository { loadFiles() + def saveHtmlReport(content: String, fileName: String) { + new File(htmlDir).mkdirs + if (!htmlDirExists) return + val f = new File(htmlDir, fileName) + var writer: PrintWriter = null + try { + writer = new PrintWriter(new FileWriter(f)) + writer.print(content) + writer.flush() + } catch { + case e: Exception ⇒ + EventHandler.error(this, "Failed to save report to [%s], due to [%s]". + format(f.getAbsolutePath, e.getMessage)) + } finally { + if (writer ne null) try { writer.close() } catch { case ignore: Exception ⇒ } + } + } + + def htmlReportUrl(fileName: String): String = new File(htmlDir, fileName).getAbsolutePath } diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala index 9160fa631e..7ec32a5904 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala @@ -10,16 +10,13 @@ class Report( resultRepository: BenchResultRepository, compareResultWith: Option[String] = None) { - private val dir = System.getProperty("benchmark.resultDir", "target/benchmark") - - private def dirExists: Boolean = new File(dir).exists - private def log = System.getProperty("benchmark.logResult", "false").toBoolean + private def log = System.getProperty("benchmark.logResult", "true").toBoolean val dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm") val legendTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm") val fileTimestampFormat = new SimpleDateFormat("yyyyMMddHHmmss") - def html(statistics: Seq[Stats]): Unit = if (dirExists) { + def html(statistics: Seq[Stats]): Unit = { val current = statistics.last val sb = new StringBuilder @@ -29,7 +26,8 @@ class Report( sb.append("

%s

\n".format(title)) sb.append("
\n")
-    sb.append(formatResultsTable(statistics))
+    val resultTable = formatResultsTable(statistics)
+    sb.append(resultTable)
     sb.append("\n
\n") sb.append(img(percentilesChart(current))) @@ -43,15 +41,17 @@ class Report( comparePercentilesChart(stats).foreach(url ⇒ sb.append(img(url))) } - if (dirExists) { - val timestamp = fileTimestampFormat.format(new Date(current.timestamp)) - val name = current.name + "--" + timestamp + ".html" - write(sb.toString, name) + val timestamp = fileTimestampFormat.format(new Date(current.timestamp)) + val reportName = current.name + "--" + timestamp + ".html" + resultRepository.saveHtmlReport(sb.toString, reportName) + + if (log) { + EventHandler.info(this, resultTable + "Charts in html report: " + resultRepository.htmlReportUrl(reportName)) } } - private def img(url: String): String = { + def img(url: String): String = { """""".format( url, GoogleChartBuilder.ChartWidth, GoogleChartBuilder.ChartHeight) + "\n" } @@ -59,7 +59,6 @@ class Report( def percentilesChart(stats: Stats): String = { val chartTitle = stats.name + " Percentiles (microseconds)" val chartUrl = GoogleChartBuilder.percentilChartUrl(resultRepository.get(stats.name), chartTitle, _.load + " clients") - if (log) EventHandler.info(this, chartTitle + " Chart:\n" + chartUrl) chartUrl } @@ -70,7 +69,6 @@ class Report( } yield { val chartTitle = stats.name + " vs. " + compareName + ", " + stats.load + " clients" + ", Percentiles (microseconds)" val chartUrl = GoogleChartBuilder.percentilChartUrl(Seq(compareStats, stats), chartTitle, _.name) - if (log) EventHandler.info(this, chartTitle + " Chart:\n" + chartUrl) chartUrl } } @@ -81,7 +79,6 @@ class Report( val chartTitle = stats.name + " vs. historical, " + stats.load + " clients" + ", Percentiles (microseconds)" val chartUrl = GoogleChartBuilder.percentilChartUrl(withHistorical, chartTitle, stats ⇒ legendTimeFormat.format(new Date(stats.timestamp))) - if (log) EventHandler.info(this, chartTitle + " Chart:\n" + chartUrl) Some(chartUrl) } else { None @@ -91,7 +88,6 @@ class Report( def latencyAndThroughputChart(stats: Stats): String = { val chartTitle = stats.name + " Latency (microseconds) and Throughput (TPS)" val chartUrl = GoogleChartBuilder.latencyAndThroughputChartUrl(resultRepository.get(stats.name), chartTitle) - if (log) EventHandler.info(this, chartTitle + " Chart:\n" + chartUrl) chartUrl } @@ -115,8 +111,6 @@ class Report( statsSeq.map(formatStats(_)).mkString("\n") + "\n" + line + "\n" - if (log) EventHandler.info(this, formattedStats) - formattedStats } @@ -146,22 +140,6 @@ class Report( } - def write(content: String, fileName: String) { - val f = new File(dir, fileName) - var writer: PrintWriter = null - try { - writer = new PrintWriter(new FileWriter(f)) - writer.print(content) - writer.flush() - } catch { - case e: Exception ⇒ - EventHandler.error(this, "Failed to save report to [%s], due to [%s]". - format(f.getAbsolutePath, e.getMessage)) - } finally { - if (writer ne null) try { writer.close() } catch { case ignore: Exception ⇒ } - } - } - def header(title: String) = """| | From fcfc0bd0777842463361ec1b1300db99cf42adc5 Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Wed, 20 Jul 2011 14:58:14 +0200 Subject: [PATCH 42/51] Ticket 981: Added mean to latency and througput chart --- .../trading/common/GoogleChartBuilder.scala | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/GoogleChartBuilder.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/common/GoogleChartBuilder.scala index d7f6c965a3..98d40a266e 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/GoogleChartBuilder.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/common/GoogleChartBuilder.scala @@ -144,11 +144,11 @@ object GoogleChartBuilder { sb.append("chxs=0,676767,11.5,0,lt,676767|1,676767,11.5,0,lt,676767|2,676767,11.5,0,lt,676767") sb.append("&") sb.append("chco=") - val seriesColors = List("25B33B", "3072F3", "FF0000", "FF9900") + val seriesColors = List("25B33B", "3072F3", "FF0000", "37F0ED", "FF9900") sb.append(seriesColors.mkString(",")) sb.append("&") // legend - sb.append("chdl=5th Percentile|Median|95th Percentile|Throughput") + sb.append("chdl=5th%20Percentile|Median|95th%20Percentile|Mean|Throughput") sb.append("&") sb.append("chdlp=b") @@ -160,6 +160,7 @@ object GoogleChartBuilder { sb.append("chls=1|1|1") sb.append("&") + // margins sb.append("chma=5,5,5,25") sb.append("&") @@ -181,6 +182,11 @@ object GoogleChartBuilder { } sb.append(percentileSeries.mkString("|")) + sb.append("|") + sb.append(loadStr).append("|") + val meanSeries = statistics.map(s ⇒ formatDouble(s.mean)).mkString(",") + sb.append(meanSeries) + sb.append("|") val maxTps: Double = statistics.map(_.tps).max sb.append(loadStr).append("|") @@ -192,7 +198,7 @@ object GoogleChartBuilder { // y range sb.append("&") - sb.append("chxr=0,").append(minLoad).append(",").append(maxLoad).append("|1,0,").append(maxValue).append("|2,0,") + sb.append("chxr=0,").append(minLoad).append(",").append(maxLoad).append(",4").append("|1,0,").append(maxValue).append("|2,0,") .append(formatDouble(maxTps)) sb.append("&") @@ -203,6 +209,9 @@ object GoogleChartBuilder { sb.append(",") } sb.append(minLoad).append(",").append(maxLoad) + sb.append(",0,").append(formatDouble(maxValue)) + sb.append(",") + sb.append(minLoad).append(",").append(maxLoad) sb.append(",0,").append(formatDouble(maxTps)) sb.append("&") From 9874f5e863895bbede31fd1ba1106991ecfc0175 Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Wed, 20 Jul 2011 15:23:41 +0200 Subject: [PATCH 43/51] Ticket 981: Added mean to percentiles and mean chart --- .../trading/common/GoogleChartBuilder.scala | 16 +++++++++---- .../performance/trading/common/Report.scala | 24 +++++++++---------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/GoogleChartBuilder.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/common/GoogleChartBuilder.scala index 98d40a266e..301227affa 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/GoogleChartBuilder.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/common/GoogleChartBuilder.scala @@ -15,9 +15,9 @@ object GoogleChartBuilder { val ChartHeight = 400 /** - * Builds a bar chart for all percentiles in the statistics. + * Builds a bar chart for all percentiles and the mean in the statistics. */ - def percentilChartUrl(statistics: Seq[Stats], title: String, legend: Stats ⇒ String): String = { + def percentilesAndMeanChartUrl(statistics: Seq[Stats], title: String, legend: akka.performance.trading.common.Stats ⇒ String): String = { if (statistics.isEmpty) return "" val current = statistics.last @@ -38,6 +38,7 @@ object GoogleChartBuilder { sb.append("&") // labels percentileLabels(current.percentiles, sb) + sb.append("|mean") sb.append("|2:|min|mean|median") sb.append("&") // label positions @@ -63,7 +64,7 @@ object GoogleChartBuilder { // data series val maxValue = statistics.map(_.percentiles.last._2).max sb.append("chd=t:") - dataSeries(statistics.map(_.percentiles), sb) + dataSeries(statistics.map(_.percentiles), statistics.map(_.mean), sb) // y range sb.append("&") @@ -98,13 +99,18 @@ object GoogleChartBuilder { sb.append(s) } - private def dataSeries(allPercentiles: Seq[TreeMap[Int, Long]], sb: StringBuilder) { - val series = + private def dataSeries(allPercentiles: Seq[TreeMap[Int, Long]], meanValues: Seq[Double], sb: StringBuilder) { + val percentileSeries = for { percentiles ← allPercentiles } yield { percentiles.values.mkString(",") } + + val series = + for ((s, m) ← percentileSeries.zip(meanValues)) + yield s + "," + formatDouble(m) + sb.append(series.mkString("|")) } diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala index 7ec32a5904..5e8dc6c2a2 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala @@ -30,15 +30,15 @@ class Report( sb.append(resultTable) sb.append("\n\n") - sb.append(img(percentilesChart(current))) + sb.append(img(percentilesAndMeanChart(current))) sb.append(img(latencyAndThroughputChart(current))) for (stats ← statistics) { - compareWithHistoricalPercentiliesChart(stats).foreach(url ⇒ sb.append(img(url))) + compareWithHistoricalPercentiliesAndMeanChart(stats).foreach(url ⇒ sb.append(img(url))) } for (stats ← statistics) { - comparePercentilesChart(stats).foreach(url ⇒ sb.append(img(url))) + comparePercentilesAndMeanChart(stats).foreach(url ⇒ sb.append(img(url))) } val timestamp = fileTimestampFormat.format(new Date(current.timestamp)) @@ -56,28 +56,28 @@ class Report( url, GoogleChartBuilder.ChartWidth, GoogleChartBuilder.ChartHeight) + "\n" } - def percentilesChart(stats: Stats): String = { - val chartTitle = stats.name + " Percentiles (microseconds)" - val chartUrl = GoogleChartBuilder.percentilChartUrl(resultRepository.get(stats.name), chartTitle, _.load + " clients") + def percentilesAndMeanChart(stats: Stats): String = { + val chartTitle = stats.name + " Percentiles and Mean (microseconds)" + val chartUrl = GoogleChartBuilder.percentilesAndMeanChartUrl(resultRepository.get(stats.name), chartTitle, _.load + " clients") chartUrl } - def comparePercentilesChart(stats: Stats): Seq[String] = { + def comparePercentilesAndMeanChart(stats: Stats): Seq[String] = { for { compareName ← compareResultWith.toSeq compareStats ← resultRepository.get(compareName, stats.load) } yield { - val chartTitle = stats.name + " vs. " + compareName + ", " + stats.load + " clients" + ", Percentiles (microseconds)" - val chartUrl = GoogleChartBuilder.percentilChartUrl(Seq(compareStats, stats), chartTitle, _.name) + val chartTitle = stats.name + " vs. " + compareName + ", " + stats.load + " clients" + ", Percentiles and Mean (microseconds)" + val chartUrl = GoogleChartBuilder.percentilesAndMeanChartUrl(Seq(compareStats, stats), chartTitle, _.name) chartUrl } } - def compareWithHistoricalPercentiliesChart(stats: Stats): Option[String] = { + def compareWithHistoricalPercentiliesAndMeanChart(stats: Stats): Option[String] = { val withHistorical = resultRepository.getWithHistorical(stats.name, stats.load) if (withHistorical.size > 1) { - val chartTitle = stats.name + " vs. historical, " + stats.load + " clients" + ", Percentiles (microseconds)" - val chartUrl = GoogleChartBuilder.percentilChartUrl(withHistorical, chartTitle, + val chartTitle = stats.name + " vs. historical, " + stats.load + " clients" + ", Percentiles and Mean (microseconds)" + val chartUrl = GoogleChartBuilder.percentilesAndMeanChartUrl(withHistorical, chartTitle, stats ⇒ legendTimeFormat.format(new Date(stats.timestamp))) Some(chartUrl) } else { From 4105cd949d002159b3b11e428d30b59400e05a49 Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Fri, 22 Jul 2011 08:13:12 +0200 Subject: [PATCH 44/51] Ticket 981: Better initialization of MatchingEngineRouting --- .../trading/common/OrderReceiver.scala | 27 +++++++------------ .../trading/common/TradingSystem.scala | 12 ++++++--- .../trading/oneway/OneWayOrderReceiver.scala | 4 +-- .../trading/oneway/OneWayTradingSystem.scala | 2 +- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/OrderReceiver.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/common/OrderReceiver.scala index e9162299d1..869c186524 100755 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/OrderReceiver.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/common/OrderReceiver.scala @@ -7,11 +7,13 @@ import akka.event.EventHandler trait OrderReceiver { type ME - val matchingEngines: List[ME] - var matchingEnginePartitionsIsStale = true var matchingEngineForOrderbook: Map[String, ME] = Map() - def refreshMatchingEnginePartitions() { + def refreshMatchingEnginePartitions(routing: MatchingEngineRouting[ME]) { + + val matchingEngines: List[ME] = routing.mapping.keys.toList + def supportedOrderbooks(me: ME): List[String] = routing.mapping(me) + val m = Map() ++ (for { me ← matchingEngines @@ -19,14 +21,11 @@ trait OrderReceiver { } yield (orderbookSymbol, me)) matchingEngineForOrderbook = m - matchingEnginePartitionsIsStale = false } - def supportedOrderbooks(me: ME): List[String] - } -class AkkaOrderReceiver(matchingEngineRouting: Map[ActorRef, List[String]], disp: Option[MessageDispatcher]) +class AkkaOrderReceiver(disp: Option[MessageDispatcher]) extends Actor with OrderReceiver { type ME = ActorRef @@ -34,21 +33,13 @@ class AkkaOrderReceiver(matchingEngineRouting: Map[ActorRef, List[String]], disp self.dispatcher = d } - override val matchingEngines: List[ActorRef] = matchingEngineRouting.keys.toList - - override def preStart() { - refreshMatchingEnginePartitions() - } - def receive = { + case routing@MatchingEngineRouting(mapping) ⇒ + refreshMatchingEnginePartitions(routing.asInstanceOf[MatchingEngineRouting[ActorRef]]) case order: Order ⇒ placeOrder(order) case unknown ⇒ EventHandler.warning(this, "Received unknown message: " + unknown) } - override def supportedOrderbooks(me: ActorRef): List[String] = { - matchingEngineRouting(me) - } - def placeOrder(order: Order) = { val matchingEngine = matchingEngineForOrderbook.get(order.orderbookSymbol) matchingEngine match { @@ -60,3 +51,5 @@ class AkkaOrderReceiver(matchingEngineRouting: Map[ActorRef, List[String]], disp } } } + +case class MatchingEngineRouting[ME](mapping: Map[ME, List[String]]) diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/TradingSystem.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/common/TradingSystem.scala index 44951879c5..ed822cf1be 100755 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/TradingSystem.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/common/TradingSystem.scala @@ -75,7 +75,7 @@ class AkkaTradingSystem extends TradingSystem { (1 to 10).toList map (i ⇒ createOrderReceiver()) } - def matchingEngineRouting: Map[ActorRef, List[String]] = { + def matchingEngineRouting: MatchingEngineRouting[ActorRef] = { val rules = for { info ← matchingEngines @@ -84,11 +84,11 @@ class AkkaTradingSystem extends TradingSystem { (info.primary, orderbookSymbols) } - Map() ++ rules + MatchingEngineRouting(Map() ++ rules) } def createOrderReceiver() = - actorOf(new AkkaOrderReceiver(matchingEngineRouting, orDispatcher)) + actorOf(new AkkaOrderReceiver(orDispatcher)) override def start() { for (MatchingEngineInfo(p, s, o) ← matchingEngines) { @@ -97,7 +97,11 @@ class AkkaTradingSystem extends TradingSystem { s.foreach(_.start()) s.foreach(p ! _) } - orderReceivers.foreach(_.start()) + val routing = matchingEngineRouting + for (or ← orderReceivers) { + or.start() + or ! routing + } } override def shutdown() { diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/oneway/OneWayOrderReceiver.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/oneway/OneWayOrderReceiver.scala index d64639d3fa..16e3a41048 100755 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/oneway/OneWayOrderReceiver.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/oneway/OneWayOrderReceiver.scala @@ -6,8 +6,8 @@ import akka.event.EventHandler import akka.performance.trading.domain._ import akka.performance.trading.common.AkkaOrderReceiver -class OneWayOrderReceiver(matchingEngineRouting: Map[ActorRef, List[String]], disp: Option[MessageDispatcher]) - extends AkkaOrderReceiver(matchingEngineRouting, disp) { +class OneWayOrderReceiver(disp: Option[MessageDispatcher]) + extends AkkaOrderReceiver(disp) { override def placeOrder(order: Order) = { val matchingEngine = matchingEngineForOrderbook.get(order.orderbookSymbol) diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/oneway/OneWayTradingSystem.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/oneway/OneWayTradingSystem.scala index d6fcafbf7c..57737e9c0e 100755 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/oneway/OneWayTradingSystem.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/oneway/OneWayTradingSystem.scala @@ -11,6 +11,6 @@ class OneWayTradingSystem extends AkkaTradingSystem { actorOf(new OneWayMatchingEngine(meId, orderbooks, meDispatcher)) override def createOrderReceiver() = - actorOf(new OneWayOrderReceiver(matchingEngineRouting, orDispatcher)) + actorOf(new OneWayOrderReceiver(orDispatcher)) } \ No newline at end of file From 031253f16dedc7751e4c97bc76e8a322e4ffbfcb Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Fri, 22 Jul 2011 08:57:59 +0200 Subject: [PATCH 45/51] Ticket 981: Include system info in report --- .../performance/trading/common/Report.scala | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala index 5e8dc6c2a2..880711b8f2 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala @@ -5,6 +5,7 @@ import java.io.PrintWriter import java.io.FileWriter import akka.event.EventHandler import java.util.Date +import java.lang.management.ManagementFactory class Report( resultRepository: BenchResultRepository, @@ -41,6 +42,11 @@ class Report( comparePercentilesAndMeanChart(stats).foreach(url ⇒ sb.append(img(url))) } + sb.append("
\n") + sb.append("
\n")
+    sb.append(systemInformation)
+    sb.append("\n
\n") + val timestamp = fileTimestampFormat.format(new Date(current.timestamp)) val reportName = current.name + "--" + timestamp + ".html" resultRepository.saveHtmlReport(sb.toString, reportName) @@ -140,6 +146,51 @@ class Report( } + def systemInformation: String = { + val runtime = ManagementFactory.getRuntimeMXBean + val os = ManagementFactory.getOperatingSystemMXBean + val threads = ManagementFactory.getThreadMXBean + val mem = ManagementFactory.getMemoryMXBean + val heap = mem.getHeapMemoryUsage + + val sb = new StringBuilder + + sb.append("Benchmark properties: ") + import scala.collection.JavaConversions._ + val propNames: Seq[String] = System.getProperties.propertyNames.toSeq.map(_.toString) + for (name ← propNames if name.startsWith("benchmark.")) { + sb.append(name).append("=").append(System.getProperty(name)).append(" ") + } + sb.append("\n") + + sb.append("Operating system: ").append(os.getName).append(", ").append(os.getArch).append(", ").append(os.getVersion) + sb.append("\n") + sb.append("JVM: ").append(runtime.getVmName).append(" ").append(runtime.getVmVendor). + append(" ").append(runtime.getVmVersion) + sb.append("\n") + val args = runtime.getInputArguments.filterNot(_.contains("classpath")).mkString(" ") + sb.append("Args: ").append(args) + sb.append("\n") + sb.append("Processors: ").append(os.getAvailableProcessors) + sb.append("\n") + sb.append("Load average: ").append(os.getSystemLoadAverage) + sb.append("\n") + sb.append("Thread count: ").append(threads.getThreadCount).append(" (").append(threads.getPeakThreadCount).append(")") + sb.append("\n") + sb.append("Heap: ").append(formatDouble(heap.getUsed.toDouble / 1024 / 1024)). + append(" (").append(formatDouble(heap.getInit.toDouble / 1024 / 1024)). + append(" - "). + append(formatDouble(heap.getMax.toDouble / 1024 / 1024)). + append(")").append(" MB") + sb.append("\n") + + sb.toString + } + + def formatDouble(value: Double): String = { + new java.math.BigDecimal(value).setScale(2, java.math.RoundingMode.HALF_EVEN).toString + } + def header(title: String) = """| | From 82710595d81f11fec7392eecd0ced42318c46b8a Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Fri, 22 Jul 2011 09:11:45 +0200 Subject: [PATCH 46/51] Ticket 981: Moved general stuff to separate package --- .../trading/common/PerformanceTest.scala | 6 +++--- .../BenchResultRepository.scala | 10 ++++++---- .../GoogleChartBuilder.scala | 7 +++---- .../{trading/common => workbench}/Report.scala | 16 +++++++++------- .../{trading/common => workbench}/Stats.scala | 2 +- 5 files changed, 22 insertions(+), 19 deletions(-) rename akka-actor-tests/src/test/scala/akka/performance/{trading/common => workbench}/BenchResultRepository.scala (98%) rename akka-actor-tests/src/test/scala/akka/performance/{trading/common => workbench}/GoogleChartBuilder.scala (97%) rename akka-actor-tests/src/test/scala/akka/performance/{trading/common => workbench}/Report.scala (97%) rename akka-actor-tests/src/test/scala/akka/performance/{trading/common => workbench}/Stats.scala (88%) diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/PerformanceTest.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/common/PerformanceTest.scala index 69a7b4bd08..3c160a09ab 100755 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/PerformanceTest.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/common/PerformanceTest.scala @@ -1,7 +1,5 @@ package akka.performance.trading.common -import java.text.SimpleDateFormat -import java.util.Date import java.util.Random import scala.collection.immutable.TreeMap @@ -12,11 +10,13 @@ import org.junit.After import org.junit.Before import org.scalatest.junit.JUnitSuite -import akka.event.EventHandler import akka.performance.trading.domain.Ask import akka.performance.trading.domain.Bid import akka.performance.trading.domain.Order import akka.performance.trading.domain.TotalTradeCounter +import akka.performance.workbench.BenchResultRepository +import akka.performance.workbench.Report +import akka.performance.workbench.Stats trait PerformanceTest extends JUnitSuite { diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/BenchResultRepository.scala b/akka-actor-tests/src/test/scala/akka/performance/workbench/BenchResultRepository.scala similarity index 98% rename from akka-actor-tests/src/test/scala/akka/performance/trading/common/BenchResultRepository.scala rename to akka-actor-tests/src/test/scala/akka/performance/workbench/BenchResultRepository.scala index c14bb62f18..0c8e5f0cb2 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/BenchResultRepository.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/workbench/BenchResultRepository.scala @@ -1,18 +1,20 @@ -package akka.performance.trading.common +package akka.performance.workbench import java.io.BufferedInputStream import java.io.BufferedOutputStream import java.io.File import java.io.FileInputStream import java.io.FileOutputStream +import java.io.FileWriter import java.io.ObjectInputStream import java.io.ObjectOutputStream +import java.io.PrintWriter import java.text.SimpleDateFormat import java.util.Date -import scala.collection.mutable.{ Map ⇒ MutableMap } + +import scala.collection.mutable.{Map => MutableMap} + import akka.event.EventHandler -import java.io.PrintWriter -import java.io.FileWriter trait BenchResultRepository { def add(stats: Stats) diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/GoogleChartBuilder.scala b/akka-actor-tests/src/test/scala/akka/performance/workbench/GoogleChartBuilder.scala similarity index 97% rename from akka-actor-tests/src/test/scala/akka/performance/trading/common/GoogleChartBuilder.scala rename to akka-actor-tests/src/test/scala/akka/performance/workbench/GoogleChartBuilder.scala index 301227affa..a2d2a381a8 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/GoogleChartBuilder.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/workbench/GoogleChartBuilder.scala @@ -1,10 +1,9 @@ -package akka.performance.trading.common +package akka.performance.workbench import java.io.UnsupportedEncodingException import java.net.URLEncoder + import scala.collection.immutable.TreeMap -import java.util.Locale -import java.util.Formatter /** * Generates URLs to Google Chart API http://code.google.com/apis/chart/ @@ -17,7 +16,7 @@ object GoogleChartBuilder { /** * Builds a bar chart for all percentiles and the mean in the statistics. */ - def percentilesAndMeanChartUrl(statistics: Seq[Stats], title: String, legend: akka.performance.trading.common.Stats ⇒ String): String = { + def percentilesAndMeanChartUrl(statistics: Seq[Stats], title: String, legend: Stats ⇒ String): String = { if (statistics.isEmpty) return "" val current = statistics.last diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala b/akka-actor-tests/src/test/scala/akka/performance/workbench/Report.scala similarity index 97% rename from akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala rename to akka-actor-tests/src/test/scala/akka/performance/workbench/Report.scala index 880711b8f2..2be216fc7a 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/Report.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/workbench/Report.scala @@ -1,11 +1,13 @@ -package akka.performance.trading.common -import java.io.File -import java.text.SimpleDateFormat -import java.io.PrintWriter -import java.io.FileWriter -import akka.event.EventHandler -import java.util.Date +package akka.performance.workbench + import java.lang.management.ManagementFactory +import java.text.SimpleDateFormat +import java.util.Date + +import scala.collection.JavaConversions.asScalaBuffer +import scala.collection.JavaConversions.enumerationAsScalaIterator + +import akka.event.EventHandler class Report( resultRepository: BenchResultRepository, diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/Stats.scala b/akka-actor-tests/src/test/scala/akka/performance/workbench/Stats.scala similarity index 88% rename from akka-actor-tests/src/test/scala/akka/performance/trading/common/Stats.scala rename to akka-actor-tests/src/test/scala/akka/performance/workbench/Stats.scala index 1b1b854cb0..4a15a2c10e 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/Stats.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/workbench/Stats.scala @@ -1,4 +1,4 @@ -package akka.performance.trading.common +package akka.performance.workbench import scala.collection.immutable.TreeMap From eccee3d12f513eac019c130f3a79840a69e93f3d Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Fri, 22 Jul 2011 10:00:57 +0200 Subject: [PATCH 47/51] Ticket 981: minor --- .../akka/performance/trading/common/BenchmarkScenarios.scala | 2 ++ .../src/test/scala/akka/performance/workbench/Stats.scala | 1 + 2 files changed, 3 insertions(+) diff --git a/akka-actor-tests/src/test/scala/akka/performance/trading/common/BenchmarkScenarios.scala b/akka-actor-tests/src/test/scala/akka/performance/trading/common/BenchmarkScenarios.scala index 6cbd6ee4ca..5442deacd5 100755 --- a/akka-actor-tests/src/test/scala/akka/performance/trading/common/BenchmarkScenarios.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/trading/common/BenchmarkScenarios.scala @@ -29,12 +29,14 @@ trait BenchmarkScenarios extends PerformanceTest { def complexScenario80 = complexScenario(80) @Test def complexScenario100 = complexScenario(100) + /* @Test def complexScenario200 = complexScenario(200) @Test def complexScenario300 = complexScenario(300) @Test def complexScenario400 = complexScenario(400) + */ def complexScenario(numberOfClients: Int) { Assume.assumeTrue(numberOfClients >= minClients) diff --git a/akka-actor-tests/src/test/scala/akka/performance/workbench/Stats.scala b/akka-actor-tests/src/test/scala/akka/performance/workbench/Stats.scala index 4a15a2c10e..c307d997e3 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/workbench/Stats.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/workbench/Stats.scala @@ -2,6 +2,7 @@ package akka.performance.workbench import scala.collection.immutable.TreeMap +@SerialVersionUID(1L) case class Stats( name: String, load: Int, From a5bbbb572a0f4ae01e276d804b7241b4fe14f1ae Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Fri, 22 Jul 2011 10:01:25 +0200 Subject: [PATCH 48/51] Ticket 981: Include akka properties in report --- .../akka/performance/workbench/Report.scala | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/performance/workbench/Report.scala b/akka-actor-tests/src/test/scala/akka/performance/workbench/Report.scala index 2be216fc7a..dce6017203 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/workbench/Report.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/workbench/Report.scala @@ -8,6 +8,8 @@ import scala.collection.JavaConversions.asScalaBuffer import scala.collection.JavaConversions.enumerationAsScalaIterator import akka.event.EventHandler +import akka.config.Config +import akka.config.Config.config class Report( resultRepository: BenchResultRepository, @@ -157,11 +159,11 @@ class Report( val sb = new StringBuilder - sb.append("Benchmark properties: ") + sb.append("Benchmark properties:") import scala.collection.JavaConversions._ val propNames: Seq[String] = System.getProperties.propertyNames.toSeq.map(_.toString) - for (name ← propNames if name.startsWith("benchmark.")) { - sb.append(name).append("=").append(System.getProperty(name)).append(" ") + for (name ← propNames if name.startsWith("benchmark")) { + sb.append("\n ").append(name).append("=").append(System.getProperty(name)) } sb.append("\n") @@ -170,9 +172,6 @@ class Report( sb.append("JVM: ").append(runtime.getVmName).append(" ").append(runtime.getVmVendor). append(" ").append(runtime.getVmVersion) sb.append("\n") - val args = runtime.getInputArguments.filterNot(_.contains("classpath")).mkString(" ") - sb.append("Args: ").append(args) - sb.append("\n") sb.append("Processors: ").append(os.getAvailableProcessors) sb.append("\n") sb.append("Load average: ").append(os.getSystemLoadAverage) @@ -186,6 +185,17 @@ class Report( append(")").append(" MB") sb.append("\n") + val args = runtime.getInputArguments.filterNot(_.contains("classpath")).mkString("\n ") + sb.append("Args:\n ").append(args) + sb.append("\n") + + sb.append("Akka version: ").append(Config.CONFIG_VERSION) + sb.append("\n") + sb.append("Akka config:") + for (key ← config.keys) { + sb.append("\n ").append(key).append("=").append(config(key)) + } + sb.toString } From f406cd98e0302167cedbc6bc08067f20f600032e Mon Sep 17 00:00:00 2001 From: Peter Vlugter Date: Mon, 25 Jul 2011 13:24:39 +1200 Subject: [PATCH 49/51] Add abstract method for dispatcher name --- .../src/main/scala/akka/dispatch/MessageHandling.scala | 5 +++++ .../main/scala/akka/testkit/CallingThreadDispatcher.scala | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala b/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala index 42caa4fca8..625c7417cf 100644 --- a/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala +++ b/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala @@ -68,6 +68,11 @@ trait MessageDispatcher { */ private[akka] def createMailbox(actorRef: ActorRef): AnyRef + /** + * Name of this dispatcher. + */ + def name: String + /** * Attaches the specified actorRef to this dispatcher */ diff --git a/akka-testkit/src/main/scala/akka/testkit/CallingThreadDispatcher.scala b/akka-testkit/src/main/scala/akka/testkit/CallingThreadDispatcher.scala index 9128afab7f..0f0344cc49 100644 --- a/akka-testkit/src/main/scala/akka/testkit/CallingThreadDispatcher.scala +++ b/akka-testkit/src/main/scala/akka/testkit/CallingThreadDispatcher.scala @@ -32,7 +32,7 @@ import scala.annotation.tailrec object CallingThreadDispatcher { - lazy val global = new CallingThreadDispatcher + lazy val global = new CallingThreadDispatcher("global-calling-thread") // PRIVATE DATA @@ -104,7 +104,7 @@ object CallingThreadDispatcher { * @author Roland Kuhn * @since 1.1 */ -class CallingThreadDispatcher(val warnings: Boolean = true) extends MessageDispatcher { +class CallingThreadDispatcher(val name: String = "calling-thread", val warnings: Boolean = true) extends MessageDispatcher { import CallingThreadDispatcher._ private[akka] override def createMailbox(actor: ActorRef) = new CallingThreadMailbox From 1b1720d65a47fce3876c31ec4b4838f0c4bebed4 Mon Sep 17 00:00:00 2001 From: Peter Veentjer Date: Mon, 25 Jul 2011 12:47:43 +0300 Subject: [PATCH 50/51] ticket #1048 --- .../test/scala/akka/AkkaExceptionSpec.scala | 28 ++++++++++++++++++ .../src/main/scala/akka/AkkaException.scala | 2 ++ .../src/main/scala/akka/actor/Actor.scala | 29 +++++++++++++++---- .../src/main/scala/akka/actor/Scheduler.scala | 1 - .../main/scala/akka/actor/Supervisor.scala | 5 ++-- .../scala/akka/cluster/ClusterInterface.scala | 6 +--- .../src/main/scala/akka/config/Config.scala | 9 ++++-- .../scala/akka/cluster/TransactionLog.scala | 5 ++-- .../scala/akka/cluster/storage/Storage.scala | 16 +++++++--- .../remote/netty/NettyRemoteSupport.scala | 4 ++- .../actor/mailbox/BeanstalkBasedMailbox.scala | 2 +- .../scala/akka/transactor/Coordinated.scala | 4 ++- 12 files changed, 85 insertions(+), 26 deletions(-) create mode 100644 akka-actor-tests/src/test/scala/akka/AkkaExceptionSpec.scala diff --git a/akka-actor-tests/src/test/scala/akka/AkkaExceptionSpec.scala b/akka-actor-tests/src/test/scala/akka/AkkaExceptionSpec.scala new file mode 100644 index 0000000000..ac0b2b75cf --- /dev/null +++ b/akka-actor-tests/src/test/scala/akka/AkkaExceptionSpec.scala @@ -0,0 +1,28 @@ +package akka; + +import akka.actor._ +import org.scalatest.matchers.MustMatchers +import org.scalatest.WordSpec; + +/** + * A spec that verified that the AkkaException has at least a single argument constructor of type String. + * + * This is required to make Akka Exceptions be friends with serialization/deserialization. + */ +class AkkaExceptionSpec extends WordSpec with MustMatchers { + + "AkkaException" must { + "have a AkkaException(String msg) constructor to be serialization friendly" in { + //if the call to this method completes, we know what there is at least a single constructor which has + //the expected argument type. + verify(classOf[AkkaException]) + + //lets also try it for the exception that triggered this bug to be discovered. + verify(classOf[ActorKilledException]) + } + } + + def verify(clazz:java.lang.Class[_]):Unit = { + clazz.getConstructor(Array(classOf[String]): _*) + } +} diff --git a/akka-actor/src/main/scala/akka/AkkaException.scala b/akka-actor/src/main/scala/akka/AkkaException.scala index f87453db10..24831ff589 100644 --- a/akka-actor/src/main/scala/akka/AkkaException.scala +++ b/akka-actor/src/main/scala/akka/AkkaException.scala @@ -26,6 +26,8 @@ class AkkaException(message: String = "", cause: Throwable = null) extends Runti lazy val toLongString = "%s: %s\n[%s]\n%s".format(getClass.getName, message, uuid, stackTraceToString) + def this(msg:String) = this(msg, null); + def stackTraceToString = { val trace = getStackTrace val sb = new StringBuffer diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index b981c954ce..d988bc1819 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -80,12 +80,29 @@ case class MaximumNumberOfRestartsWithinTimeRangeReached( @BeanProperty lastExceptionCausingRestart: Throwable) extends LifeCycleMessage // Exceptions for Actors -class ActorStartException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) -class IllegalActorStateException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) -class ActorKilledException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) -class ActorInitializationException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) -class ActorTimeoutException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) -class InvalidMessageException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) +class ActorStartException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause){ + def this(msg:String) = this(msg, null); +} + +class IllegalActorStateException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) { + def this(msg:String) = this(msg, null); +} + +class ActorKilledException private[akka] (message: String, cause: Throwable) extends AkkaException(message, cause){ + def this(msg: String) = this(msg, null); +} + +class ActorInitializationException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) { + def this(msg:String) = this(msg, null); +} + +class ActorTimeoutException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) { + def this(msg:String) = this(msg, null); +} + +class InvalidMessageException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) { + def this(msg:String) = this(msg, null); +} /** * This message is thrown by default when an Actors behavior doesn't match a message diff --git a/akka-actor/src/main/scala/akka/actor/Scheduler.scala b/akka-actor/src/main/scala/akka/actor/Scheduler.scala index efbec15239..9c93e2dbdd 100644 --- a/akka-actor/src/main/scala/akka/actor/Scheduler.scala +++ b/akka-actor/src/main/scala/akka/actor/Scheduler.scala @@ -22,7 +22,6 @@ import java.util.concurrent._ import java.lang.RuntimeException object Scheduler { - import Actor._ case class SchedulerException(msg: String, e: Throwable) extends AkkaException(msg, e) diff --git a/akka-actor/src/main/scala/akka/actor/Supervisor.scala b/akka-actor/src/main/scala/akka/actor/Supervisor.scala index 5063ca994a..95532e8fb7 100644 --- a/akka-actor/src/main/scala/akka/actor/Supervisor.scala +++ b/akka-actor/src/main/scala/akka/actor/Supervisor.scala @@ -10,10 +10,11 @@ import ReflectiveAccess._ import Actor._ import java.util.concurrent.{ CopyOnWriteArrayList, ConcurrentHashMap } -import java.net.InetSocketAddress import akka.config.Supervision._ -class SupervisorException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) +class SupervisorException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) { + def this(msg:String) = this(msg, null); +} /** * Factory object for creating supervisors declarative. It creates instances of the 'Supervisor' class. diff --git a/akka-actor/src/main/scala/akka/cluster/ClusterInterface.scala b/akka-actor/src/main/scala/akka/cluster/ClusterInterface.scala index 690a69841f..f59d2ff4ab 100644 --- a/akka-actor/src/main/scala/akka/cluster/ClusterInterface.scala +++ b/akka-actor/src/main/scala/akka/cluster/ClusterInterface.scala @@ -10,18 +10,14 @@ import akka.actor._ import DeploymentConfig._ import akka.dispatch.Future import akka.config.Config -import akka.util._ import akka.routing.RouterType import akka.AkkaException import com.eaio.uuid.UUID import java.net.InetSocketAddress -import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger } -import java.util.concurrent.{ ConcurrentSkipListSet, ConcurrentHashMap } +import java.util.concurrent.{ ConcurrentSkipListSet} -import scala.collection.mutable.ConcurrentMap -import scala.collection.JavaConversions._ class ClusterException(message: String) extends AkkaException(message) diff --git a/akka-actor/src/main/scala/akka/config/Config.scala b/akka-actor/src/main/scala/akka/config/Config.scala index 0c1505ae21..40f84a30d2 100644 --- a/akka-actor/src/main/scala/akka/config/Config.scala +++ b/akka-actor/src/main/scala/akka/config/Config.scala @@ -10,8 +10,13 @@ import java.net.InetAddress import com.eaio.uuid.UUID -class ConfigurationException(message: String, cause: Throwable = null) extends AkkaException(message, cause) -class ModuleNotAvailableException(message: String, cause: Throwable = null) extends AkkaException(message, cause) +class ConfigurationException(message: String, cause: Throwable = null) extends AkkaException(message, cause) { + def this(msg:String) = this(msg, null); +} + +class ModuleNotAvailableException(message: String, cause: Throwable = null) extends AkkaException(message, cause) { + def this(msg:String) = this(msg, null); +} /** * Loads up the configuration (from the akka.conf file). diff --git a/akka-cluster/src/main/scala/akka/cluster/TransactionLog.scala b/akka-cluster/src/main/scala/akka/cluster/TransactionLog.scala index ae98e6848e..2261829934 100644 --- a/akka-cluster/src/main/scala/akka/cluster/TransactionLog.scala +++ b/akka-cluster/src/main/scala/akka/cluster/TransactionLog.scala @@ -14,17 +14,16 @@ import akka.config._ import Config._ import akka.util._ import akka.actor._ -import DeploymentConfig.{ ReplicationScheme, ReplicationStrategy, Transient, WriteThrough, WriteBehind } +import DeploymentConfig.{ ReplicationScheme} import akka.event.EventHandler import akka.dispatch.{ DefaultPromise, Promise, MessageInvocation } import akka.remote.MessageSerializer import akka.cluster.zookeeper._ -import akka.serialization.{ Serializer, Serialization, Compression } +import akka.serialization.Compression import Compression.LZF import akka.serialization.ActorSerialization._ import java.util.Enumeration -import java.util.concurrent.atomic.AtomicLong // FIXME allow user to choose dynamically between 'async' and 'sync' tx logging (asyncAddEntry(byte[] data, AddCallback cb, Object ctx)) // FIXME clean up old entries in log after doing a snapshot diff --git a/akka-cluster/src/main/scala/akka/cluster/storage/Storage.scala b/akka-cluster/src/main/scala/akka/cluster/storage/Storage.scala index ef7b1a1aa4..0129c39eb0 100755 --- a/akka-cluster/src/main/scala/akka/cluster/storage/Storage.scala +++ b/akka-cluster/src/main/scala/akka/cluster/storage/Storage.scala @@ -118,23 +118,31 @@ class VersionedData(val data: Array[Byte], val version: Long) {} /** * An AkkaException thrown by the Storage module. */ -class StorageException(msg: String = null, cause: java.lang.Throwable = null) extends AkkaException(msg, cause) +class StorageException(msg: String = null, cause: java.lang.Throwable = null) extends AkkaException(msg, cause){ + def this(msg:String) = this(msg, null); +} /** * * * A StorageException thrown when an operation is done on a non existing node. */ -class MissingDataException(msg: String = null, cause: java.lang.Throwable = null) extends StorageException(msg, cause) +class MissingDataException(msg: String = null, cause: java.lang.Throwable = null) extends StorageException(msg, cause) { + def this(msg:String) = this(msg, null); +} /** * A StorageException thrown when an operation is done on an existing node, but no node was expected. */ -class DataExistsException(msg: String = null, cause: java.lang.Throwable = null) extends StorageException(msg, cause) +class DataExistsException(msg: String = null, cause: java.lang.Throwable = null) extends StorageException(msg, cause){ + def this(msg:String) = this(msg, null); +} /** * A StorageException thrown when an operation causes an optimistic locking failure. */ -class BadVersionException(msg: String = null, cause: java.lang.Throwable = null) extends StorageException(msg, cause) +class BadVersionException(msg: String = null, cause: java.lang.Throwable = null) extends StorageException(msg, cause) { + def this(msg:String) = this(msg, null); +} /** * A Storage implementation based on ZooKeeper. diff --git a/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala b/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala index 863e2b4917..b676e9f254 100644 --- a/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala +++ b/akka-cluster/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala @@ -47,7 +47,9 @@ import java.util.concurrent.atomic.{AtomicReference, AtomicBoolean} import java.util.concurrent._ import akka.AkkaException -class RemoteClientMessageBufferException(message: String, cause: Throwable = null) extends AkkaException(message, cause) +class RemoteClientMessageBufferException(message: String, cause: Throwable = null) extends AkkaException(message, cause){ + def this(msg:String) = this(msg, null); +} object RemoteEncoder { def encode(rmp: RemoteMessageProtocol): AkkaRemoteProtocol = { diff --git a/akka-durable-mailboxes/akka-beanstalk-mailbox/src/main/scala/akka/actor/mailbox/BeanstalkBasedMailbox.scala b/akka-durable-mailboxes/akka-beanstalk-mailbox/src/main/scala/akka/actor/mailbox/BeanstalkBasedMailbox.scala index 35ec40edee..8138d04b14 100644 --- a/akka-durable-mailboxes/akka-beanstalk-mailbox/src/main/scala/akka/actor/mailbox/BeanstalkBasedMailbox.scala +++ b/akka-durable-mailboxes/akka-beanstalk-mailbox/src/main/scala/akka/actor/mailbox/BeanstalkBasedMailbox.scala @@ -15,7 +15,7 @@ import akka.event.EventHandler import com.surftools.BeanstalkClient._ import com.surftools.BeanstalkClientImpl._ -class BeanstalkBasedMailboxException(message: String) extends AkkaException(message) +class BeanstalkBasedMailboxException(message: String) extends AkkaException(message) {} /** * @author Jonas Bonér diff --git a/akka-stm/src/main/scala/akka/transactor/Coordinated.scala b/akka-stm/src/main/scala/akka/transactor/Coordinated.scala index a43cf39786..bd50926d72 100644 --- a/akka-stm/src/main/scala/akka/transactor/Coordinated.scala +++ b/akka-stm/src/main/scala/akka/transactor/Coordinated.scala @@ -17,7 +17,9 @@ import org.multiverse.api.exceptions.ControlFlowError /** * Akka-specific exception for coordinated transactions. */ -class CoordinatedTransactionException(message: String, cause: Throwable = null) extends AkkaException(message, cause) +class CoordinatedTransactionException(message: String, cause: Throwable = null) extends AkkaException(message, cause){ + def this(msg:String) = this(msg, null); +} /** * Coordinated transactions across actors. From 374f5dc4dc28a4df1553d119156535bb132cca49 Mon Sep 17 00:00:00 2001 From: viktorklang Date: Mon, 25 Jul 2011 04:55:01 -0700 Subject: [PATCH 51/51] Added docs for Amazon Elastic Beanstalk --- akka-docs/scala/http.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/akka-docs/scala/http.rst b/akka-docs/scala/http.rst index ba25234f93..44448b14fc 100644 --- a/akka-docs/scala/http.rst +++ b/akka-docs/scala/http.rst @@ -1,4 +1,3 @@ - .. _http-module: HTTP @@ -462,4 +461,7 @@ Using the Akka Mist module with the Facebook Graph API and WebGL Example project using Akka Mist with the Facebook Graph API and WebGL ``_ +Using Akka Mist on Amazon ElasticBeanstalk +****************************************** +``_