Created
May 29, 2012 04:38
-
-
Save havocp/2822571 to your computer and use it in GitHub Desktop.
set the 'actor' field in ActorCell mid-actor-construction rather than post-construction
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala | |
index f268b8f..2db8956 100644 | |
--- a/akka-actor/src/main/scala/akka/actor/Actor.scala | |
+++ b/akka-actor/src/main/scala/akka/actor/Actor.scala | |
@@ -304,6 +304,10 @@ trait Actor { | |
*/ | |
implicit final val self = context.self //MUST BE A VAL, TRUST ME | |
+ // this will call back to receive and aroundReceive so do it | |
+ // only after we set up `context` and `self` | |
+ context.setInstance(this) | |
+ | |
/** | |
* The reference sender Actor of the last received message. | |
* Is defined if the message was sent from another Actor, | |
diff --git a/akka-actor/src/main/scala/akka/actor/ActorCell.scala b/akka-actor/src/main/scala/akka/actor/ActorCell.scala | |
index 52da820..3c17bd5 100644 | |
--- a/akka-actor/src/main/scala/akka/actor/ActorCell.scala | |
+++ b/akka-actor/src/main/scala/akka/actor/ActorCell.scala | |
@@ -140,6 +140,11 @@ trait ActorContext extends ActorRefFactory { | |
*/ | |
final protected def writeObject(o: ObjectOutputStream): Unit = | |
throw new NotSerializableException("ActorContext is not serializable!") | |
+ | |
+ /** | |
+ * Internal to Akka, called on each construction of the actor instance. | |
+ */ | |
+ private[actor] def setInstance(instance: Actor): Unit | |
} | |
/** | |
@@ -186,8 +191,6 @@ private[akka] object ActorCell { | |
final val emptyReceiveTimeoutData: (Long, Cancellable) = (-1, emptyCancellable) | |
- final val behaviorStackPlaceHolder: Stack[Actor.Receive] = Stack.empty.push(Actor.emptyBehavior) | |
- | |
sealed trait SuspendReason | |
case object UserRequest extends SuspendReason | |
case class Recreation(cause: Throwable) extends SuspendReason | |
@@ -492,23 +495,24 @@ private[akka] class ActorCell( | |
case _ ⇒ system.deadLetters | |
} | |
+ private[actor] def setInstance(instance: Actor): Unit = { | |
+ // this code runs at the start of Actor construction, should make | |
+ // the ActorCell valid so Actor construction can use its context | |
+ actor = instance | |
+ behaviorStack = behaviorStack.push(actor.aroundReceive(actor.receive)) | |
+ } | |
+ | |
//This method is in charge of setting up the contextStack and create a new instance of the Actor | |
- protected def newActor(): Actor = { | |
+ protected def createActor(): Unit = { | |
contextStack.set(contextStack.get.push(this)) | |
try { | |
- import ActorCell.behaviorStackPlaceHolder | |
- | |
- behaviorStack = behaviorStackPlaceHolder | |
+ behaviorStack = Stack.empty | |
val instance = props.creator.apply() | |
+ require(instance eq actor) | |
if (instance eq null) | |
throw new ActorInitializationException(self, "Actor instance passed to actorOf can't be 'null'") | |
- behaviorStack = behaviorStack match { | |
- case `behaviorStackPlaceHolder` ⇒ Stack.empty.push(instance.receive) | |
- case newBehaviors ⇒ Stack.empty.push(instance.receive).pushAll(newBehaviors.reverse.drop(1)) | |
- } | |
- behaviorStack = behaviorStack.map(instance.aroundReceive(_)) | |
instance | |
} finally { | |
val stackAfter = contextStack.get | |
@@ -522,11 +526,10 @@ private[akka] class ActorCell( | |
def create(): Unit = if (isNormal) { | |
try { | |
- val created = newActor() | |
- actor = created | |
- created.preStart() | |
+ createActor() | |
+ actor.preStart() | |
checkReceiveTimeout | |
- if (system.settings.DebugLifecycle) system.eventStream.publish(Debug(self.path.toString, clazz(created), "started (" + created + ")")) | |
+ if (system.settings.DebugLifecycle) system.eventStream.publish(Debug(self.path.toString, clazz(actor), "started (" + actor + ")")) | |
} catch { | |
case NonFatal(i: InstantiationException) ⇒ | |
throw new ActorInitializationException(self, | |
@@ -649,12 +652,7 @@ private[akka] class ActorCell( | |
def become(behavior: Actor.Receive, discardOld: Boolean = true): Unit = { | |
if (discardOld) unbecome() | |
- // actor is null during construction of the actor | |
- val wrappedBehavior = if (actor ne null) | |
- actor.aroundReceive(behavior) | |
- else | |
- behavior | |
- behaviorStack = behaviorStack.push(wrappedBehavior) | |
+ behaviorStack = behaviorStack.push(actor.aroundReceive(behavior)) | |
} | |
/** | |
@@ -709,7 +707,7 @@ private[akka] class ActorCell( | |
if (system.settings.DebugLifecycle) | |
system.eventStream.publish(Debug(self.path.toString, clazz(actor), "stopped")) | |
} finally { | |
- behaviorStack = ActorCell.behaviorStackPlaceHolder | |
+ behaviorStack = Stack.empty | |
clearActorFields(a) | |
actor = null | |
} | |
@@ -719,12 +717,16 @@ private[akka] class ActorCell( | |
private def doRecreate(cause: Throwable, failedActor: Actor): Unit = try { | |
// after all killed children have terminated, recreate the rest, then go on to start the new instance | |
actor.supervisorStrategy.handleSupervisorRestarted(cause, self, children) | |
- val freshActor = newActor() | |
- actor = freshActor // this must happen before postRestart has a chance to fail | |
- if (freshActor eq failedActor) setActorFields(freshActor, this, self) // If the creator returns the same instance, we need to restore our nulled out fields. | |
+ createActor() | |
+ if (actor eq failedActor) { | |
+ // If the creator returns the same instance, we need to restore our nulled out fields | |
+ // and fill in the behavior stack. | |
+ setActorFields(actor, this, self) | |
+ setInstance(actor) | |
+ } | |
- freshActor.postRestart(cause) | |
- if (system.settings.DebugLifecycle) system.eventStream.publish(Debug(self.path.toString, clazz(freshActor), "restarted")) | |
+ actor.postRestart(cause) | |
+ if (system.settings.DebugLifecycle) system.eventStream.publish(Debug(self.path.toString, clazz(actor), "restarted")) | |
dispatcher.resume(this) | |
} catch { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment