This is an automated email from the ASF dual-hosted git repository. smiklosovic pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/trunk by this push: new 5d46ff2796 Remove dependency on Sigar in favor of OSHI 5d46ff2796 is described below commit 5d46ff27968050e51425083fc3ab8b7d4a51fcd5 Author: Claude Warren <claude.war...@aiven.io> AuthorDate: Wed Oct 25 13:00:50 2023 +0200 Remove dependency on Sigar in favor of OSHI patch by Claude Warren; reviewed by Stefan Miklosovic, Jacek Lewandowski, Michael Semb Wever for CASSANDRA-16565 Co-authored-by: Stefan Miklosovic <smikloso...@apache.org> --- .build/build-resolver.xml | 47 +---- .build/cassandra-deps-template.xml | 4 +- .build/parent-pom-template.xml | 18 +- CHANGES.txt | 1 + bin/cassandra.in.sh | 3 - conf/cassandra-env.sh | 5 - debian/cassandra.install | 1 - ide/idea/workspace.xml | 3 - ide/nbproject/project.xml | 3 +- ide/nbproject/update-netbeans-classpaths.sh | 6 +- redhat/cassandra.spec | 1 - redhat/noboolean/cassandra.spec | 1 - .../config/CassandraRelevantProperties.java | 2 - .../apache/cassandra/service/StartupChecks.java | 16 +- .../org/apache/cassandra/utils/FBUtilities.java | 52 +---- .../org/apache/cassandra/utils/SigarLibrary.java | 187 ----------------- .../org/apache/cassandra/utils/SystemInfo.java | 228 +++++++++++++++++++++ test/conf/logback-simulator.xml | 2 +- .../distributed/test/ResourceLeakTest.java | 5 +- .../cassandra/distributed/test/TestBaseImpl.java | 1 - .../distributed/upgrade/UpgradeTestBase.java | 1 - .../cassandra/simulator/SimulationRunner.java | 2 - .../config/DatabaseDescriptorRefTest.java | 1 + .../cassandra/service/StartupChecksTest.java | 14 +- .../apache/cassandra/utils/FBUtilitiesTest.java | 16 -- .../org/apache/cassandra/utils/SystemInfoTest.java | 180 ++++++++++++++++ 26 files changed, 461 insertions(+), 339 deletions(-) diff --git a/.build/build-resolver.xml b/.build/build-resolver.xml index fa5703a7cd..86d0091a24 100644 --- a/.build/build-resolver.xml +++ b/.build/build-resolver.xml @@ -204,8 +204,6 @@ <files dir="${build.lib}" layout="{artifactId}-{version}-{classifier}.{extension}" scopes="compile,!provide,!system"/> </resolve> </retry> - <mkdir dir="${local.repository}/org/apache/cassandra/deps/sigar-bin"/> - <mkdir dir="${build.lib}/sigar-bin"/> <mkdir dir="${build.lib}/x86_64"/> <mkdir dir="${build.lib}/aarch64"/> <!-- uname -m on arm prints aarch64 instead of aarch_64 --> @@ -237,28 +235,6 @@ <file file="${local.repository}/org/apache/cassandra/deps/pure_sasl-0.6.2-py2-none-any.zip"/> <file file="${local.repository}/org/apache/cassandra/deps/wcwidth-0.2.5-py2.py3-none-any.zip"/> </copy> - <copy todir="${build.lib}/sigar-bin/" quiet="true"> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-amd64-freebsd-6.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-amd64-linux.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-amd64-solaris.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-ia64-hpux-11.sl"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-ia64-linux.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-pa-hpux-11.sl"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-ppc-aix-5.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-ppc-linux.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-ppc64-aix-5.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-ppc64-linux.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-ppc64le-linux.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-s390x-linux.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-sparc-solaris.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-sparc64-solaris.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-universal-macosx.dylib"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-universal64-macosx.dylib"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-x86-freebsd-5.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-x86-freebsd-6.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-x86-linux.so"/> - <file file="${local.repository}/org/apache/cassandra/deps/sigar-bin/libsigar-x86-solaris.so"/> - </copy> <!-- as resolver will copy all dependencies into lib dir, and we are copying jars to lib/{x86_64|aarch64} as well, we would have duplicities --> <delete file="${build.lib}/AmazonCorrettoCryptoProvider-2.2.0-linux-x86_64.jar" failonerror="false"/> @@ -269,6 +245,7 @@ </target> <target name="_resolver-dist-lib_get_files"> + <mkdir dir="${local.repository}/org/apache/cassandra/deps" /> <!-- files.pythonhosted.org/packages --> <get src="${artifact.python.pypi}/59/a0/cf4cd997e1750f0c2d91c6ea5abea218251c43c3581bcc2f118b00baf5cf/futures-2.1.6-py2.py3-none-any.whl" dest="${local.repository}/org/apache/cassandra/deps/futures-2.1.6-py2.py3-none-any.zip" usetimestamp="true" quiet="true" skipexisting="true"/> <get src="${artifact.python.pypi}/37/b2/ef1124540ee2c0b417be8d0f74667957e6aa084a3f26621aa67e2e77f3fb/pure_sasl-0.6.2-py2-none-any.whl" dest="${local.repository}/org/apache/cassandra/deps/pure_sasl-0.6.2-py2-none-any.zip" usetimestamp="true" quiet="true" skipexisting="true"/> @@ -276,28 +253,6 @@ <!-- apache/cassandra/lib --> <get src="${lib.download.base.url}/lib/geomet-0.1.0.zip" dest="${local.repository}/org/apache/cassandra/deps/geomet-0.1.0.zip" usetimestamp="true" quiet="true" skipexisting="true"/> - <get dest="${local.repository}/org/apache/cassandra/deps/sigar-bin/" quiet="true" usetimestamp="true" skipexisting="true"> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-amd64-freebsd-6.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-amd64-linux.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-amd64-solaris.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-ia64-hpux-11.sl"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-ia64-linux.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-pa-hpux-11.sl"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-ppc-aix-5.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-ppc-linux.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-ppc64-aix-5.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-ppc64-linux.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-ppc64le-linux.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-s390x-linux.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-sparc-solaris.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-sparc64-solaris.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-universal-macosx.dylib"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-universal64-macosx.dylib"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-x86-freebsd-5.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-x86-freebsd-6.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-x86-linux.so"/> - <url url="${lib.download.base.url}/lib/sigar-bin/libsigar-x86-solaris.so"/> - </get> </target> </project> diff --git a/.build/cassandra-deps-template.xml b/.build/cassandra-deps-template.xml index 47e8a6cda6..98cea9626f 100644 --- a/.build/cassandra-deps-template.xml +++ b/.build/cassandra-deps-template.xml @@ -244,8 +244,8 @@ <!-- end of chronicle-queue --> <dependency> - <groupId>org.fusesource</groupId> - <artifactId>sigar</artifactId> + <groupId>com.github.oshi</groupId> + <artifactId>oshi-core</artifactId> </dependency> <dependency> <groupId>org.eclipse.jdt</groupId> diff --git a/.build/parent-pom-template.xml b/.build/parent-pom-template.xml index 5440085c97..fd418a44f3 100644 --- a/.build/parent-pom-template.xml +++ b/.build/parent-pom-template.xml @@ -993,13 +993,21 @@ <scope>provided</scope> </dependency> <dependency> - <groupId>org.fusesource</groupId> - <artifactId>sigar</artifactId> - <version>1.6.4</version> + <groupId>com.github.oshi</groupId> + <artifactId>oshi-core</artifactId> + <version>6.4.8</version> <exclusions> <exclusion> - <artifactId>log4j</artifactId> - <groupId>log4j</groupId> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-bom</artifactId> + </exclusion> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-parent</artifactId> </exclusion> </exclusions> </dependency> diff --git a/CHANGES.txt b/CHANGES.txt index 728a5d4af2..108096a416 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 5.1 + * Remove dependency on Sigar in favor of OSHI (CASSANDRA-16565) * Simplify the bind marker and Term logic (CASSANDRA-18813) * Limit cassandra startup to supported JDKs, allow higher JDKs by setting CASSANDRA_JDK_UNSUPPORTED (CASSANDRA-18688) * Standardize nodetool tablestats formatting of data units (CASSANDRA-19104) diff --git a/bin/cassandra.in.sh b/bin/cassandra.in.sh index 86a684b14a..881e425de1 100644 --- a/bin/cassandra.in.sh +++ b/bin/cassandra.in.sh @@ -81,9 +81,6 @@ fi # set JVM javaagent opts to avoid warnings/errors JAVA_AGENT="$JAVA_AGENT -javaagent:$CASSANDRA_HOME/lib/jamm-0.4.0.jar" -# Added sigar-bin to the java.library.path CASSANDRA-7838 -JAVA_OPTS="$JAVA_OPTS:-Djava.library.path=$CASSANDRA_HOME/lib/sigar-bin" - platform=$(uname -m) if [ -d "$CASSANDRA_HOME"/lib/"$platform" ]; then for jar in "$CASSANDRA_HOME"/lib/"$platform"/*.jar ; do diff --git a/conf/cassandra-env.sh b/conf/cassandra-env.sh index cf6399560f..0b1dec45ed 100644 --- a/conf/cassandra-env.sh +++ b/conf/cassandra-env.sh @@ -271,11 +271,6 @@ JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.password.file=/etc/cassandra/ #MX4J_ADDRESS="127.0.0.1" #MX4J_PORT="8081" -# Cassandra uses SIGAR to capture OS metrics CASSANDRA-7838 -# for SIGAR we have to set the java.library.path -# to the location of the native libraries. -JVM_OPTS="$JVM_OPTS -Djava.library.path=$CASSANDRA_HOME/lib/sigar-bin" - if [ "x$MX4J_ADDRESS" != "x" ]; then if [[ "$MX4J_ADDRESS" == \-Dmx4jaddress* ]]; then # Backward compatible with the older style #13578 diff --git a/debian/cassandra.install b/debian/cassandra.install index 578fd93a61..7ee058bb59 100644 --- a/debian/cassandra.install +++ b/debian/cassandra.install @@ -30,6 +30,5 @@ tools/bin/hash_password usr/bin tools/bin/sstablepartitions usr/bin lib/*.jar usr/share/cassandra/lib lib/*.zip usr/share/cassandra/lib -lib/sigar-bin/* usr/share/cassandra/lib/sigar-bin lib/x86_64/* usr/share/cassandra/lib/x86_64 lib/aarch64/* usr/share/cassandra/lib/aarch64 diff --git a/ide/idea/workspace.xml b/ide/idea/workspace.xml index 89528b2408..c5c0e28b96 100644 --- a/ide/idea/workspace.xml +++ b/ide/idea/workspace.xml @@ -149,7 +149,6 @@ -Dcassandra.logdir=$PROJECT_DIR$/data/logs -Dcassandra.reads.thresholds.coordinator.defensive_checks_enabled=true -Dcassandra.storagedir=$PROJECT_DIR$/data - -Djava.library.path=$PROJECT_DIR$/lib/sigar-bin -Dlogback.configurationFile=file://$PROJECT_DIR$/conf/logback.xml -XX:HeapDumpPath=build/test -ea" /> @@ -194,7 +193,6 @@ -Dcassandra.tolerate_sstable_size=true -Dcassandra.use_nix_recursive_delete=true -Dinvalid-legacy-sstable-root=$PROJECT_DIR$/test/data/invalid-legacy-sstables - -Djava.library.path=$PROJECT_DIR$/lib/sigar-bin -Dlegacy-sstable-root=$PROJECT_DIR$/test/data/legacy-sstables -Dlogback.configurationFile=file://$PROJECT_DIR$/test/conf/logback-test.xml -Dmigration-sstable-root=$PROJECT_DIR$/test/data/migration-sstables @@ -231,7 +229,6 @@ -Dcassandra.reads.thresholds.coordinator.defensive_checks_enabled=true -Dcassandra.storagedir=$PROJECT_DIR$/data -Dcassandra.triggers_dir=$PROJECT_DIR$/conf/triggers - -Djava.library.path=$PROJECT_DIR$/lib/sigar-bin -Dlogback.configurationFile=file://$PROJECT_DIR$/conf/logback.xml -XX:HeapDumpPath=build/test -Xmx1G diff --git a/ide/nbproject/project.xml b/ide/nbproject/project.xml index ea9a486aa5..038b2b1cf9 100644 --- a/ide/nbproject/project.xml +++ b/ide/nbproject/project.xml @@ -7,7 +7,8 @@ <properties> <property name="project.dir">..</property> <!-- the compile classpaths should be distinct per compilation unit… but it is kept simple and the build will catch errors --> - <property name="cassandra.classpath.jars">${project.dir}/build/lib/jars/AmazonCorrettoCryptoProvider-2.2.0-linux-x86_64.jar:${project.dir}/build/lib/jars/HdrHistogram-2.1.9.jar:${project.dir}/build/lib/jars/ST4-4.0.8.jar:${project.dir}/build/lib/jars/affinity-3.23.3.jar:${project.dir}/build/lib/jars/agrona-1.17.1.jar:${project.dir}/build/lib/jars/airline-0.8.jar:${project.dir}/build/lib/jars/antlr-3.5.2.jar:${project.dir}/build/lib/jars/antlr-runtime-3.5.2.jar:${project.d [...] + <!-- DO NOT EDIT THE FOLLOWING LINE DIRECTLY: Use the update-netbeans-classpath.sh script --> + <property name="cassandra.classpath.jars">${project.dir}/build/lib/jars/affinity-3.23.3.jar:${project.dir}/build/lib/jars/agrona-1.17.1.jar:${project.dir}/build/lib/jars/airline-0.8.jar:${project.dir}/build/lib/jars/AmazonCorrettoCryptoProvider-2.2.0-linux-x86_64.jar:${project.dir}/build/lib/jars/antlr-3.5.2.jar:${project.dir}/build/lib/jars/antlr-runtime-3.5.2.jar:${project.dir}/build/lib/jars/asm-9.4.jar:${project.dir}/build/lib/jars/bcpkix-jdk15on-1.70.jar:${project.di [...] </properties> <folders> <source-folder> diff --git a/ide/nbproject/update-netbeans-classpaths.sh b/ide/nbproject/update-netbeans-classpaths.sh index 219ee303e1..6822cf5516 100755 --- a/ide/nbproject/update-netbeans-classpaths.sh +++ b/ide/nbproject/update-netbeans-classpaths.sh @@ -27,5 +27,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" cd $DIR/../.. CLASSPATH=`for f in build/lib/jars/*.jar ; do echo -n '${project.dir}/'$f: ; done ; for f in build/test/lib/jars/*.jar ; do echo -n '${project.dir}/'$f: ; done ;` -sed -i '' 's/cassandra\.classpath\.jars\">.*<\/property>/cassandra\.classpath\.jars\">NEW_CLASSPATH<\/property>/' $DIR/project.xml -sed -i '' "s@NEW_CLASSPATH@"$CLASSPATH"@" $DIR/project.xml +sed 's/cassandra\.classpath\.jars\">.*<\/property>/cassandra\.classpath\.jars\">NEW_CLASSPATH<\/property>/' $DIR/project.xml > $DIR/project.xml.tmp +mv $DIR/project.xml.tmp $DIR/project.xml +sed "s@NEW_CLASSPATH@"$CLASSPATH"@" $DIR/project.xml > $DIR/project.xml.tmp +mv $DIR/project.xml.tmp $DIR/project.xml diff --git a/redhat/cassandra.spec b/redhat/cassandra.spec index 923ed9fa80..f55899e13c 100644 --- a/redhat/cassandra.spec +++ b/redhat/cassandra.spec @@ -103,7 +103,6 @@ sed -i 's/^# hints_directory:/hints_directory:/' conf/cassandra.yaml rm -f bin/stop-server rm -f bin/*.orig rm -f bin/cassandra.in.sh -rm -f lib/sigar-bin/*winnt* # strip segfaults on dll.. rm -f tools/bin/cassandra.in.sh # copy default configs diff --git a/redhat/noboolean/cassandra.spec b/redhat/noboolean/cassandra.spec index c6b1a69888..e151f03878 100644 --- a/redhat/noboolean/cassandra.spec +++ b/redhat/noboolean/cassandra.spec @@ -103,7 +103,6 @@ sed -i 's/^# hints_directory:/hints_directory:/' conf/cassandra.yaml rm -f bin/stop-server rm -f bin/*.orig rm -f bin/cassandra.in.sh -rm -f lib/sigar-bin/*winnt* # strip segfaults on dll.. rm -f tools/bin/cassandra.in.sh # copy default configs diff --git a/src/java/org/apache/cassandra/config/CassandraRelevantProperties.java b/src/java/org/apache/cassandra/config/CassandraRelevantProperties.java index 5f9289e048..ed92ee6a41 100644 --- a/src/java/org/apache/cassandra/config/CassandraRelevantProperties.java +++ b/src/java/org/apache/cassandra/config/CassandraRelevantProperties.java @@ -567,7 +567,6 @@ public enum CassandraRelevantProperties * can be also done manually for that particular case: {@code flush(SchemaConstants.SCHEMA_KEYSPACE_NAME);}. */ TEST_FLUSH_LOCAL_SCHEMA_CHANGES("cassandra.test.flush_local_schema_changes", "true"), TEST_HARRY_SWITCH_AFTER("cassandra.test.harry.progression.switch-after", "1"), - TEST_IGNORE_SIGAR("cassandra.test.ignore_sigar"), TEST_INVALID_LEGACY_SSTABLE_ROOT("invalid-legacy-sstable-root"), TEST_JVM_DTEST_DISABLE_SSL("cassandra.test.disable_ssl"), TEST_JVM_SHUTDOWN_MESSAGING_GRACEFULLY("cassandra.test.messagingService.gracefulShutdown", "false"), @@ -579,7 +578,6 @@ public enum CassandraRelevantProperties TEST_REUSE_PREPARED("cassandra.test.reuse_prepared", "true"), TEST_ROW_CACHE_SIZE("cassandra.test.row_cache_size"), TEST_SERIALIZATION_WRITES("cassandra.test-serialization-writes"), - TEST_SIGAR_NATIVE_LOGGING("sigar.nativeLogging", "true"), TEST_SIMULATOR_DEBUG("cassandra.test.simulator.debug"), TEST_SIMULATOR_DETERMINISM_CHECK("cassandra.test.simulator.determinismcheck", "none"), TEST_SIMULATOR_LIVENESS_CHECK("cassandra.test.simulator.livenesscheck", "true"), diff --git a/src/java/org/apache/cassandra/service/StartupChecks.java b/src/java/org/apache/cassandra/service/StartupChecks.java index ba83c5881b..5dc11a6c6b 100644 --- a/src/java/org/apache/cassandra/service/StartupChecks.java +++ b/src/java/org/apache/cassandra/service/StartupChecks.java @@ -73,7 +73,6 @@ import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.utils.FBUtilities; import org.apache.cassandra.utils.JavaUtils; import org.apache.cassandra.utils.NativeLibrary; -import org.apache.cassandra.utils.SigarLibrary; import static org.apache.cassandra.config.CassandraRelevantProperties.CASSANDRA_JMX_LOCAL_PORT; import static org.apache.cassandra.config.CassandraRelevantProperties.COM_SUN_MANAGEMENT_JMXREMOTE_PORT; @@ -89,7 +88,7 @@ import static org.apache.cassandra.utils.Clock.Global.currentTimeMillis; * Each individual test is modelled as an implementation of StartupCheck, these are run * at the start of CassandraDaemon#setup() before any local state is mutated. The default * checks are a mix of informational tests (inspectJvmOptions), initialization - * (initSigarLibrary, checkCacheServiceInitialization) and invariant checking + * (checkProcessEnvironment, checkCacheServiceInitialization) and invariant checking * (checkValidLaunchDate, checkSystemKeyspaceState, checkSSTablesFormat). * * In addition, if checkSystemKeyspaceState determines that the release version has @@ -138,7 +137,7 @@ public class StartupChecks checkJMXProperties, inspectJvmOptions, checkNativeLibraryInitialization, - initSigarLibrary, + checkProcessEnvironment, checkMaxMapCount, checkReadAheadKbSetting, checkDataDirs, @@ -417,14 +416,17 @@ public class StartupChecks } }; - public static final StartupCheck initSigarLibrary = new StartupCheck() + public static final StartupCheck checkProcessEnvironment = new StartupCheck() { @Override public void execute(StartupChecksOptions options) { - if (options.isDisabled(getStartupCheckType())) - return; - SigarLibrary.instance.warnIfRunningInDegradedMode(); + Optional<String> degradations = FBUtilities.getSystemInfo().isDegraded(); + + if (degradations.isPresent()) + logger.warn("Cassandra server running in degraded mode. " + degradations.get()); + else + logger.info("Checked OS settings and found them configured for optimal performance."); } }; diff --git a/src/java/org/apache/cassandra/utils/FBUtilities.java b/src/java/org/apache/cassandra/utils/FBUtilities.java index 2a02933e0f..d3728f95d8 100644 --- a/src/java/org/apache/cassandra/utils/FBUtilities.java +++ b/src/java/org/apache/cassandra/utils/FBUtilities.java @@ -47,7 +47,6 @@ import java.util.Map; import java.util.NavigableSet; import java.util.Optional; import java.util.Properties; -import java.util.Scanner; import java.util.TreeSet; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -138,7 +137,7 @@ public class FBUtilities private static int availableProcessors = CASSANDRA_AVAILABLE_PROCESSORS.getInt(DatabaseDescriptor.getAvailableProcessors()); - private static volatile Supplier<Semver> kernelVersionSupplier = Suppliers.memoize(FBUtilities::getKernelVersionFromUname); + private static volatile Supplier<SystemInfo> systemInfoSupplier = Suppliers.memoize(SystemInfo::new); public static void setAvailableProcessors(int value) { @@ -146,9 +145,9 @@ public class FBUtilities } @VisibleForTesting - public static void setKernelVersionSupplier(Supplier<Semver> supplier) + public static void setSystemInfoSupplier(Supplier<SystemInfo> supplier) { - kernelVersionSupplier = supplier; + systemInfoSupplier = supplier; } public static int getAvailableProcessors() @@ -1449,50 +1448,11 @@ public class FBUtilities public static Semver getKernelVersion() { - return kernelVersionSupplier.get(); + return systemInfoSupplier.get().getKernelVersion(); } - @VisibleForTesting - static Semver getKernelVersionFromUname() - { - // TODO rewrite this method with Oshi when it is eventually included in the project - if (!isLinux) - return null; - - try - { - String output = exec(Map.of(), Duration.ofSeconds(5), 1024, 1024, "uname", "-r"); - - if (output.isEmpty()) - throw new RuntimeException("Error while trying to get kernel version, 'uname -r' returned empty output"); - - return parseKernelVersion(output); - } - catch (IOException | TimeoutException e) - { - throw new RuntimeException("Error while trying to get kernel version", e); - } - catch (InterruptedException e) - { - Thread.currentThread().interrupt(); - throw new RuntimeException(e); - } - } - - @VisibleForTesting - static Semver parseKernelVersion(String versionString) + public static SystemInfo getSystemInfo() { - Preconditions.checkNotNull(versionString, "kernel version cannot be null"); - try (Scanner scanner = new Scanner(versionString)) - { - while (scanner.hasNextLine()) - { - String version = scanner.nextLine().trim(); - if (version.isEmpty()) - continue; - return new Semver(version, Semver.SemverType.LOOSE); - } - } - throw new IllegalArgumentException("Error while trying to parse kernel version - no version found"); + return systemInfoSupplier.get(); } } \ No newline at end of file diff --git a/src/java/org/apache/cassandra/utils/SigarLibrary.java b/src/java/org/apache/cassandra/utils/SigarLibrary.java deleted file mode 100644 index 830f7cab8e..0000000000 --- a/src/java/org/apache/cassandra/utils/SigarLibrary.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * 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.hyperic.sigar.*; -import org.slf4j.LoggerFactory; -import org.slf4j.Logger; - -import org.apache.cassandra.config.CassandraRelevantProperties; - -@Shared -public class SigarLibrary -{ - private Logger logger = LoggerFactory.getLogger(SigarLibrary.class); - - public static final SigarLibrary instance = new SigarLibrary(); - - private Sigar sigar; - private FileSystemMap mounts = null; - private boolean initialized = false; - private long INFINITY = -1; - private long EXPECTED_MIN_NOFILE = 10000l; // number of files that can be opened - private long EXPECTED_NPROC = 32768l; // number of processes - private long EXPECTED_AS = INFINITY; // address space - - // TODO: Determine memlock limits if possible - // TODO: Determine if file system is remote or local - // TODO: Determine if disk latency is within acceptable limits - - private SigarLibrary() - { - logger.info("Initializing SIGAR library"); - try - { - sigar = new Sigar(); - mounts = sigar.getFileSystemMap(); - initialized = true; - } - catch (SigarException e) - { - logger.info("Could not initialize SIGAR library {} ", e.getMessage()); - } - catch (UnsatisfiedLinkError linkError) - { - logger.info("Could not initialize SIGAR library {} ", linkError.getMessage()); - } - } - - /** - * - * @return true or false indicating if sigar was successfully initialized - */ - public boolean initialized() - { - return initialized; - } - - private boolean hasAcceptableProcNumber() - { - try - { - long fileMax = sigar.getResourceLimit().getProcessesMax(); - if (fileMax >= EXPECTED_NPROC || fileMax == INFINITY) - { - return true; - } - else - { - return false; - } - } - catch (SigarException sigarException) - { - logger.warn("Could not determine if max processes was acceptable. Error message: {}", sigarException); - return false; - } - } - - private boolean hasAcceptableFileLimits() - { - try - { - long fileMax = sigar.getResourceLimit().getOpenFilesMax(); - if (fileMax >= EXPECTED_MIN_NOFILE || fileMax == INFINITY) - { - return true; - } - else - { - return false; - } - } - catch (SigarException sigarException) - { - logger.warn("Could not determine if max open file handle limit is correctly configured. Error message: {}", sigarException); - return false; - } - } - - private boolean hasAcceptableAddressSpace() - { - try - { - long fileMax = sigar.getResourceLimit().getVirtualMemoryMax(); - if (fileMax == EXPECTED_AS) - { - return true; - } - else - { - return false; - } - } - catch (SigarException sigarException) - { - logger.warn("Could not determine if VirtualMemoryMax was acceptable. Error message: {}", sigarException); - return false; - } - } - - private boolean isSwapEnabled() - { - try - { - Swap swap = sigar.getSwap(); - long swapSize = swap.getTotal(); - if (swapSize > 0) - { - return true; - } - else - { - return false; - } - } - catch (SigarException sigarException) - { - logger.warn("Could not determine if swap configuration is acceptable. Error message: {}", sigarException); - return false; - } - } - - public long getPid() - { - return initialized ? sigar.getPid() : -1; - } - - public void warnIfRunningInDegradedMode() - { - if (initialized) - { - boolean swapEnabled = isSwapEnabled(); - boolean goodAddressSpace = hasAcceptableAddressSpace(); - boolean goodFileLimits = hasAcceptableFileLimits(); - boolean goodProcNumber = hasAcceptableProcNumber(); - if (swapEnabled || !goodAddressSpace || !goodFileLimits || !goodProcNumber || CassandraRelevantProperties.TEST_IGNORE_SIGAR.getBoolean()) - { - logger.warn("Cassandra server running in degraded mode. Is swap disabled? : {}, Address space adequate? : {}, " + - " nofile limit adequate? : {}, nproc limit adequate? : {} ", !swapEnabled, goodAddressSpace, - goodFileLimits, goodProcNumber ); - } - else - { - logger.info("Checked OS settings and found them configured for optimal performance."); - } - } - else - { - logger.info("Sigar could not be initialized, test for checking degraded mode omitted."); - } - } -} diff --git a/src/java/org/apache/cassandra/utils/SystemInfo.java b/src/java/org/apache/cassandra/utils/SystemInfo.java new file mode 100644 index 0000000000..ec793a692b --- /dev/null +++ b/src/java/org/apache/cassandra/utils/SystemInfo.java @@ -0,0 +1,228 @@ +/* + * 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 java.util.List; +import java.util.Optional; +import java.util.function.Supplier; +import java.util.regex.Pattern; + +import com.vdurmont.semver4j.Semver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.cassandra.io.util.File; +import org.apache.cassandra.io.util.FileUtils; +import oshi.PlatformEnum; + +import static java.lang.String.format; +import static java.util.Optional.empty; +import static java.util.Optional.of; + +/** + * An abstraction of System information, this class provides access to system information without specifying how + * it is retrieved. + */ +public class SystemInfo +{ + // TODO: Determine memlock limits if possible + // TODO: Determine if file system is remote or local + // TODO: Determine if disk latency is within acceptable limits + + private static final Logger logger = LoggerFactory.getLogger(SystemInfo.class); + + private static final long INFINITY = -1L; + static final long EXPECTED_MIN_NUMBER_OF_OPENED_FILES = 10000L; // number of files that can be opened + static final long EXPECTED_MIN_NUMBER_OF_PROCESSES = 32768L; // number of processes + static final long EXPECTED_ADDRESS_SPACE = 0x7FFFFFFFL; // address space + + static final String OPEN_FILES_VIOLATION_MESSAGE = format("Minimum value for max open files should be >= %s. ", EXPECTED_MIN_NUMBER_OF_OPENED_FILES); + static final String NUMBER_OF_PROCESSES_VIOLATION_MESSAGE = format("Number of processes should be >= %s. ", EXPECTED_MIN_NUMBER_OF_PROCESSES); + static final String ADDRESS_SPACE_VIOLATION_MESSAGE = format("Amount of available address space should be >= %s. ", EXPECTED_ADDRESS_SPACE); + static final String SWAP_VIOLATION_MESSAGE = "Swap should be disabled. "; + + /** + * The default number of processes that are reported if the actual value can not be retrieved. + */ + private static final long DEFAULT_MAX_PROCESSES = 1024; + + private static final Pattern SPACES_PATTERN = Pattern.compile("\\s+"); + + /** + * The oshi.SystemInfo has the following note: + * Platform-specific Hardware and Software objects are retrieved via memoized suppliers. To conserve memory at the + * cost of additional processing time, create a new version of SystemInfo() for subsequent calls. To conserve + * processing time at the cost of additional memory usage, re-use the same {@link SystemInfo} object for future + * queries. + * <p> + * We are opting for minimal memory footprint. + */ + private final oshi.SystemInfo si; + + public SystemInfo() + { + si = new oshi.SystemInfo(); + } + + /** + * @return The PlatformEnum for the current platform. (e.g. Linux, Windows, AIX, etc.) + */ + public PlatformEnum platform() + { + return oshi.SystemInfo.getCurrentPlatform(); + } + + /** + * Gets the maximum number of processes the user can create. + * Note: if not on a Linux system this always return the + * + * @return The maximum number of processes. + * @see #DEFAULT_MAX_PROCESSES + */ + public long getMaxProcess() + { + // this check only works on Linux systems. Errors fall through to return default. + if (platform() == PlatformEnum.LINUX) + { + String path = format("/proc/%s/limits", getPid()); + try + { + List<String> lines = FileUtils.readLines(new File(path)); + for (String line : lines) + { + if (line.startsWith("Max processes")) + { + String[] parts = SPACES_PATTERN.split(line); + + if (parts.length < 3) + continue; + + String limit = parts[2]; + return "unlimited".equals(limit) ? INFINITY : Long.parseLong(limit); + } + } + logger.error("'Max processes' not found in {}", path); + } + catch (Exception t) + { + logger.error(format("Unable to read %s", path), t); + } + } + + /* return the default value for non-Linux systems or parsing error. + * Can not return 0 as we know there is at least 1 process (this one) and + * -1 historically represents infinity. + */ + return DEFAULT_MAX_PROCESSES; + } + + /** + * @return The maximum number of open files allowd to the current process/user. + */ + public long getMaxOpenFiles() + { + // ulimit -H -n + return si.getOperatingSystem().getCurrentProcess().getHardOpenFileLimit(); + } + + /** + * Gets the Virtual Memory Size (VSZ). Includes all memory that the process can access, + * including memory that is swapped out and memory that is from shared libraries. + * + * @return The amount of virtual memory allowed to be allocatedby the current process/user. + */ + public long getVirtualMemoryMax() + { + return si.getOperatingSystem().getCurrentProcess().getVirtualSize(); + } + + /** + * @return The amount of swap space allocated on the system. + */ + public long getSwapSize() + { + return si.getHardware().getMemory().getVirtualMemory().getSwapTotal(); + } + + /** + * @return the PID of the current system. + */ + public long getPid() + { + return si.getOperatingSystem().getProcessId(); + } + + /** + * @return the Semver for the kernel version of the OS. + */ + public Semver getKernelVersion() + { + return new Semver(si.getOperatingSystem().getVersionInfo().getBuildNumber(), Semver.SemverType.LOOSE); + } + + /** + * Tests if the system is running in degraded mode. + * + * @return non-empty optional with degradation messages if the system is in degraded mode, empty optional otherwise. + */ + public Optional<String> isDegraded() + { + Supplier<String> expectedNumProc = () -> { + // only check proc on nproc linux + if (platform() == PlatformEnum.LINUX) + return invalid(getMaxProcess(), EXPECTED_MIN_NUMBER_OF_PROCESSES) ? NUMBER_OF_PROCESSES_VIOLATION_MESSAGE + : null; + else + return format("System is running %s, Linux OS is recommended. ", platform()); + }; + + Supplier<String> swapShouldBeDisabled = () -> (getSwapSize() > 0) ? SWAP_VIOLATION_MESSAGE : null; + + Supplier<String> expectedAddressSpace = () -> invalid(getVirtualMemoryMax(), EXPECTED_ADDRESS_SPACE) + ? ADDRESS_SPACE_VIOLATION_MESSAGE + : null; + + Supplier<String> expectedMinNoFile = () -> invalid(getMaxOpenFiles(), EXPECTED_MIN_NUMBER_OF_OPENED_FILES) + ? OPEN_FILES_VIOLATION_MESSAGE + : null; + + StringBuilder sb = new StringBuilder(); + + for (Supplier<String> check : List.of(expectedNumProc, swapShouldBeDisabled, expectedAddressSpace, expectedMinNoFile)) + Optional.ofNullable(check.get()).map(sb::append); + + String message = sb.toString(); + return message.isEmpty() ? empty() : of(message); + } + + /** + * Checks if a value is invalid. + * <p> + * Value is invalid if it is smaller than {@code min} and it is not {@code INFINITY}, + * here represented as a value of -1; + * + * @param value the value to check + * @param min the minimum value + * @return true if value is valid + */ + private boolean invalid(long value, long min) + { + return value < min && value != INFINITY; + } +} diff --git a/test/conf/logback-simulator.xml b/test/conf/logback-simulator.xml index 3a9fabc380..d0082d43fa 100644 --- a/test/conf/logback-simulator.xml +++ b/test/conf/logback-simulator.xml @@ -43,7 +43,7 @@ <logger name="org.apache.cassandra.net.Message" level="ERROR"/> <logger name="org.reflections.Reflections" level="ERROR"/> <logger name="org.apache.hadoop" level="WARN"/> - <logger name="org.apache.cassandra.utils.SigarLibrary" level="ERROR"/> + <logger name="org.apache.cassandra.utils.SystemInfo" level="ERROR"/> <logger name="org.apache.cassandra.utils.FBUtilities" level="ERROR"/> <logger name="org.apache.cassandra.config.DatabaseDescriptor" level="ERROR"/> <logger name="org.apache.cassandra.service.StartupChecks" level="ERROR"/> diff --git a/test/distributed/org/apache/cassandra/distributed/test/ResourceLeakTest.java b/test/distributed/org/apache/cassandra/distributed/test/ResourceLeakTest.java index b90b895662..736112c6d4 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/ResourceLeakTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/ResourceLeakTest.java @@ -41,7 +41,7 @@ import org.apache.cassandra.distributed.api.IInstanceConfig; import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.distributed.shared.JMXUtil; import org.apache.cassandra.io.util.File; -import org.apache.cassandra.utils.SigarLibrary; +import org.apache.cassandra.utils.FBUtilities; import static org.apache.cassandra.distributed.api.Feature.GOSSIP; import static org.apache.cassandra.distributed.api.Feature.JMX; @@ -91,8 +91,7 @@ public class ResourceLeakTest extends TestBaseImpl */ private static Long getProcessId() { - // Once Java 9 is ready the process API should provide a better way to get the process ID. - long pid = SigarLibrary.instance.getPid(); + long pid = FBUtilities.getSystemInfo().getPid(); if (pid >= 0) return Long.valueOf(pid); diff --git a/test/distributed/org/apache/cassandra/distributed/test/TestBaseImpl.java b/test/distributed/org/apache/cassandra/distributed/test/TestBaseImpl.java index 6bd41a7e1b..72ba9d4f04 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/TestBaseImpl.java +++ b/test/distributed/org/apache/cassandra/distributed/test/TestBaseImpl.java @@ -81,7 +81,6 @@ public class TestBaseImpl extends DistributedTestBase { ICluster.setup(); SKIP_GC_INSPECTOR.setBoolean(true); - System.setProperty("sigar.nativeLogging", "false"); } @Override diff --git a/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTestBase.java b/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTestBase.java index 4b2d0ae374..017c1c5a44 100644 --- a/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTestBase.java +++ b/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTestBase.java @@ -71,7 +71,6 @@ public class UpgradeTestBase extends DistributedTestBase { ICluster.setup(); SKIP_GC_INSPECTOR.setBoolean(true); - System.setProperty("sigar.nativeLogging", "false"); } diff --git a/test/simulator/main/org/apache/cassandra/simulator/SimulationRunner.java b/test/simulator/main/org/apache/cassandra/simulator/SimulationRunner.java index 71acd6d95d..026078c9b8 100644 --- a/test/simulator/main/org/apache/cassandra/simulator/SimulationRunner.java +++ b/test/simulator/main/org/apache/cassandra/simulator/SimulationRunner.java @@ -74,7 +74,6 @@ import static org.apache.cassandra.config.CassandraRelevantProperties.PAXOS_REPA import static org.apache.cassandra.config.CassandraRelevantProperties.RING_DELAY; import static org.apache.cassandra.config.CassandraRelevantProperties.SHUTDOWN_ANNOUNCE_DELAY_IN_MS; import static org.apache.cassandra.config.CassandraRelevantProperties.SYSTEM_AUTH_DEFAULT_RF; -import static org.apache.cassandra.config.CassandraRelevantProperties.TEST_IGNORE_SIGAR; import static org.apache.cassandra.config.CassandraRelevantProperties.DISABLE_GOSSIP_ENDPOINT_REMOVAL; import static org.apache.cassandra.config.CassandraRelevantProperties.TEST_JVM_DTEST_DISABLE_SSL; import static org.apache.cassandra.simulator.debug.Reconcile.reconcileWith; @@ -121,7 +120,6 @@ public class SimulationRunner DISABLE_SSTABLE_ACTIVITY_TRACKING.setBoolean(false); DETERMINISM_SSTABLE_COMPRESSION_DEFAULT.setBoolean(false); // compression causes variation in file size for e.g. UUIDs, IP addresses, random file paths CONSISTENT_DIRECTORY_LISTINGS.setBoolean(true); - TEST_IGNORE_SIGAR.setBoolean(true); SYSTEM_AUTH_DEFAULT_RF.setInt(3); DISABLE_GOSSIP_ENDPOINT_REMOVAL.setBoolean(true); MEMTABLE_OVERHEAD_SIZE.setInt(100); diff --git a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java index b4da790360..8df889a5bd 100644 --- a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java +++ b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java @@ -276,6 +276,7 @@ public class DatabaseDescriptorRefTest "org.apache.cassandra.utils.CloseableIterator", "org.apache.cassandra.utils.FBUtilities", "org.apache.cassandra.utils.FBUtilities$1", + "org.apache.cassandra.utils.SystemInfo", "org.apache.cassandra.utils.Pair", "org.apache.cassandra.utils.binlog.BinLogOptions", "org.apache.cassandra.utils.concurrent.RefCounted", diff --git a/test/unit/org/apache/cassandra/service/StartupChecksTest.java b/test/unit/org/apache/cassandra/service/StartupChecksTest.java index 6916f35424..d5ed25a89f 100644 --- a/test/unit/org/apache/cassandra/service/StartupChecksTest.java +++ b/test/unit/org/apache/cassandra/service/StartupChecksTest.java @@ -57,6 +57,7 @@ import org.apache.cassandra.schema.SchemaConstants; import org.apache.cassandra.service.DataResurrectionCheck.Heartbeat; import org.apache.cassandra.utils.Clock; import org.apache.cassandra.utils.FBUtilities; +import org.apache.cassandra.utils.SystemInfo; import static java.util.Collections.singletonList; import static org.apache.cassandra.config.CassandraRelevantProperties.TEST_INVALID_LEGACY_SSTABLE_ROOT; @@ -312,14 +313,21 @@ public class StartupChecksTest String savedCommitLogLocation = DatabaseDescriptor.getCommitLogLocation(); DiskAccessMode savedCommitLogWriteDiskAccessMode = DatabaseDescriptor.getCommitLogWriteDiskAccessMode(); - Semver savedKernelVersion = FBUtilities.getKernelVersion(); + SystemInfo savedSystemInfo = FBUtilities.getSystemInfo(); try { DatabaseDescriptor.setCommitLogLocation(commitLogLocation); DatabaseDescriptor.setCommitLogWriteDiskAccessMode(diskAccessMode); DatabaseDescriptor.initializeCommitLogDiskAccessMode(); assertThat(DatabaseDescriptor.getCommitLogWriteDiskAccessMode()).isEqualTo(diskAccessMode); - FBUtilities.setKernelVersionSupplier(() -> kernelVersion); + FBUtilities.setSystemInfoSupplier(() -> new SystemInfo() + { + @Override + public Semver getKernelVersion() + { + return kernelVersion; + } + }); withPathOverriddingFileSystem(Map.of(commitLogLocation, fsType), () -> { if (expectToFail) assertThatExceptionOfType(StartupException.class).isThrownBy(() -> StartupChecks.checkKernelBug1057843.execute(options)); @@ -333,7 +341,7 @@ public class StartupChecksTest DatabaseDescriptor.setCommitLogLocation(savedCommitLogLocation); DatabaseDescriptor.setCommitLogWriteDiskAccessMode(savedCommitLogWriteDiskAccessMode); DatabaseDescriptor.initializeCommitLogDiskAccessMode(); - FBUtilities.setKernelVersionSupplier(() -> savedKernelVersion); + FBUtilities.setSystemInfoSupplier(() -> savedSystemInfo); } } diff --git a/test/unit/org/apache/cassandra/utils/FBUtilitiesTest.java b/test/unit/org/apache/cassandra/utils/FBUtilitiesTest.java index 28059f5784..17b59400e7 100644 --- a/test/unit/org/apache/cassandra/utils/FBUtilitiesTest.java +++ b/test/unit/org/apache/cassandra/utils/FBUtilitiesTest.java @@ -59,9 +59,7 @@ import org.apache.cassandra.dht.Murmur3Partitioner; import org.apache.cassandra.dht.OrderPreservingPartitioner; import org.apache.cassandra.dht.RandomPartitioner; -import static org.apache.cassandra.utils.FBUtilities.parseKernelVersion; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -409,20 +407,6 @@ public class FBUtilitiesTest Assert.assertEquals("Infinity", FBUtilities.prettyPrintAverage(Double.POSITIVE_INFINITY)); } - @Test - public void testParseKernelVersion() - { - assertThat(parseKernelVersion("4.4.0-21-generic").toString()).isEqualTo("4.4.0-21-generic"); - assertThat(parseKernelVersion("4.4.0-pre21-generic").toString()).isEqualTo("4.4.0-pre21-generic"); - assertThat(parseKernelVersion("4.4-pre21-generic").toString()).isEqualTo("4.4-pre21-generic"); - assertThat(parseKernelVersion("4.4.0-21-generic\n").toString()).isEqualTo("4.4.0-21-generic"); - assertThat(parseKernelVersion("\n4.4.0-21-generic\n").toString()).isEqualTo("4.4.0-21-generic"); - assertThat(parseKernelVersion("\n 4.4.0-21-generic \n").toString()).isEqualTo("4.4.0-21-generic"); - - assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> parseKernelVersion("\n \n")) - .withMessageContaining("no version found"); - } - @Test public void testGetKernelVersion() { diff --git a/test/unit/org/apache/cassandra/utils/SystemInfoTest.java b/test/unit/org/apache/cassandra/utils/SystemInfoTest.java new file mode 100644 index 0000000000..61fec64818 --- /dev/null +++ b/test/unit/org/apache/cassandra/utils/SystemInfoTest.java @@ -0,0 +1,180 @@ +/* + * 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 java.util.Optional; + +import org.junit.Assume; +import org.junit.Test; + +import com.vdurmont.semver4j.Semver; +import oshi.PlatformEnum; + +import static org.apache.cassandra.utils.SystemInfo.ADDRESS_SPACE_VIOLATION_MESSAGE; +import static org.apache.cassandra.utils.SystemInfo.NUMBER_OF_PROCESSES_VIOLATION_MESSAGE; +import static org.apache.cassandra.utils.SystemInfo.OPEN_FILES_VIOLATION_MESSAGE; +import static org.apache.cassandra.utils.SystemInfo.SWAP_VIOLATION_MESSAGE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class SystemInfoTest +{ + private static class TestSystemInfo extends SystemInfo + { + @Override + public PlatformEnum platform() + { + return PlatformEnum.LINUX; + } + + @Override + public long getMaxProcess() + { + return EXPECTED_MIN_NUMBER_OF_PROCESSES; + } + + @Override + public long getMaxOpenFiles() + { + return EXPECTED_MIN_NUMBER_OF_OPENED_FILES; + } + + @Override + public long getVirtualMemoryMax() + { + return EXPECTED_ADDRESS_SPACE; + } + + @Override + public long getSwapSize() + { + return 0; + } + } + + @Test + public void testSystemInfo() + { + SystemInfo oldSystemInfo = FBUtilities.getSystemInfo(); + + try + { + // valid testing system info does not violate anything + TestSystemInfo testSystemInfo = new TestSystemInfo(); + assertFalse(testSystemInfo.isDegraded().isPresent()); + + // platform + + assertDegradation(new TestSystemInfo() + { + @Override + public PlatformEnum platform() + { + return PlatformEnum.FREEBSD; + } + }, "System is running FREEBSD, Linux OS is recommended. "); + + // swap + + + assertDegradation(new TestSystemInfo() + { + @Override + public long getSwapSize() + { + return 100; + } + }, SWAP_VIOLATION_MESSAGE); + + // address space + + assertDegradation(new TestSystemInfo() + { + @Override + public long getVirtualMemoryMax() + { + return 1234; + } + }, ADDRESS_SPACE_VIOLATION_MESSAGE); + + // expected minimal number of opened files + + assertDegradation(new TestSystemInfo() + { + @Override + public long getMaxOpenFiles() + { + return 10; + } + }, OPEN_FILES_VIOLATION_MESSAGE); + + // expected number of processes + + assertDegradation(new TestSystemInfo() + { + @Override + public long getMaxProcess() + { + return 5; + } + }, NUMBER_OF_PROCESSES_VIOLATION_MESSAGE); + + // test multiple violations + + assertDegradation(new TestSystemInfo() + { + @Override + public PlatformEnum platform() + { + return PlatformEnum.FREEBSD; + } + + @Override + public long getSwapSize() + { + return 10; + } + }, "System is running FREEBSD, Linux OS is recommended. " + SWAP_VIOLATION_MESSAGE); + } + finally + { + FBUtilities.setSystemInfoSupplier(() -> oldSystemInfo); + } + } + + @Test + public void testGetKernelVersion() + { + Assume.assumeTrue(FBUtilities.isLinux); + Semver kernelVersion = FBUtilities.getSystemInfo().getKernelVersion(); + assertThat(kernelVersion).isGreaterThan(new Semver("0.0.0", Semver.SemverType.LOOSE)) + .isLessThan(new Semver("100.0.0", Semver.SemverType.LOOSE)); + } + + private void assertDegradation(final SystemInfo systemInfo, String expectedDegradation) + { + FBUtilities.setSystemInfoSupplier(() -> systemInfo); + Optional<String> degradations = FBUtilities.getSystemInfo().isDegraded(); + + assertTrue(degradations.isPresent()); + assertEquals(expectedDegradation, degradations.get()); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org