diff --git a/CHANGES.txt b/CHANGES.txt index c2c62aedfd..f15a2630fa 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -10,6 +10,7 @@ 2.2 + * Change Windows kernel default timer resolution (CASSANDRA-9634) * Deprected sstable2json and json2sstable (CASSANDRA-9618) * Allow native functions in user-defined aggregates (CASSANDRA-9542) * Don't repair system_distributed by default (CASSANDRA-9621) diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml index 4593a7e757..5e65ae30a1 100644 --- a/conf/cassandra.yaml +++ b/conf/cassandra.yaml @@ -860,3 +860,10 @@ tracetype_repair_ttl: 604800 # This will inherently be backwards-incompatible with any 2.2 UDF that perform insecure # operations such as opening a socket or writing to the filesystem. enable_user_defined_functions: false + +# The default Windows kernel timer and scheduling resolution is 15.6ms for power conservation. +# Lowering this value on Windows can provide much tighter latency and better throughput, however +# some virtualized environments may see a negative performance impact from changing this setting +# below their system default. The sysinternals 'clockres' tool can confirm your system's default +# setting. +windows_timer_interval: 1 diff --git a/src/java/org/apache/cassandra/config/Config.java b/src/java/org/apache/cassandra/config/Config.java index e5891ab0d7..7cc28bf527 100644 --- a/src/java/org/apache/cassandra/config/Config.java +++ b/src/java/org/apache/cassandra/config/Config.java @@ -261,6 +261,8 @@ public class Config public static final int otc_coalescing_window_us_default = 200; public int otc_coalescing_window_us = otc_coalescing_window_us_default; + public int windows_timer_interval = 0; + public boolean enable_user_defined_functions = false; public static boolean getOutboundBindAny() diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index b5ee921c0a..a40eac16ab 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -1693,4 +1693,9 @@ public class DatabaseDescriptor { return conf.enable_user_defined_functions; } + + public static int getWindowsTimerInterval() + { + return conf.windows_timer_interval; + } } diff --git a/src/java/org/apache/cassandra/service/CassandraDaemon.java b/src/java/org/apache/cassandra/service/CassandraDaemon.java index b954e5004b..1e6d21f2bd 100644 --- a/src/java/org/apache/cassandra/service/CassandraDaemon.java +++ b/src/java/org/apache/cassandra/service/CassandraDaemon.java @@ -441,6 +441,13 @@ public class CassandraDaemon { String pidFile = System.getProperty("cassandra-pidfile"); + if (FBUtilities.isWindows()) + { + // We need to adjust the system timer on windows from the default 15ms down to the minimum of 1ms as this + // impacts timer intervals, thread scheduling, driver interrupts, etc. + WindowsTimer.startTimerPeriod(DatabaseDescriptor.getWindowsTimerInterval()); + } + try { try diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index eeda32d15f..60eafb8ed7 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -142,6 +142,7 @@ import org.apache.cassandra.utils.FBUtilities; import org.apache.cassandra.utils.JVMStabilityInspector; import org.apache.cassandra.utils.OutputHandler; import org.apache.cassandra.utils.Pair; +import org.apache.cassandra.utils.WindowsTimer; import org.apache.cassandra.utils.WrappedRunnable; import org.apache.cassandra.utils.progress.ProgressEvent; import org.apache.cassandra.utils.progress.ProgressEventType; @@ -677,6 +678,9 @@ public class StorageService extends NotificationBroadcasterSupport implements IE CommitLog.instance.shutdownBlocking(); + if (FBUtilities.isWindows()) + WindowsTimer.endTimerPeriod(DatabaseDescriptor.getWindowsTimerInterval()); + // wait for miscellaneous tasks like sstable and commitlog segment deletion ScheduledExecutors.nonPeriodicTasks.shutdown(); if (!ScheduledExecutors.nonPeriodicTasks.awaitTermination(1, TimeUnit.MINUTES)) @@ -721,6 +725,9 @@ public class StorageService extends NotificationBroadcasterSupport implements IE { if (drainOnShutdown != null) Runtime.getRuntime().removeShutdownHook(drainOnShutdown); + + if (FBUtilities.isWindows()) + WindowsTimer.endTimerPeriod(DatabaseDescriptor.getWindowsTimerInterval()); } private boolean shouldBootstrap() diff --git a/src/java/org/apache/cassandra/transport/Server.java b/src/java/org/apache/cassandra/transport/Server.java index 333b956763..72a1b6079e 100644 --- a/src/java/org/apache/cassandra/transport/Server.java +++ b/src/java/org/apache/cassandra/transport/Server.java @@ -136,7 +136,6 @@ public class Server implements CassandraDaemon.Server // Configure the server. eventExecutorGroup = new RequestThreadPoolExecutor(); - boolean hasEpoll = enableEpoll ? Epoll.isAvailable() : false; if (hasEpoll) { diff --git a/src/java/org/apache/cassandra/utils/WindowsTimer.java b/src/java/org/apache/cassandra/utils/WindowsTimer.java new file mode 100644 index 0000000000..9db8559845 --- /dev/null +++ b/src/java/org/apache/cassandra/utils/WindowsTimer.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jna.LastErrorException; +import com.sun.jna.Native; + +public final class WindowsTimer +{ + private static final Logger logger = LoggerFactory.getLogger(WindowsTimer.class); + + static + { + try + { + Native.register("winmm"); + } + catch (Exception e) + { + logger.error("Failed to register winmm.dll. Performance will be negatively impacted on this node."); + } + } + + private static native int timeBeginPeriod(int period) throws LastErrorException; + private static native int timeEndPeriod(int period) throws LastErrorException; + + private WindowsTimer() {} + + public static void startTimerPeriod(int period) + { + if (period == 0) + return; + assert(period > 0); + if (timeBeginPeriod(period) != 0) + logger.warn("Failed to set timer to : " + period + ". Performance will be degraded."); + } + + public static void endTimerPeriod(int period) + { + if (period == 0) + return; + assert(period > 0); + if (timeEndPeriod(period) != 0) + logger.warn("Failed to end accelerated timer period. System timer will remain set to: " + period + " ms."); + } +} diff --git a/tools/stress/src/org/apache/cassandra/stress/Stress.java b/tools/stress/src/org/apache/cassandra/stress/Stress.java index 256cefb7fd..a4ec8a0c9d 100644 --- a/tools/stress/src/org/apache/cassandra/stress/Stress.java +++ b/tools/stress/src/org/apache/cassandra/stress/Stress.java @@ -22,6 +22,8 @@ import java.net.Socket; import java.net.SocketException; import org.apache.cassandra.stress.settings.StressSettings; +import org.apache.cassandra.utils.FBUtilities; +import org.apache.cassandra.utils.WindowsTimer; public final class Stress { @@ -52,6 +54,9 @@ public final class Stress public static void main(String[] arguments) throws Exception { + if (FBUtilities.isWindows()) + WindowsTimer.startTimerPeriod(1); + final StressSettings settings; try { @@ -109,6 +114,8 @@ public final class Stress stressAction.run(); } + if (FBUtilities.isWindows()) + WindowsTimer.endTimerPeriod(1); System.exit(0); }