From 3f5c953edb2d4c83fec716064eb370c470628ab5 Mon Sep 17 00:00:00 2001 From: He-Pin Date: Sat, 15 Jun 2024 18:04:24 +0800 Subject: [PATCH] feat: Support adjust the scheduler's tick-duration. --- .../apache/pekko/actor/SchedulerSpec.scala | 26 +++++++++++++- .../org/apache/pekko/config/ConfigSpec.scala | 1 + actor/src/main/resources/reference.conf | 9 +++++ .../actor/LightArrayRevolverScheduler.scala | 35 ++++++++++++++----- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/actor-tests/src/test/scala/org/apache/pekko/actor/SchedulerSpec.scala b/actor-tests/src/test/scala/org/apache/pekko/actor/SchedulerSpec.scala index b245d963f39..bb9eef056bd 100644 --- a/actor-tests/src/test/scala/org/apache/pekko/actor/SchedulerSpec.scala +++ b/actor-tests/src/test/scala/org/apache/pekko/actor/SchedulerSpec.scala @@ -26,12 +26,13 @@ import scala.util.control.NonFatal import atomic.{ AtomicInteger, AtomicReference } import scala.annotation.nowarn import com.typesafe.config.{ Config, ConfigFactory } + import language.postfixOps import org.scalatest.BeforeAndAfterEach - import org.apache.pekko import pekko.pattern.ask import pekko.testkit._ +import pekko.util.Helpers object SchedulerSpec { val testConfRevolver = @@ -40,6 +41,13 @@ object SchedulerSpec { pekko.scheduler.ticks-per-wheel = 32 """).withFallback(PekkoSpec.testConf) + val testConfAdjustment = + ConfigFactory.parseString(""" + pekko.scheduler.implementation = org.apache.pekko.actor.LightArrayRevolverScheduler + pekko.scheduler.tick-duration = 1ns + pekko.scheduler.error-on-tick-duration-verification-failed = off + """).withFallback(PekkoSpec.testConf) + } trait SchedulerSpec extends BeforeAndAfterEach with DefaultTimeout with ImplicitSender { this: PekkoSpec => @@ -819,3 +827,19 @@ class LightArrayRevolverSchedulerSpec extends PekkoSpec(SchedulerSpec.testConfRe } } + +class LightArrayRevolverSchedulerAdjustConfigSpec extends PekkoSpec(SchedulerSpec.testConfAdjustment) + with SchedulerSpec { + override def collectCancellable(c: Cancellable): Cancellable = c + private val tickDuration = system.scheduler.asInstanceOf[LightArrayRevolverScheduler].TickDuration + + "A LightArrayRevolverScheduler" must { + "be able to adjust the config" in { + if (Helpers.isWindows) { + tickDuration should ===(10.millis) + } else { + tickDuration should ===(1.millis) + } + } + } +} diff --git a/actor-tests/src/test/scala/org/apache/pekko/config/ConfigSpec.scala b/actor-tests/src/test/scala/org/apache/pekko/config/ConfigSpec.scala index d2b1411cfe4..90cc700fdbd 100644 --- a/actor-tests/src/test/scala/org/apache/pekko/config/ConfigSpec.scala +++ b/actor-tests/src/test/scala/org/apache/pekko/config/ConfigSpec.scala @@ -50,6 +50,7 @@ class ConfigSpec extends PekkoSpec(ConfigFactory.defaultReference(ActorSystem.fi getInt("pekko.scheduler.ticks-per-wheel") should ===(512) getDuration("pekko.scheduler.tick-duration", TimeUnit.MILLISECONDS) should ===(10L) + getBoolean("pekko.scheduler.error-on-tick-duration-verification-failed") should ===(true) getString("pekko.scheduler.implementation") should ===("org.apache.pekko.actor.LightArrayRevolverScheduler") getBoolean("pekko.daemonic") should ===(false) diff --git a/actor/src/main/resources/reference.conf b/actor/src/main/resources/reference.conf index 6a920143bce..9459cda1418 100644 --- a/actor/src/main/resources/reference.conf +++ b/actor/src/main/resources/reference.conf @@ -829,8 +829,17 @@ pekko { # Note that it might take up to 1 tick to stop the Timer, so setting the # tick-duration to a high value will make shutting down the actor system # take longer. + # + # Requirements: + # 1. The minimum supported tick-duration on Windows is 10ms, + # 2. The minimum supported tick-duration is 1ms tick-duration = 10ms + # An error will be throw when the tick-duration does not meet the requirements. + # When this is set to off, the tick-duration will be adjusted to meet the requirements + # and a warning will be logged. + error-on-tick-duration-verification-failed = on + # The timer uses a circular wheel of buckets to store the timer tasks. # This should be set such that the majority of scheduled timeouts (for high # scheduling frequency) will be shorter than one rotation of the wheel diff --git a/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala b/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala index 193c890bbc7..9bcdeb1ae21 100644 --- a/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala +++ b/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala @@ -54,18 +54,35 @@ class LightArrayRevolverScheduler(config: Config, log: LoggingAdapter, threadFac import Helpers.ConfigOps import Helpers.Requiring - val WheelSize = + val WheelSize: Int = config .getInt("pekko.scheduler.ticks-per-wheel") .requiring(ticks => (ticks & (ticks - 1)) == 0, "ticks-per-wheel must be a power of 2") - val TickDuration = - config - .getMillisDuration("pekko.scheduler.tick-duration") - .requiring( - _ >= 10.millis || !Helpers.isWindows, - "minimum supported pekko.scheduler.tick-duration on Windows is 10ms") - .requiring(_ >= 1.millis, "minimum supported pekko.scheduler.tick-duration is 1ms") - val ShutdownTimeout = config.getMillisDuration("pekko.scheduler.shutdown-timeout") + + val TickDuration: FiniteDuration = { + val durationFromConfig = config.getMillisDuration("pekko.scheduler.tick-duration") + val errorOnVerificationFailed = config.getBoolean("pekko.scheduler.error-on-tick-duration-verification-failed") + + if (Helpers.isWindows && durationFromConfig < 10.millis) { + if (errorOnVerificationFailed) { + throw new IllegalArgumentException( + "requirement failed: minimum supported pekko.scheduler.tick-duration on Windows is 10ms") + } else { + log.warning( + "requirement failed: minimum supported pekko.scheduler.tick-duration on Windows is 10ms, adjusted to 10ms now.") + 10.millis + } + } else if (durationFromConfig < 1.millis) { + if (errorOnVerificationFailed) { + throw new IllegalArgumentException("requirement failed: minimum supported pekko.scheduler.tick-duration is 1ms") + } else { + log.warning("requirement failed: minimum supported pekko.scheduler.tick-duration is 1ms, adjusted to 1ms now.") + 1.millis + } + } else durationFromConfig + } + + val ShutdownTimeout: FiniteDuration = config.getMillisDuration("pekko.scheduler.shutdown-timeout") import LightArrayRevolverScheduler._