diff --git a/akka-actor/src/main/java/akka/util/internal/HashedWheelTimer.java b/akka-actor/src/main/java/akka/util/internal/HashedWheelTimer.java index e95ff9ad95..73b3cf143d 100644 --- a/akka-actor/src/main/java/akka/util/internal/HashedWheelTimer.java +++ b/akka-actor/src/main/java/akka/util/internal/HashedWheelTimer.java @@ -24,6 +24,7 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import akka.util.Helpers; import scala.concurrent.duration.Duration; import scala.concurrent.duration.FiniteDuration; import akka.event.LoggingAdapter; @@ -91,7 +92,6 @@ public class HashedWheelTimer implements Timer { final ReusableIterator[] iterators; final int mask; final ReadWriteLock lock = new ReentrantReadWriteLock(); - final boolean isWindows = System.getProperty("os.name", "").toLowerCase().indexOf("win") >= 0; volatile int wheelCursor; private LoggingAdapter logger; @@ -396,7 +396,7 @@ public class HashedWheelTimer implements Timer { // the JVM if it runs on windows. // // See https://github.com/netty/netty/issues/356 - if (isWindows) { + if (Helpers.isWindows()) { sleepTimeMs = (sleepTimeMs / 10) * 10; } diff --git a/akka-actor/src/main/scala/akka/util/Helpers.scala b/akka-actor/src/main/scala/akka/util/Helpers.scala index 8c0cfec86c..430d4582ae 100644 --- a/akka-actor/src/main/scala/akka/util/Helpers.scala +++ b/akka-actor/src/main/scala/akka/util/Helpers.scala @@ -9,6 +9,8 @@ import java.util.regex.Pattern object Helpers { + val isWindows: Boolean = System.getProperty("os.name", "").toLowerCase.indexOf("win") >= 0 + def makePattern(s: String): Pattern = Pattern.compile("^\\Q" + s.replace("?", "\\E.\\Q").replace("*", "\\E.*\\Q") + "\\E$") def compareIdentityHash(a: AnyRef, b: AnyRef): Int = { diff --git a/akka-remote-tests/src/main/scala/akka/remote/testconductor/RemoteConnection.scala b/akka-remote-tests/src/main/scala/akka/remote/testconductor/RemoteConnection.scala index db212e7cbf..adca9518b4 100644 --- a/akka-remote-tests/src/main/scala/akka/remote/testconductor/RemoteConnection.scala +++ b/akka-remote-tests/src/main/scala/akka/remote/testconductor/RemoteConnection.scala @@ -13,6 +13,7 @@ import org.jboss.netty.handler.timeout.{ ReadTimeoutHandler, ReadTimeoutExceptio import java.net.InetSocketAddress import java.util.concurrent.Executors import akka.event.Logging +import akka.util.Helpers /** * INTERNAL API. @@ -59,7 +60,7 @@ private[akka] object RemoteConnection { poolSize) val bootstrap = new ServerBootstrap(socketfactory) bootstrap.setPipelineFactory(new TestConductorPipelineFactory(handler)) - bootstrap.setOption("reuseAddress", true) + bootstrap.setOption("reuseAddress", !Helpers.isWindows) bootstrap.setOption("child.tcpNoDelay", true) bootstrap.bind(sockaddr) } diff --git a/akka-remote/src/main/resources/reference.conf b/akka-remote/src/main/resources/reference.conf index bb91d1a34c..61bcecf03e 100644 --- a/akka-remote/src/main/resources/reference.conf +++ b/akka-remote/src/main/resources/reference.conf @@ -141,6 +141,11 @@ akka { # (I) Sets the size of the connection backlog backlog = 4096 + # (I) Sets the SO_REUSE_ADDR flag, valid values are "on", "off" and "off-for-windows" + # due to the following Windows bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4476378 + # "off-for-windows" of course means that it's "on" for all other platforms + reuse-address = off-for-windows + # (I) Length in akka.time-unit how long core threads will be kept alive if # idling execution-pool-keepalive = 60s diff --git a/akka-remote/src/main/scala/akka/remote/netty/Server.scala b/akka-remote/src/main/scala/akka/remote/netty/Server.scala index 15ca143bf8..8de51a48b1 100644 --- a/akka-remote/src/main/scala/akka/remote/netty/Server.scala +++ b/akka-remote/src/main/scala/akka/remote/netty/Server.scala @@ -37,7 +37,7 @@ private[akka] class NettyRemoteServer(val netty: NettyRemoteTransport) { b.setOption("backlog", settings.Backlog) b.setOption("tcpNoDelay", true) b.setOption("child.keepAlive", true) - b.setOption("reuseAddress", true) + b.setOption("reuseAddress", settings.ReuseAddress) settings.ReceiveBufferSize.foreach(sz ⇒ b.setOption("receiveBufferSize", sz)) settings.SendBufferSize.foreach(sz ⇒ b.setOption("sendBufferSize", sz)) settings.WriteBufferHighWaterMark.foreach(sz ⇒ b.setOption("writeBufferHighWaterMark", sz)) diff --git a/akka-remote/src/main/scala/akka/remote/netty/Settings.scala b/akka-remote/src/main/scala/akka/remote/netty/Settings.scala index 5852f7a3ca..b02b0297d8 100644 --- a/akka-remote/src/main/scala/akka/remote/netty/Settings.scala +++ b/akka-remote/src/main/scala/akka/remote/netty/Settings.scala @@ -11,6 +11,7 @@ import akka.ConfigurationException import akka.japi.Util.immutableSeq import scala.concurrent.duration.FiniteDuration import akka.dispatch.ThreadPoolConfig +import akka.util.Helpers private[akka] class NettySettings(config: Config, val systemName: String) { @@ -72,6 +73,11 @@ private[akka] class NettySettings(config: Config, val systemName: String) { val Backlog: Int = getInt("backlog") + val ReuseAddress: Boolean = getString("reuse-address") match { + case "off-for-windows" ⇒ !Helpers.isWindows + case _ ⇒ getBoolean("reuse-address") + } + val ExecutionPoolKeepalive: FiniteDuration = Duration(getMilliseconds("execution-pool-keepalive"), MILLISECONDS) val ExecutionPoolSize: Int = getInt("execution-pool-size") match { diff --git a/akka-remote/src/test/scala/akka/remote/RemoteConfigSpec.scala b/akka-remote/src/test/scala/akka/remote/RemoteConfigSpec.scala index 45b6ad5610..1f2d5e5e96 100644 --- a/akka-remote/src/test/scala/akka/remote/RemoteConfigSpec.scala +++ b/akka-remote/src/test/scala/akka/remote/RemoteConfigSpec.scala @@ -9,6 +9,7 @@ import akka.testkit.AkkaSpec import akka.actor.ExtendedActorSystem import scala.concurrent.duration._ import akka.remote.netty.NettyRemoteTransport +import akka.util.Helpers @org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) class RemoteConfigSpec extends AkkaSpec( @@ -49,6 +50,7 @@ class RemoteConfigSpec extends AkkaSpec( MessageFrameSize must be(1048576) ConnectionTimeout must be(2 minutes) Backlog must be(4096) + ReuseAddress must be(!Helpers.isWindows) ExecutionPoolKeepalive must be(1 minute) ExecutionPoolSize must be(4) MaxChannelMemorySize must be(0) @@ -88,6 +90,10 @@ class RemoteConfigSpec extends AkkaSpec( pool.getDouble("pool-size-factor") must equal(1.0) pool.getInt("pool-size-max") must equal(8) } + + { + c.getString("reuse-address") must be("off-for-windows") + } } } }