From 6240acf25e4292e708f6563bd324f256ea1e0a5f Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Sat, 4 Jun 2016 21:44:13 +0200 Subject: [PATCH] improve performance of serializer lookup by id * Map.apply allocates Some --- .../akka/serialization/Serialization.scala | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/akka-actor/src/main/scala/akka/serialization/Serialization.scala b/akka-actor/src/main/scala/akka/serialization/Serialization.scala index 673fee3706..9889759455 100644 --- a/akka-actor/src/main/scala/akka/serialization/Serialization.scala +++ b/akka-actor/src/main/scala/akka/serialization/Serialization.scala @@ -17,6 +17,7 @@ import scala.util.Success import java.nio.ByteBuffer import java.util.concurrent.atomic.AtomicReference import scala.annotation.tailrec +import java.util.NoSuchElementException object Serialization { @@ -101,7 +102,7 @@ class Serialization(val system: ExtendedActorSystem) extends Extension { */ def deserialize[T](bytes: Array[Byte], serializerId: Int, clazz: Option[Class[_ <: T]]): Try[T] = Try { - val serializer = try serializerByIdentity(serializerId) catch { + val serializer = try getSerializerById(serializerId) catch { case _: NoSuchElementException ⇒ throw new NotSerializableException( s"Cannot find serializer with id [$serializerId]. The most probable reason is that the configuration entry " + "akka.actor.serializers is not in synch between the two systems.") @@ -116,7 +117,7 @@ class Serialization(val system: ExtendedActorSystem) extends Extension { */ def deserialize(bytes: Array[Byte], serializerId: Int, manifest: String): Try[AnyRef] = Try { - val serializer = try serializerByIdentity(serializerId) catch { + val serializer = try getSerializerById(serializerId) catch { case _: NoSuchElementException ⇒ throw new NotSerializableException( s"Cannot find serializer with id [$serializerId]. The most probable reason is that the configuration entry " + "akka.actor.serializers is not in synch between the two systems.") @@ -161,7 +162,7 @@ class Serialization(val system: ExtendedActorSystem) extends Extension { * Returns either the resulting object or throws an exception if deserialization fails. */ def deserializeByteBuffer(buf: ByteBuffer, serializerId: Int, manifest: String): AnyRef = { - val serializer = try serializerByIdentity(serializerId) catch { + val serializer = try getSerializerById(serializerId) catch { case _: NoSuchElementException ⇒ throw new NotSerializableException( s"Cannot find serializer with id [$serializerId]. The most probable reason is that the configuration entry " + "akka.actor.serializers is not in synch between the two systems.") @@ -288,6 +289,31 @@ class Serialization(val system: ExtendedActorSystem) extends Extension { val serializerByIdentity: Map[Int, Serializer] = Map(NullSerializer.identifier → NullSerializer) ++ serializers map { case (_, v) ⇒ (v.identifier, v) } + /** + * Serializers with id 0 - 1023 are stored in an array for quick allocation free access + */ + private val quickSerializerByIdentity: Array[Serializer] = { + val size = 1024 + val table = Array.ofDim[Serializer](size) + serializerByIdentity.foreach { + case (id, ser) ⇒ if (0 <= id && id < size) table(id) = ser + } + table + } + + /** + * @throws `NoSuchElementException` if no serializer with given `id` + */ + private def getSerializerById(id: Int): Serializer = { + if (0 <= id && id < quickSerializerByIdentity.length) { + quickSerializerByIdentity(id) match { + case null ⇒ throw new NoSuchElementException(s"key not found: $id") + case ser ⇒ ser + } + } else + serializerByIdentity(id) + } + private val isJavaSerializationWarningEnabled = settings.config.getBoolean("akka.actor.warn-about-java-serializer-usage") private def shouldWarnAboutJavaSerializer(serializedClass: Class[_], serializer: Serializer) = {