From ec7772b7869a492f9e37d4fa0298de81a504a5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bone=CC=81r?= Date: Fri, 3 Feb 2012 14:55:16 +0100 Subject: [PATCH] Fixes bug in RandomRouter. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes an interesting "bug" in RandomRouter. Tests failed on my 12 core Linux box. After some investigation I found that it hanged randomly inside the SecureRandom seed generator. [JVM-Node4] "main" prio=10 tid=0x0000000001701000 nid=0x1942 runnable [0x00007fee631dc000] [JVM-Node4] java.lang.Thread.State: RUNNABLE [JVM-Node4] at java.io.FileInputStream.readBytes(Native Method) [JVM-Node4] at java.io.FileInputStream.read(FileInputStream.java:236) [JVM-Node4] at sun.security.provider.SeedGenerator$URLSeedGenerator.getSeedBytes(SeedGenerator.java:509) [JVM-Node4] at sun.security.provider.SeedGenerator.generateSeed(SeedGenerator.java:135) [JVM-Node4] at sun.security.provider.SecureRandom.engineGenerateSeed(SecureRandom.java:131) [JVM-Node4] at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:188) [JVM-Node4] - locked <0x00000007c3d84130> (a sun.security.provider.SecureRandom) [JVM-Node4] at java.security.SecureRandom.nextBytes(SecureRandom.java:450) [JVM-Node4] - locked <0x00000007c3d843d0> (a java.security.SecureRandom) [JVM-Node4] at java.security.SecureRandom.next(SecureRandom.java:472) [JVM-Node4] at java.util.Random.nextInt(Random.java:272) [JVM-Node4] at akka.routing.RandomLike$class.getNext$2(Routing.scala:466) Puzzled at first I Googled the problem and found this bug report: http://bugs.sun.com/view_bug.do?bug_id=6521844 In short it is designed to block on /dev/random (on Linux) when the entropy pool is empty until some "environmental noise is gathered". From the Linux manual: "Hanging at generateSeed is not a bug, since that's what was designed: When the entropy pool is empty, reads from /dev/random will block until additional environmental noise is gathered. (Source: Linux Programmer's Manual, section 4)" Fix was to switch to java.util.Random. Fun one Signed-off-by: Jonas Bonér --- akka-actor/src/main/scala/akka/routing/Routing.scala | 6 +++--- .../akka/remote/DirectRoutedRemoteActorMultiJvmSpec.scala | 1 - .../scala/akka/remote/NewRemoteActorMultiJvmSpec.scala | 2 -- .../akka/remote/RandomRoutedRemoteActorMultiJvmSpec.scala | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/akka-actor/src/main/scala/akka/routing/Routing.scala b/akka-actor/src/main/scala/akka/routing/Routing.scala index 4ef7cff330..ff05a4aac0 100644 --- a/akka-actor/src/main/scala/akka/routing/Routing.scala +++ b/akka-actor/src/main/scala/akka/routing/Routing.scala @@ -448,14 +448,14 @@ case class RandomRouter(nrOfInstances: Int = 0, routees: Iterable[String] = Nil, trait RandomLike { this: RouterConfig ⇒ - import java.security.SecureRandom + import java.util.Random def nrOfInstances: Int def routees: Iterable[String] - private val random = new ThreadLocal[SecureRandom] { - override def initialValue = SecureRandom.getInstance("SHA1PRNG") + private val random = new ThreadLocal[Random] { + override def initialValue = new Random } def createRoute(props: Props, routeeProvider: RouteeProvider): Route = { diff --git a/akka-remote/src/multi-jvm/scala/akka/remote/DirectRoutedRemoteActorMultiJvmSpec.scala b/akka-remote/src/multi-jvm/scala/akka/remote/DirectRoutedRemoteActorMultiJvmSpec.scala index a9422b2b8f..1c7d4b2602 100644 --- a/akka-remote/src/multi-jvm/scala/akka/remote/DirectRoutedRemoteActorMultiJvmSpec.scala +++ b/akka-remote/src/multi-jvm/scala/akka/remote/DirectRoutedRemoteActorMultiJvmSpec.scala @@ -7,7 +7,6 @@ import akka.pattern.ask object DirectRoutedRemoteActorMultiJvmSpec extends AbstractRemoteActorMultiJvmSpec { override def NrOfNodes = 2 -// override def PortRangeStart = 3990 class SomeActor extends Actor with Serializable { def receive = { diff --git a/akka-remote/src/multi-jvm/scala/akka/remote/NewRemoteActorMultiJvmSpec.scala b/akka-remote/src/multi-jvm/scala/akka/remote/NewRemoteActorMultiJvmSpec.scala index 0899b60c6a..a91b203707 100644 --- a/akka-remote/src/multi-jvm/scala/akka/remote/NewRemoteActorMultiJvmSpec.scala +++ b/akka-remote/src/multi-jvm/scala/akka/remote/NewRemoteActorMultiJvmSpec.scala @@ -8,8 +8,6 @@ import akka.pattern.ask object NewRemoteActorMultiJvmSpec extends AbstractRemoteActorMultiJvmSpec { override def NrOfNodes = 2 -// override def PortRangeStart = 2990 - class SomeActor extends Actor with Serializable { def receive = { case "identify" ⇒ sender ! self diff --git a/akka-remote/src/multi-jvm/scala/akka/remote/RandomRoutedRemoteActorMultiJvmSpec.scala b/akka-remote/src/multi-jvm/scala/akka/remote/RandomRoutedRemoteActorMultiJvmSpec.scala index f895708294..bc69b2dd76 100644 --- a/akka-remote/src/multi-jvm/scala/akka/remote/RandomRoutedRemoteActorMultiJvmSpec.scala +++ b/akka-remote/src/multi-jvm/scala/akka/remote/RandomRoutedRemoteActorMultiJvmSpec.scala @@ -76,7 +76,7 @@ class RandomRoutedRemoteActorMultiJvmNode4 extends AkkaRemoteSpec(RandomRoutedRe "be locally instantiated on a remote node and be able to communicate through its RemoteActorRef" in { barrier("start") - val actor = system.actorOf(Props[SomeActor].withRouter(RoundRobinRouter()), "service-hello") + val actor = system.actorOf(Props[SomeActor].withRouter(RandomRouter()), "service-hello") actor.isInstanceOf[RoutedActorRef] must be(true) val connectionCount = NrOfNodes - 1