This is an automated email from the ASF dual-hosted git repository.
fanningpj pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko.git
The following commit(s) were added to refs/heads/main by this push:
new e29c133a47 Port akka-core optimizations for typed actor context and
system adapter (#2750)
e29c133a47 is described below
commit e29c133a473eb0b25e86c9ca8546e27749c65a0c
Author: PJ Fanning <[email protected]>
AuthorDate: Wed Mar 18 10:03:10 2026 +0100
Port akka-core optimizations for typed actor context and system adapter
(#2750)
* Initial plan
* Port akka-core PRs 31843 and 31842: optimize typed actor context and
system adapter
Co-authored-by: pjfanning <[email protected]>
* scalafmt
---------
Co-authored-by: copilot-swe-agent[bot]
<[email protected]>
Co-authored-by: pjfanning <[email protected]>
---
.../pekko/actor/typed/MailboxSelectorSpec.scala | 2 +-
.../typed/internal/adapter/ActorAdapter.scala | 2 +-
.../internal/adapter/ActorContextAdapter.scala | 46 +++++++++++-----------
.../internal/adapter/ActorSystemAdapter.scala | 17 +++++++-
.../scala/org/apache/pekko/actor/ActorSystem.scala | 7 ++++
5 files changed, 47 insertions(+), 27 deletions(-)
diff --git
a/actor-typed-tests/src/test/scala/org/apache/pekko/actor/typed/MailboxSelectorSpec.scala
b/actor-typed-tests/src/test/scala/org/apache/pekko/actor/typed/MailboxSelectorSpec.scala
index 36a029a634..0b7bfbb04f 100644
---
a/actor-typed-tests/src/test/scala/org/apache/pekko/actor/typed/MailboxSelectorSpec.scala
+++
b/actor-typed-tests/src/test/scala/org/apache/pekko/actor/typed/MailboxSelectorSpec.scala
@@ -45,7 +45,7 @@ class MailboxSelectorSpec extends
ScalaTestWithActorTestKit("""
case WhatsYourMailbox(replyTo) =>
val mailbox = context match {
case adapter: ActorContextAdapter[_] =>
- adapter.classicContext match {
+ adapter.classicActorContext match {
case cell: ActorCell =>
cell.mailbox.messageQueue
case unexpected => throw new RuntimeException(s"Unexpected:
$unexpected")
diff --git
a/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorAdapter.scala
b/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorAdapter.scala
index da1604cd3b..872cfc4298 100644
---
a/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorAdapter.scala
+++
b/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorAdapter.scala
@@ -72,7 +72,7 @@ import pekko.util.OptionVal
// when the adapter is used for the user guardian (which avoids touching
context until it is safe)
private var _ctx: ActorContextAdapter[T] = _
def ctx: ActorContextAdapter[T] = {
- if (_ctx eq null) _ctx = new ActorContextAdapter[T](context, this)
+ if (_ctx eq null) _ctx = new ActorContextAdapter[T](this)
_ctx
}
diff --git
a/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorContextAdapter.scala
b/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorContextAdapter.scala
index 018d5c1e72..95be6cd5de 100644
---
a/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorContextAdapter.scala
+++
b/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorContextAdapter.scala
@@ -28,7 +28,7 @@ private[pekko] object ActorContextAdapter {
private def toClassicImp[U](context: TypedActorContext[_]):
classic.ActorContext =
context match {
- case adapter: ActorContextAdapter[_] => adapter.classicContext
+ case adapter: ActorContextAdapter[_] => adapter.classicActorContext
case _ =>
throw new UnsupportedOperationException(
"Only adapted classic ActorContext permissible " +
@@ -45,9 +45,7 @@ private[pekko] object ActorContextAdapter {
/**
* INTERNAL API. Wrapping an [[pekko.actor.ActorContext]] as an
[[TypedActorContext]].
*/
-@InternalApi private[pekko] final class ActorContextAdapter[T](
- val classicContext: classic.ActorContext,
- adapter: ActorAdapter[T])
+@InternalApi private[pekko] final class ActorContextAdapter[T](adapter:
ActorAdapter[T])
extends ActorContextImpl[T] {
import ActorRefAdapter.toClassic
@@ -60,28 +58,28 @@ private[pekko] object ActorContextAdapter {
private var _self: OptionVal[ActorRef[T]] = OptionVal.None
override def self: ActorRef[T] = {
if (_self.isEmpty) {
- _self = OptionVal.Some(ActorRefAdapter(classicContext.self))
+ _self = OptionVal.Some(ActorRefAdapter(classicActorContext.self))
}
_self.get
}
- final override val system = ActorSystemAdapter(classicContext.system)
- private[pekko] def classicActorContext = classicContext
+ override def system = ActorSystemAdapter(classicActorContext.system)
+ private[pekko] def classicActorContext = adapter.context
override def children: Iterable[ActorRef[Nothing]] = {
checkCurrentActorThread()
- classicContext.children.map(ActorRefAdapter(_))
+ classicActorContext.children.map(ActorRefAdapter(_))
}
override def child(name: String): Option[ActorRef[Nothing]] = {
checkCurrentActorThread()
- classicContext.child(name).map(ActorRefAdapter(_))
+ classicActorContext.child(name).map(ActorRefAdapter(_))
}
override def spawnAnonymous[U](behavior: Behavior[U], props: Props =
Props.empty): ActorRef[U] = {
checkCurrentActorThread()
- ActorRefFactoryAdapter.spawnAnonymous(classicContext, behavior, props,
rethrowTypedFailure = true)
+ ActorRefFactoryAdapter.spawnAnonymous(classicActorContext, behavior,
props, rethrowTypedFailure = true)
}
override def spawn[U](behavior: Behavior[U], name: String, props: Props =
Props.empty): ActorRef[U] = {
checkCurrentActorThread()
- ActorRefFactoryAdapter.spawn(classicContext, behavior, name, props,
rethrowTypedFailure = true)
+ ActorRefFactoryAdapter.spawn(classicActorContext, behavior, name, props,
rethrowTypedFailure = true)
}
override def stop[U](child: ActorRef[U]): Unit = {
@@ -89,12 +87,12 @@ private[pekko] object ActorContextAdapter {
if (child.path.parent == self.path) { // only if a direct child
toClassic(child) match {
case f: pekko.actor.FunctionRef =>
- val cell = classicContext.asInstanceOf[pekko.actor.ActorCell]
+ val cell = classicActorContext.asInstanceOf[pekko.actor.ActorCell]
cell.removeFunctionRef(f)
case c =>
- classicContext.child(child.path.name) match {
+ classicActorContext.child(child.path.name) match {
case Some(`c`) =>
- classicContext.stop(c)
+ classicActorContext.stop(c)
case _ =>
// child that was already stopped
}
@@ -115,37 +113,37 @@ private[pekko] object ActorContextAdapter {
override def watch[U](other: ActorRef[U]): Unit = {
checkCurrentActorThread()
- classicContext.watch(toClassic(other))
+ classicActorContext.watch(toClassic(other))
}
override def watchWith[U](other: ActorRef[U], msg: T): Unit = {
checkCurrentActorThread()
- classicContext.watchWith(toClassic(other), msg)
+ classicActorContext.watchWith(toClassic(other), msg)
}
override def unwatch[U](other: ActorRef[U]): Unit = {
checkCurrentActorThread()
- classicContext.unwatch(toClassic(other))
+ classicActorContext.unwatch(toClassic(other))
}
var receiveTimeoutMsg: T = null.asInstanceOf[T]
override def setReceiveTimeout(d: FiniteDuration, msg: T): Unit = {
checkCurrentActorThread()
receiveTimeoutMsg = msg
- classicContext.setReceiveTimeout(d)
+ classicActorContext.setReceiveTimeout(d)
}
override def cancelReceiveTimeout(): Unit = {
checkCurrentActorThread()
receiveTimeoutMsg = null.asInstanceOf[T]
- classicContext.setReceiveTimeout(Duration.Undefined)
+ classicActorContext.setReceiveTimeout(Duration.Undefined)
}
- override def executionContext: ExecutionContextExecutor =
classicContext.dispatcher
+ override def executionContext: ExecutionContextExecutor =
classicActorContext.dispatcher
override def scheduleOnce[U](delay: FiniteDuration, target: ActorRef[U],
msg: U): classic.Cancellable = {
- import classicContext.dispatcher
- classicContext.system.scheduler.scheduleOnce(delay, toClassic(target), msg)
+ classicActorContext.system.scheduler.scheduleOnce(delay,
toClassic(target), msg)(classicActorContext.dispatcher)
}
override private[pekko] def internalSpawnMessageAdapter[U](f: U => T, _name:
String): ActorRef[U] = {
- val cell = classicContext.asInstanceOf[pekko.actor.ActorCell]
+ val cell = classicActorContext.asInstanceOf[pekko.actor.ActorCell]
// apply the function inside the actor by wrapping the msg and f, handled
by ActorAdapter
- val ref = cell.addFunctionRef((_, msg) => classicContext.self !
AdaptMessage[U, T](msg.asInstanceOf[U], f), _name)
+ val ref =
+ cell.addFunctionRef((_, msg) => classicActorContext.self !
AdaptMessage[U, T](msg.asInstanceOf[U], f), _name)
ActorRefAdapter[U](ref)
}
diff --git
a/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorSystemAdapter.scala
b/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorSystemAdapter.scala
index 2cf322c878..7c9bfb6ca8 100644
---
a/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorSystemAdapter.scala
+++
b/actor-typed/src/main/scala/org/apache/pekko/actor/typed/internal/adapter/ActorSystemAdapter.scala
@@ -41,6 +41,7 @@ import
pekko.actor.typed.internal.PropsImpl.DispatcherSameAsParent
import pekko.actor.typed.internal.SystemMessage
import pekko.actor.typed.scaladsl.Behaviors
import pekko.annotation.InternalApi
+import pekko.util.OptionVal
import org.slf4j.{ Logger, LoggerFactory }
@@ -141,7 +142,21 @@ import org.slf4j.{ Logger, LoggerFactory }
}
private[pekko] object ActorSystemAdapter {
- def apply(system: classic.ActorSystem): ActorSystem[Nothing] =
AdapterExtension(system).adapter
+ def apply(system: classic.ActorSystem): ActorSystem[Nothing] = {
+ system match {
+ case system: classic.ActorSystemImpl =>
+ // Optimization to cut out going through adapter lookup if possible
+ system.typedSystem match {
+ case OptionVal.Some(typedSystem: ActorSystem[_]) => typedSystem
+ case _ =>
+ val typedSystem: ActorSystem[_] = AdapterExtension(system).adapter
+ system.typedSystem = OptionVal.Some(typedSystem)
+ typedSystem
+ }
+ case _ =>
+ AdapterExtension(system).adapter
+ }
+ }
// to make sure we do never create more than one adapter for the same actor
system
class AdapterExtension(system: classic.ExtendedActorSystem) extends
classic.Extension {
diff --git a/actor/src/main/scala/org/apache/pekko/actor/ActorSystem.scala
b/actor/src/main/scala/org/apache/pekko/actor/ActorSystem.scala
index 3a6cfe2900..95a263241b 100644
--- a/actor/src/main/scala/org/apache/pekko/actor/ActorSystem.scala
+++ b/actor/src/main/scala/org/apache/pekko/actor/ActorSystem.scala
@@ -848,6 +848,13 @@ private[pekko] class ActorSystemImpl(
private val _dynamicAccess: DynamicAccess = createDynamicAccess()
+ /**
+ * Optimistic optimization: Tries to avoid going through the extension
infrastructure if possible when using
+ * the typed system. Will contain a org.apache.pekko.actor.typed.ActorSystem
if set, should not be touched by
+ * anything but the typed ActorSystemAdapter.
+ */
+ private[pekko] var typedSystem: OptionVal[AnyRef] = OptionVal.None
+
final val settings: Settings = {
val config = Settings.amendSlf4jConfig(
applicationConfig.withFallback(ConfigFactory.defaultReference(classLoader)),
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]