Make sure Serialization.currentTransportInformation is always set, #25067

* The ThreadLocal Serialization.currentTransportInformation is used for serializing local
  actor refs, but it's also useful when a serializer library e.g. custom serializer/deserializer
  in Jackson need access to the current ActorSystem.
* We set this in a rather ad-hoc way from remoting and in some persistence plugins, but it's only
  set for serialization and not deserialization, and it's easy for Persistence plugins or other
  libraries to forget this when using Akka serialization directly.
* This change is automatically setting the info when using the ordinary serialize and deserialize
  methods.
* It's also set when LocalActorRefProvider, which wasn't always the case previously.
* Keep a cached instance of Serialization.Information in the provider to avoid
  creating new instances all the time.
* Added optional Persistence TCK tests to verify that the plugin is setting this
  if it's using some custom calls to the serializer.
This commit is contained in:
Patrik Nordwall 2018-05-21 16:59:04 +02:00 committed by GitHub
parent 6ec46e762f
commit e6633f17fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 579 additions and 146 deletions

View file

@ -10,11 +10,9 @@ import akka.dispatch.sysmsg._
import akka.event.{ EventStream, Logging, LoggingAdapter }
import akka.event.Logging.Error
import akka.pattern.pipe
import scala.util.control.NonFatal
import akka.actor.SystemGuardian.{ RegisterTerminationHook, TerminationHook, TerminationHookDone }
import scala.util.control.Exception.Catcher
import scala.concurrent.Future
@ -29,6 +27,7 @@ import akka.remote.artery.OutboundEnvelope
import akka.remote.artery.SystemMessageDelivery.SystemMessageEnvelope
import akka.remote.serialization.ActorRefResolveThreadLocalCache
import akka.remote.artery.tcp.ArteryTcpTransport
import akka.serialization.Serialization
/**
* INTERNAL API
@ -475,6 +474,21 @@ private[akka] class RemoteActorRefProvider(
def getDefaultAddress: Address = transport.defaultAddress
// no need for volatile, only intended as cached value, not necessarily a singleton value
private var serializationInformationCache: OptionVal[Serialization.Information] = OptionVal.None
@InternalApi override private[akka] def serializationInformation: Serialization.Information =
serializationInformationCache match {
case OptionVal.Some(info) info
case OptionVal.None
if ((transport eq null) || (transport.defaultAddress eq null))
local.serializationInformation // address not know yet, access before complete init and binding
else {
val info = Serialization.Information(transport.defaultAddress, transport.system)
serializationInformationCache = OptionVal.Some(info)
info
}
}
private def hasAddress(address: Address): Boolean =
address == local.rootPath.address || address == rootPath.address || transport.addresses(address)
@ -508,6 +522,9 @@ private[akka] class RemoteActorRef private[akka] (
deploy: Option[Deploy])
extends InternalActorRef with RemoteRef {
if (path.address.hasLocalScope)
throw new IllegalArgumentException(s"Unexpected local address in RemoteActorRef [$this]")
remote match {
case t: ArteryTransport
// detect mistakes such as using "akka.tcp" with Artery