Add JDK21 support

Patch by Josh McKenzie; reviewed by Mick Semb Wever and Ekaterina Dimitrova for CASSANDRA-18831

Co-authored-by: Aleksey Yeschenko
Co-authored-by: Achilles Benetopoulos
Co-authored-by: Mick Semb Wever
This commit is contained in:
Josh McKenzie 2024-11-19 13:27:03 -05:00 committed by Josh McKenzie
parent 4184e759de
commit 940739a488
87 changed files with 1182 additions and 672 deletions

View File

@ -56,7 +56,8 @@ fi
################################
if grep "^ID=" /etc/os-release | grep -q 'debian\|ubuntu' ; then
sudo update-java-alternatives --set java-1.${java_version}.0-openjdk-$(dpkg --print-architecture)
sudo update-alternatives --set java /usr/lib/jvm/java-${java_version}-openjdk-$(dpkg --print-architecture)/bin/java
sudo update-alternatives --set javac /usr/lib/jvm/java-${java_version}-openjdk-$(dpkg --print-architecture)/bin/javac
else
sudo alternatives --set java $(alternatives --display java | grep "family java-${java_version}-openjdk" | cut -d' ' -f1)
sudo alternatives --set javac $(alternatives --display javac | grep "family java-${java_version}-openjdk" | cut -d' ' -f1)

View File

@ -42,6 +42,7 @@ RUN yum -y install \
git \
java-11-openjdk-devel \
java-17-openjdk-devel \
java-21-openjdk-devel \
make \
rpm-build \
sudo \

View File

@ -18,5 +18,5 @@
#
# Creates the tarball artifact
$(dirname -- "$0")/_docker_run.sh bullseye-build.docker build-artifacts.sh $1
$(dirname -- "$0")/_docker_run.sh debian-build.docker build-artifacts.sh $1
exit $?

View File

@ -32,5 +32,5 @@ echo
#
# Creates the debian package
$(dirname -- "$0")/_docker_run.sh bullseye-build.docker docker/_build-debian.sh $1
$(dirname -- "$0")/_docker_run.sh debian-build.docker docker/_build-debian.sh $1
exit $?

View File

@ -18,5 +18,5 @@
#
# Build the jars
$(dirname -- "$0")/_docker_run.sh bullseye-build.docker build-jars.sh $1
$(dirname -- "$0")/_docker_run.sh debian-build.docker build-jars.sh $1
exit $?

View File

@ -20,4 +20,4 @@
export CASSANDRA_DOCKER_ANT_OPTS="-Ddependency-check.home.base=/tmp"
$(dirname -- "$0")/_docker_run.sh bullseye-build.docker check-code.sh $1
$(dirname -- "$0")/_docker_run.sh debian-build.docker check-code.sh $1

View File

@ -36,16 +36,31 @@ RUN echo 'Acquire::http::Timeout "60";' > /etc/apt/apt.conf.d/80proxy.conf
RUN echo 'Acquire::ftp::Timeout "60";' >> /etc/apt/apt.conf.d/80proxy.conf
# install deps
RUN until apt-get update \
&& apt-get -y install ant build-essential curl devscripts ed git sudo \
RUN until apt-get update && apt-get -y install ant build-essential curl devscripts ed git sudo \
python3-pip rsync procps dh-python quilt bash-completion ; \
do echo "apt failed… trying again in 10s… " ; sleep 10 ; done
RUN until apt-get update \
&& apt-get install -y --no-install-recommends openjdk-11-jdk openjdk-17-jdk ; \
RUN until apt-get install -y --no-install-recommends openjdk-11-jdk openjdk-17-jdk; \
do echo "apt failed… trying again in 10s… " ; sleep 10 ; done
RUN update-java-alternatives --set java-1.11.0-openjdk-$(dpkg --print-architecture)
# Download and install OpenJDK 21.0.2 for the current architecture
RUN sh -c '\
JDK_OS=linux ;\
JDK_TAR="openjdk-21.0.2_${JDK_OS}-$(uname -m | sed "s/x86_64/x64/")_bin.tar.gz" ;\
JDK_VERSION_SHAS="08db1392a48d4eb5ea5315cf8f18b89dbaf36cda663ba882cf03c704c9257ec2 a2def047a73941e01a73739f92755f86b895811afb1f91243db214cff5bdac3f 8fd09e15dc406387a0aba70bf5d99692874e999bf9cd9208b452b5d76ac922d3 b3d588e16ec1e0ef9805d8a696591bd518a5cea62567da8f53b5ce32d11d22e4" ;\
curl -L --fail --silent --retry 2 --retry-delay 5 --max-time 3600 "https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d69e91c558476027ac/13/GPL/${JDK_TAR}" -o $JDK_TAR ;\
JDK_SHA="$(sha256sum $JDK_TAR | cut -d" " -f2)" ;\
echo "$JDK_VERSION_SHAS" | sed "s/ /\n/g" | grep -q "$JDK_SHA" || { echo "SHA256 mismatch for $JDK_TAR $JDK_SHA"; exit 1; } ;\
mkdir -p /usr/lib/jvm/java-21-openjdk-$(dpkg --print-architecture) ;\
tar -C /usr/lib/jvm/java-21-openjdk-$(dpkg --print-architecture) --strip-components=1 -xzf $JDK_TAR ;\
rm $JDK_TAR'
# Add OpenJDK 21 to update-alternatives
RUN update-alternatives --install /usr/bin/java java /usr/lib/jvm/java-21-openjdk-$(dpkg --print-architecture)/bin/java 1
RUN update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/java-21-openjdk-$(dpkg --print-architecture)/bin/javac 1
RUN update-alternatives --set java /usr/lib/jvm/java-11-openjdk-$(dpkg --print-architecture)/bin/java
RUN update-alternatives --set javac /usr/lib/jvm/java-11-openjdk-$(dpkg --print-architecture)/bin/javac
# python3 is needed for the gen-doc target
RUN pip install --upgrade pip
@ -58,11 +73,8 @@ RUN sh -c '\
GO_VERSION="1.24.3" ;\
GO_VERSION_SHAS="3333f6ea53afa971e9078895eaa4ac7204a8c6b5c68c10e6bc9a33e8e391bdd8 a463cb59382bd7ae7d8f4c68846e73c4d589f223c589ac76871b66811ded7836 13e6fe3fcf65689d77d40e633de1e31c6febbdbcb846eb05fc2434ed2213e92b 64a3fa22142f627e78fac3018ce3d4aeace68b743eff0afda8aae0411df5e4fb" ;\
GO_OS=linux ;\
[ $(uname) = "Darwin" ] && GO_OS=darwin ;\
GO_PLATFORM=amd64 ;\
[ $(uname -m) = "aarch64" ] && GO_PLATFORM=arm64 ;\
GO_TAR="go${GO_VERSION}.${GO_OS}-${GO_PLATFORM}.tar.gz" ;\
curl -L --fail --silent --retry 2 --retry-delay 5 --max-time 30 https://go.dev/dl/$GO_TAR -o $GO_TAR ;\
GO_TAR="go${GO_VERSION}.${GO_OS}-$(dpkg --print-architecture).tar.gz" ;\
curl -L --fail --silent --retry 2 --retry-delay 5 --max-time 3600 https://go.dev/dl/$GO_TAR -o $GO_TAR ;\
GO_SHA="$(sha256sum $GO_TAR | cut -d" " -f2)" ;\
echo "$GO_VERSION_SHAS" | sed "s/ /\n/g" | grep -q "$GO_SHA" || { echo "SHA256 mismatch for $GO_TAR $GO_SHA"; exit 1; } ;\
tar -C /usr/local -xzf $GO_TAR ;\
@ -71,3 +83,10 @@ RUN sh -c '\
ENV GOROOT="/usr/local/go"
ENV GOPATH="$BUILD_HOME/go"
ENV PATH="$PATH:/usr/local/go/bin"
# allow lower UIDs and GIDs
RUN sed -i 's/UID_MIN 1000/UID_MIN 100/' /etc/login.defs
RUN sed -i 's/UID_MIN 1000/UID_MIN 10/' /etc/login.defs
# suppress warnings about mismatching ownership
RUN git config --global --add safe.directory ${CASSANDRA_DIR}

View File

@ -134,7 +134,7 @@ docker --version
pushd ${cassandra_dir}/.build >/dev/null
# build test image
dockerfile="ubuntu2004_test.docker"
dockerfile="ubuntu-test.docker"
image_tag="$(md5sum docker/${dockerfile} | cut -d' ' -f1)"
image_name="apache/cassandra-${dockerfile/.docker/}:${image_tag}"
docker_mounts="-v ${cassandra_dir}:/home/cassandra/cassandra -v "${build_dir}":/home/cassandra/cassandra/build -v ${m2_dir}:/home/cassandra/.m2/repository"

View File

@ -11,7 +11,7 @@
# limitations under the License.
FROM ubuntu:20.04
MAINTAINER Apache Cassandra <dev@cassandra.apache.org>
LABEL org.opencontainers.image.authors="Apache Cassandra <dev@cassandra.apache.org>"
# CONTEXT is expected to be cassandra/.build
@ -52,7 +52,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3.11 python3.11-venv python3.11-dev \
virtualenv net-tools libev4 libev-dev wget gcc libxml2 libxslt1-dev \
vim lsof sudo libjemalloc2 dumb-init locales rsync \
openjdk-8-jdk openjdk-11-jdk openjdk-17-jdk ant ant-optional
openjdk-8-jdk openjdk-11-jdk openjdk-17-jdk openjdk-21-jdk ant ant-optional
RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.8 2
@ -71,8 +71,9 @@ RUN chmod 0644 /opt/requirements.txt
RUN pip3 install virtualenv virtualenv-clone
RUN pip3 install --upgrade wheel
# make Java 8 the default executable (we use to run all tests against Java 8)
RUN update-java-alternatives --set java-1.8.0-openjdk-$(dpkg --print-architecture)
# make Java 11 the default executable
RUN update-alternatives --set java /usr/lib/jvm/java-11-openjdk-$(dpkg --print-architecture)/bin/java
RUN update-alternatives --set javac /usr/lib/jvm/java-11-openjdk-$(dpkg --print-architecture)/bin/javac
# enable legacy TLSv1 and TLSv1.1 (CASSANDRA-16848)
RUN find /etc -type f -name java.security -exec sed -i 's/TLSv1, TLSv1.1//' {} \;

View File

@ -36,8 +36,8 @@
</license>
</licenses>
<properties>
<bytebuddy.version>1.12.13</bytebuddy.version>
<byteman.version>4.0.20</byteman.version>
<bytebuddy.version>1.17.8</bytebuddy.version>
<byteman.version>4.0.26</byteman.version>
<netty.version>4.1.130.Final</netty.version>
<ohc.version>0.5.1</ohc.version>
<async-profiler.version>4.2</async-profiler.version>
@ -494,13 +494,13 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.7.0</version>
<version>5.12.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>4.7.0</version>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
@ -891,7 +891,8 @@
<dependency>
<groupId>net.openhft</groupId>
<artifactId>chronicle-queue</artifactId>
<version>5.23.37</version>
<!-- chronicle ea builds before the corresponding Final are code identical; Final builds are not made available on Maven -->
<version>5.25ea16</version>
<exclusions>
<exclusion>
<artifactId>tools</artifactId>
@ -907,7 +908,12 @@
<dependency>
<groupId>net.openhft</groupId>
<artifactId>chronicle-core</artifactId>
<version>2.23.36</version>
<!-- While we broadly don't want to use ea libraries in the project, the Chronicle ecosystem has moved
to an approach of only allowing paid usage for non-ea builds. The ea builds are identical to the .0 release
of the next major version, so "ea" in this context signifies "stable GA build" for this major release line.
We plan to move away from chronicle for this and other reasons; the details of the conversation on the mailing
list can be found here: https://issues.apache.org/jira/browse/CASSANDRA-18831?focusedCommentId=17902034&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-17902034 -->
<version>2.25ea14</version>
<exclusions>
<exclusion>
<artifactId>chronicle-analytics</artifactId>
@ -922,7 +928,8 @@
<dependency>
<groupId>net.openhft</groupId>
<artifactId>chronicle-bytes</artifactId>
<version>2.23.33</version>
<!-- See above for details about exception re: inclusion of ea lib -->
<version>2.25ea10</version>
<exclusions>
<exclusion>
<artifactId>annotations</artifactId>
@ -933,7 +940,8 @@
<dependency>
<groupId>net.openhft</groupId>
<artifactId>chronicle-wire</artifactId>
<version>2.23.39</version>
<!-- See above for details about exception re: inclusion of ea lib -->
<version>2.25ea15</version>
<exclusions>
<exclusion>
<artifactId>compiler</artifactId>
@ -949,7 +957,8 @@
<dependency>
<groupId>net.openhft</groupId>
<artifactId>chronicle-threads</artifactId>
<version>2.23.25</version>
<!-- See above for details about exception re: inclusion of ea lib -->
<version>2.25ea7</version>
<exclusions>
<exclusion>
<!-- pulls in affinity-3.23ea1 which pulls in third-party-bom-3.22.4-SNAPSHOT -->

View File

@ -138,7 +138,7 @@ set -e # enable immediate exit if venv setup fails
# fresh virtualenv and test logs results everytime
[[ "/" == "${DIST_DIR}" ]] || rm -rf "${DIST_DIR}/venv" "${DIST_DIR}/test/{html,output,logs}"
# re-use when possible the pre-installed virtualenv found in the cassandra-ubuntu2004_test docker image
# re-use when possible the pre-installed virtualenv found in the cassandra2004_test docker image
virtualenv-clone ${BUILD_HOME}/env${python_version} ${DIST_DIR}/venv || virtualenv --python=python${python_version} ${DIST_DIR}/venv
source ${DIST_DIR}/venv/bin/activate
pip3 install --exists-action w -r ${CASSANDRA_DTEST_DIR}/requirements.txt

View File

@ -254,7 +254,11 @@ _run_testlist() {
for ((i=0; i < _test_iterations; i++)); do
[ "${_test_iterations}" -eq 1 ] || printf " run ${i}\n"
set +o errexit
ant "$_testlist_target" -Dtest.classlistprefix="${_target_prefix}" -Dtest.classlistfile=<(echo "${testlist}") -Dtest.timeout="${_test_timeout}" ${ANT_TEST_OPTS}
ant "$_testlist_target" \
-Dtest.classlistprefix="${_target_prefix}" \
-Dtest.classlistfile=<(echo "${testlist}") \
-Dtest.timeout="${_test_timeout}" \
${ANT_TEST_OPTS}
ant_status=$?
set -o errexit
if [[ $ant_status -ne 0 ]]; then

View File

@ -352,7 +352,7 @@ def build(command, cell) {
test -f .jenkins/Jenkinsfile || { echo "Invalid git fork/branch"; exit 1; }
grep -q "Jenkins CI declaration" .jenkins/Jenkinsfile || { echo "Only Cassandra 5.0+ supported"; exit 1; }
"""
fetchDockerImages("redhat" == cell.step ? ['almalinux-build'] : ['bullseye-build'])
fetchDockerImages("redhat" == cell.step ? ['almalinux-build'] : ['debian-build'])
def cell_suffix = "_jdk${cell.jdk}_${cell.arch}"
def logfile = "stage-logs/${JOB_NAME}_${BUILD_NUMBER}_${cell.step}${cell_suffix}_attempt${attempt}.log.xz"
def script_vars = "#!/bin/bash \n set -o pipefail ; " // pipe to tee needs pipefail
@ -391,7 +391,7 @@ def test(command, cell) {
withEnv(cell.collect { k, v -> "${k}=${v}" }) {
ws("workspace/${JOB_NAME}/${BUILD_NUMBER}/${cell.step}/${cell.arch}/jdk-${cell.jdk}/python-${cell.python}") {
fetchSource(cell.step, cell.arch, cell.jdk)
fetchDockerImages(['ubuntu2004_test'])
fetchDockerImages(['ubuntu-test'])
def cell_suffix = "_jdk${cell.jdk}_python_${cell.python}_${cell.cython}_${cell.arch}_${cell.split}_${splits}"
def logfile = "stage-logs/${JOB_NAME}_${BUILD_NUMBER}_${cell.step}${cell_suffix}_attempt${attempt}.log.xz"
def script_vars = "#!/bin/bash \n set -o pipefail ; " // pipe to tee needs pipefail
@ -594,11 +594,11 @@ def generateTestReports() {
echo "Report for \${target} (\$(find build/test/output/\${target} -name '*.xml' | wc -l) test files)"
CASSANDRA_DOCKER_ANT_OPTS="-Dbuild.test.output.dir=build/test/output/\${target} -Dbuild.test.report.dir=build/test/reports/\${target}"
export CASSANDRA_DOCKER_ANT_OPTS
.build/docker/_docker_run.sh bullseye-build.docker ci/generate-test-report.sh
.build/docker/_docker_run.sh debian-build.docker ci/generate-test-report.sh
fi
done
.build/docker/_docker_run.sh bullseye-build.docker ci/generate-ci-summary.sh || echo "failed generate-ci-summary.sh"
.build/docker/_docker_run.sh debian-build.docker ci/generate-ci-summary.sh || echo "failed generate-ci-summary.sh"
tar -cf build/results_details.tar -C build/test/ reports
xz -8f build/results_details.tar ) ${teeSuffix}

View File

@ -80,6 +80,9 @@ using the provided 'sstableupgrade' tool.
New features
------------
- JDK21 and Generational ZGC are now officially supported and generational ZGC is now the default Garbage Collector
when using JDK21. See jvm21-server.options for more details and configuration parameters. We do not recommend using
non-generational ZGC with Apache Cassandra.
[The following is a placeholder, to be revised asap]
- CEP-37 Auto Repair is a fully automated scheduler that provides repair orchestration within Apache Cassandra. This
significantly reduces operational overhead by eliminating the need for operators to deploy external tools to submit
@ -205,6 +208,11 @@ Upgrading
Deprecation
-----------
- `use_deterministic_table_id` is no longer supported and should be removed from cassandra.yaml. Table IDs may still be supplied explicitly on CREATE.
- Updating dependencies for JDK21 necessitated updating Chronicle Queue, which has changed the enums used for log
rolling (cassandra.yaml -> full_query_logging_options:roll_cycle). Older legacy options will still work for the
foreseeable future but you will see warnings in logs and future dependency upgrades may break your log rolling param.
The default log rolling param has been changed from HOURLY to FAST_HOURLY, primarily different on how frequently
indexes are built (256 in FAST_HOURLY vs. 16 in HOURLY).
- IEndpointSnitch has been deprecated as ClusterMetadata is now the source of truth regarding topology information.
The responsibilities of the snitch have been broken out to a handful of new classes:
* o.a.c.locator.Locator provides datacenter and rack info for endpoints. This is not configurable as topology is

View File

@ -114,56 +114,36 @@ if [ -z $JAVA ] ; then
fi
# Matches variable 'java.supported' in build.xml
java_versions_supported=11,17
java_versions_supported="11 17 21"
java_version_string=$(IFS=" "; echo "${java_versions_supported}")
# Determine the sort of JVM we'll be running on.
java_ver_output=`"${JAVA:-java}" -version 2>&1`
jvmver=`echo "$java_ver_output" | grep '[openjdk|java] version' | awk -F'"' 'NR==1 {print $2}' | cut -d\- -f1`
JVM_VERSION=${jvmver%_*}
short=$(echo "${jvmver}" | cut -c1-2)
JAVA_VERSION=$(java -version 2>&1 | grep '[openjdk|java] version' | cut -d '"' -f2 | cut -d '.' -f1)
# Unsupported JDKs below the upper supported version are not allowed
if [ "$short" != "$(echo "$java_versions_supported" | cut -d, -f1)" ] && [ "$JVM_VERSION" \< "$(echo "$java_versions_supported" | cut -d, -f2)" ] ; then
echo "Unsupported Java $JVM_VERSION. Supported are $java_versions_supported"
exit 1;
supported=0
for version in ${java_versions_supported}; do
if [ "$version" -eq "$JAVA_VERSION" ]; then
supported=1
fi
# Allow execution of supported Java versions, and newer if CASSANDRA_JDK_UNSUPPORTED is set
is_supported_version=$(echo "$java_versions_supported" | tr "," '\n' | grep -F -x "$short")
if [ -z "$is_supported_version" ] ; then
done
if [ "$supported" -eq 0 ]; then
if [ -z "$CASSANDRA_JDK_UNSUPPORTED" ]; then
echo "Unsupported Java $JVM_VERSION. Supported are $java_versions_supported"
echo "Unsupported Java $JAVA_VERSION. Supported are $java_version_string"
echo "If you would like to test with newer Java versions set CASSANDRA_JDK_UNSUPPORTED to any value (for example, CASSANDRA_JDK_UNSUPPORTED=true). Unset the parameter for default behavior"
exit 1;
exit 1
else
echo "######################################################################"
echo "Warning! You are using JDK$short. This Cassandra version only supports $java_versions_supported."
echo "Warning! You are using JDK$JAVA_VERSION. This Cassandra version only supports $java_version_string"
echo "######################################################################"
fi
fi
JAVA_VERSION=$short
jvm=`echo "$java_ver_output" | grep -A 1 '[openjdk|java] version' | awk 'NR==2 {print $1}'`
case "$jvm" in
OpenJDK)
JVM_VENDOR=OpenJDK
# this will be "64-Bit" or "32-Bit"
JVM_ARCH=`echo "$java_ver_output" | awk 'NR==3 {print $2}'`
;;
"Java(TM)")
JVM_VENDOR=Oracle
# this will be "64-Bit" or "32-Bit"
JVM_ARCH=`echo "$java_ver_output" | awk 'NR==3 {print $3}'`
;;
*)
# Help fill in other JVM values
JVM_VENDOR=other
JVM_ARCH=unknown
;;
esac
# Read user-defined JVM options from jvm-server.options file
JVM_OPTS_FILE=$CASSANDRA_CONF/jvm${jvmoptions_variant:--clients}.options
if [ $JAVA_VERSION -ge 17 ] ; then
if [ $JAVA_VERSION -ge 21 ] ; then
JVM_DEP_OPTS_FILE=$CASSANDRA_CONF/jvm21${jvmoptions_variant:--clients}.options
elif [ $JAVA_VERSION -ge 17 ] ; then
JVM_DEP_OPTS_FILE=$CASSANDRA_CONF/jvm17${jvmoptions_variant:--clients}.options
elif [ $JAVA_VERSION -ge 11 ] ; then
JVM_DEP_OPTS_FILE=$CASSANDRA_CONF/jvm11${jvmoptions_variant:--clients}.options

110
build.xml
View File

@ -45,7 +45,7 @@
The use of both CASSANDRA_USE_JDK11 and use-jdk11 is deprecated.
-->
<property name="java.default" value="11" />
<property name="java.supported" value="11,17" />
<property name="java.supported" value="11,17,21" />
<!-- directory details -->
<property name="basedir" value="."/>
@ -173,7 +173,7 @@
<!-- When updating ASM, please, do consider whether you might need to update also FBUtilities#ASM_BYTECODE_VERSION
and the simulator InterceptClasses#BYTECODE_VERSION, in particular if we are looking to provide Cassandra support
for newer JDKs (CASSANDRA-17873). -->
<property name="asm.version" value="9.4"/>
<property name="asm.version" value="9.5"/>
<property name="allocation-instrumenter.version" value="3.1.0"/>
<condition property="is.source.artifact">
@ -323,14 +323,82 @@
<string>--add-opens java.base/java.lang=ALL-UNNAMED</string>
<string>--add-opens java.base/java.util=ALL-UNNAMED</string>
<string>--add-opens java.base/java.nio=ALL-UNNAMED</string>
<string>--add-opens java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED</string>
<!-- Needed for in-jvm dtests straddling 6.0+ -->
<string>--add-opens java.base/java.util.concurrent=ALL-UNNAMED</string>
<string>--add-opens java.base/java.util.concurrent.atomic=ALL-UNNAMED</string>
</resources>
<pathconvert property="_jvm17_args_concat" refid="_jvm17_arg_items" pathsep=" "/>
<condition property="java-jvmargs" value="${_jvm17_args_concat}">
<equals arg1="${ant.java.version}" arg2="17"/>
</condition>
<resources id="_jvm21_arg_items">
<string>-Djdk.attach.allowAttachSelf=true</string>
<string>-XX:+UseZGC</string>
<string>-XX:+ZGenerational</string>
<!-- Temporary workaround for jamm having incorrect default CompressedOops for JDK21 -->
<!-- Without this, memory layout and sizing calculations will be incorrect as jamm assumes compressedOops -->
<string>-XX:-UseCompressedOops</string>
<!-- <string>-XX:+UseLargePages</string> -->
<!-- Max size ZGC will _attempt_ to stay below -->
<!-- <string>-XX:+SoftMaxHeapSize=12G</string> -->
<!-- Disable returning memory to the OS -->
<!-- <string>-XX:-ZUncommit</string> -->
<!-- Time memory should have been unused before eligible for uncommit in seconds -->
<!-- <string>-XX:ZUncommitDelay=300</string> -->
<!-- Pay the tax up front to pretouch memory to smooth out latency later -->
<!-- <string>-XX:+AlwaysPreTouch</string> -->
<!-- Need to explicitly allow security manager on JDK21; deprecated for removal -->
<string>-Djava.security.manager=allow</string>
<string>--add-exports java.base/java.lang.ref=ALL-UNNAMED</string>
<string>--add-exports java.base/java.lang.reflect=ALL-UNNAMED</string>
<string>--add-exports java.base/jdk.internal.misc=ALL-UNNAMED</string>
<string>--add-exports java.base/jdk.internal.ref=ALL-UNNAMED</string>
<string>--add-exports java.base/sun.nio.ch=ALL-UNNAMED</string>
<string>--add-exports java.management.rmi/com.sun.jmx.remote.internal.rmi=ALL-UNNAMED</string>
<string>--add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED</string>
<string>--add-exports java.rmi/sun.rmi.server=ALL-UNNAMED</string>
<string>--add-exports java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED</string>
<string>--add-exports java.sql/java.sql=ALL-UNNAMED</string>
<string>--add-exports jdk.unsupported/sun.misc=ALL-UNNAMED</string>
<string>--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</string>
<string>--add-exports jdk.attach/sun.tools.attach=ALL-UNNAMED</string>
<string>--add-opens java.base/java.io=ALL-UNNAMED</string>
<string>--add-opens java.base/java.lang=ALL-UNNAMED</string>
<string>--add-opens java.base/java.lang.module=ALL-UNNAMED</string>
<string>--add-opens java.base/java.lang.reflect=ALL-UNNAMED</string>
<string>--add-opens java.base/java.math=ALL-UNNAMED</string>
<string>--add-opens java.base/java.net=ALL-UNNAMED</string>
<string>--add-opens java.base/java.nio=ALL-UNNAMED</string>
<string>--add-opens java.base/java.util=ALL-UNNAMED</string>
<string>--add-opens java.base/java.util.concurrent=ALL-UNNAMED</string>
<string>--add-opens java.base/java.util.concurrent.atomic=ALL-UNNAMED</string>
<string>--add-opens java.base/jdk.internal.loader=ALL-UNNAMED</string>
<string>--add-opens java.base/jdk.internal.math=ALL-UNNAMED</string>
<string>--add-opens java.base/jdk.internal.module=ALL-UNNAMED</string>
<string>--add-opens java.base/jdk.internal.ref=ALL-UNNAMED</string>
<string>--add-opens java.base/jdk.internal.reflect=ALL-UNNAMED</string>
<string>--add-opens java.base/sun.nio.ch=ALL-UNNAMED</string>
<string>--add-opens java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED</string>
<string>--add-opens jdk.management/com.sun.management=ALL-UNNAMED</string>
</resources>
<pathconvert property="_jvm21_args_concat" refid="_jvm21_arg_items" pathsep=" "/>
<condition property="java-jvmargs" value="${_jvm21_args_concat}" else="">
<equals arg1="${ant.java.version}" arg2="21"/>
</condition>
<!--
JVM arguments for tests.
@ -344,21 +412,48 @@
buffer construction (see CASSANDRA-16493)
-->
<resources id="_jvm11_test_arg_items">
<string>-XX:+HeapDumpOnOutOfMemoryError</string>
<string>-XX:-CMSClassUnloadingEnabled</string>
<string>-Dio.netty.tryReflectionSetAccessible=true</string>
<string>-XX:MaxMetaspaceSize=2G</string>
</resources>
<pathconvert property="_jvm11_test_arg_items_concat" refid="_jvm11_test_arg_items" pathsep=" "/>
<resources id="_jvm17_test_arg_items">
<string>-XX:+HeapDumpOnOutOfMemoryError</string>
<string>-Dio.netty.tryReflectionSetAccessible=true</string>
<!-- Open things up so we don't run into any jamm rejections that'd then go unsafe and crash out on in-jvm dtests -->
<string>--add-opens=java.base/java.lang=ALL-UNNAMED</string>
<string>--add-exports=java.base/jdk.internal.vm.annotation=ALL-UNNAMED</string>
</resources>
<pathconvert property="_jvm17_test_arg_items_concat" refid="_jvm17_test_arg_items" pathsep=" "/>
<resources id="_jvm21_test_arg_items">
<string>-XX:+HeapDumpOnOutOfMemoryError</string>
<string>-Dnet.bytebuddy.experimental=true</string>
<string>-Djava.security.manager=allow</string>
<string>-Dio.netty.tryReflectionSetAccessible=true</string>
<!-- Open things up so we don't run into any jamm rejections that'd then go unsafe and crash out on in-jvm dtests-->
<string>--add-opens=java.base/java.lang=ALL-UNNAMED</string>
<string>--add-exports=java.base/jdk.internal.vm.annotation=ALL-UNNAMED</string>
<!-- Revert to pre-JEP-416 Core Reflection implementation (without method handles) -->
<!-- without this, FieldUtils cannot overwrite static final fields, breaking some tests -->
<!-- removed in 22 (JDK-8309635) so will need a proper fix for 25 -->
<string>-Djdk.reflect.useDirectMethodHandle=false</string>
</resources>
<pathconvert property="_jvm21_test_arg_items_concat" refid="_jvm21_test_arg_items" pathsep=" "/>
<condition property="_std-test-jvmargs" value="${_jvm11_test_arg_items_concat}">
<equals arg1="${ant.java.version}" arg2="11"/>
</condition>
<condition property="_std-test-jvmargs" value="${_jvm17_test_arg_items_concat}">
<equals arg1="${ant.java.version}" arg2="17"/>
</condition>
<condition property="_std-test-jvmargs" value="${_jvm21_test_arg_items_concat}">
<equals arg1="${ant.java.version}" arg2="21"/>
</condition>
<!-- needed to compile org.apache.cassandra.utils.JMXServerUtils -->
<!-- needed to compile org.apache.cassandra.distributed.impl.Instance-->
@ -484,9 +579,13 @@
<target name="gen-cql3-grammar" depends="check-gen-cql3-grammar" unless="cql3current">
<echo>Building Grammar ${build.src.antlr}/Cql.g ...</echo>
<!-- antlr will crash on the first run on JDK21 and subsequently succeed if we don't fork it and execute in a separate JVM... -->
<java classname="org.antlr.Tool"
classpathref="cql3-grammar.classpath"
failonerror="true">
failonerror="true"
fork="true"
outputproperty="antlr.output"
errorproperty="antlr.error">
<arg value="-Xconversiontimeout" />
<arg value="10000" />
<arg value="${build.src.antlr}/Cql.g" />
@ -1237,6 +1336,8 @@
<jvmarg value="-ea"/>
<jvmarg value="-Djava.io.tmpdir=${tmp.dir}"/>
<jvmarg value="-Dcassandra.debugrefcount=true"/>
<!-- Pull this up for genZGC / JDK21 -->
<jvmarg value="-Xms512M"/>
<jvmarg value="${jvm_xss}"/>
<!-- When we do classloader manipulation SoftReferences can cause memory leaks
that can OOM our test runs. The next two settings informs our GC
@ -1491,6 +1592,7 @@
<test if="withMethods" name="${test.name}" methods="${test.methods}" todir="${build.test.output.dir}/" outfile="TEST-${test.name}-${test.methods}"/>
<test if="withoutMethods" name="${test.name}" todir="${build.test.output.dir}/" outfile="TEST-${test.name}"/>
<jvmarg value="-Dlogback.configurationFile=test/conf/logback-burntest.xml"/>
<jvmarg value="-Dnet.bytebuddy.experimental=true"/>
</testmacro>
</target>

View File

@ -100,6 +100,8 @@ echo $JVM_OPTS | grep -q UseConcMarkSweepGC
USING_CMS=$?
echo $JVM_OPTS | grep -q +UseG1GC
USING_G1=$?
echo $JVM_OPTS | grep -q +UseZGC
USING_ZGC=$?
calculate_heap_sizes
@ -177,6 +179,11 @@ if [ $DEFINED_XMN -eq 0 ] && [ $USING_G1 -eq 0 ]; then
exit 1
fi
# If a user tries to use -Xmn with ZGC we should let them know it's not going to work. Not worth killing the node over though.
if [ $DEFINED_XMN -eq 0 ] && [ $USING_ZGC -eq 0]; then
echo "-Xmn does nothing when used in conjunction with ZGC; this setting will be ignored."
fi
if [ $USING_G1 -eq 0 ] && [ $DEFINED_PARALLEL_GC_THREADS -ne 0 ] && [ $DEFINED_CONC_GC_THREADS -ne 0 ] ; then
# Set ParallelGCThreads and ConcGCThreads equal to number of cpu cores.
# Setting both to the same value is important to reduce STW durations.

View File

@ -2129,7 +2129,7 @@ audit_logging_options:
# excluded_categories:
# included_users:
# excluded_users:
# roll_cycle: HOURLY
# roll_cycle: FAST_HOURLY
# block: true
# max_queue_weight: 268435456 # 256 MiB
# max_log_size: 17179869184 # 16 GiB
@ -2144,7 +2144,7 @@ audit_logging_options:
# nodetool enablefullquerylog
# full_query_logging_options:
# log_dir:
# roll_cycle: HOURLY
# roll_cycle: FAST_HOURLY
# block: true
# max_queue_weight: 268435456 # 256 MiB
# max_log_size: 17179869184 # 16 GiB

View File

@ -185,6 +185,9 @@
# For production use you may wish to adjust this for your environment.
# If that's the case, see MAX_HEAP_SIZE (and HEAP_NEWSIZE for CMS) in cassandra-env.sh
# Need experimental bytebuddy for JDK21
-Dnet.bytebuddy.experimental
#####################
# OFF-HEAP SETTINGS #
#####################

View File

@ -0,0 +1,53 @@
#
# 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.
#
###########################################################################
# jvm21-clients.options #
# #
# See jvm-clients.options. This file is specific for Java 21 #
###########################################################################
###################
# JPMS SETTINGS #
###################
-Djdk.attach.allowAttachSelf=true
--add-exports java.base/java.lang.ref=ALL-UNNAMED
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED
--add-exports java.management.rmi/com.sun.jmx.remote.internal.rmi=ALL-UNNAMED
--add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED
--add-exports java.rmi/sun.rmi.server=ALL-UNNAMED
--add-exports java.sql/java.sql=ALL-UNNAMED
--add-exports jdk.unsupported/sun.misc=ALL-UNNAMED
--add-opens java.base/java.io=ALL-UNNAMED
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.lang.module=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
--add-opens java.base/java.nio=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens java.base/jdk.internal.math=ALL-UNNAMED
--add-opens java.base/jdk.internal.module=ALL-UNNAMED
--add-opens java.base/jdk.internal.ref=ALL-UNNAMED
--add-opens java.base/jdk.internal.reflect=ALL-UNNAMED
--add-opens java.base/sun.nio.ch=ALL-UNNAMED
--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED
# The newline in the end of file is intentional

146
conf/jvm21-server.options Normal file
View File

@ -0,0 +1,146 @@
#
# 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.
#
###########################################################################
# jvm21-server.options #
# #
# See jvm-server.options. This file is specific for Java 21 and newer. #
###########################################################################
#################
# GC SETTINGS #
#################
### Generational ZGC settings
-XX:+UseZGC
-XX:+ZGenerational
# Temporary workaround for jamm's incorrect default CompressedOops; if you're using ZGC this needs to be set
-XX:-UseCompressedOops
# Blanket enabling of all the THP / large pages available in the env
# -XX:+UseLargePages
# Max size ZGC will _attempt_ to stay below
# -XX:+SoftMaxHeapSize=12G
# Don't let ZGC return unclaimed memory to the OS by setting the following
# -XX:-ZUncommit
# Time memory should have been unused before eligible for uncommit in seconds
# -XX:ZUncommitDelay=300
# Tell GC to touch heap and allocate and fault in memory pages backing heap at startup. Can prevent later allocation pauses
# -XX:+AlwaysPreTouch
### G1 Settings
## Use the Hotspot garbage-first collector.
#-XX:+UseG1GC
#-XX:+ParallelRefProcEnabled
#-XX:MaxTenuringThreshold=2
#-XX:G1HeapRegionSize=16m
# Floor the young generation size to 50% of the heap size
#-XX:+UnlockExperimentalVMOptions
#-XX:G1NewSizePercent=50
# Have the JVM do less remembered set work during STW, instead
# preferring concurrent GC. Reduces p99.9 latency.
#-XX:G1RSetUpdatingPauseTimePercent=5
# Main G1GC tunable: lowering the pause target will lower throughput and vise versa.
# 200ms is the JVM default and lowest viable setting
# 1000ms increases throughput. Keep it smaller than the timeouts in cassandra.yaml.
#-XX:MaxGCPauseMillis=300
## Optional G1 Settings
# Save CPU time on large (>= 16GB) heaps by delaying region scanning
# until the heap is 70% full. The default in Hotspot 8u40 is 40%.
#-XX:InitiatingHeapOccupancyPercent=70
# For systems with > 8 cores, the default ParallelGCThreads is 5/8 the number of logical cores.
# Otherwise equal to the number of cores when 8 or less.
# Machines with > 10 cores should try setting these to <= full cores.
# By default, ConcGCThreads is 1/4 of ParallelGCThreads.
# Setting both to the same value can reduce STW durations.
# When leaving both unset then cassandra-env.sh will set them both to the number of your cores.
#-XX:ParallelGCThreads=16
#-XX:ConcGCThreads=16
### JPMS
-Djdk.attach.allowAttachSelf=true
--add-exports java.base/java.lang.ref=ALL-UNNAMED
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED
--add-exports java.management.rmi/com.sun.jmx.remote.internal.rmi=ALL-UNNAMED
--add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED
--add-exports java.rmi/sun.rmi.server=ALL-UNNAMED
--add-exports java.sql/java.sql=ALL-UNNAMED
--add-exports jdk.unsupported/sun.misc=ALL-UNNAMED
--add-opens java.base/java.io=ALL-UNNAMED
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.lang.module=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
--add-opens java.base/java.nio=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens java.base/jdk.internal.math=ALL-UNNAMED
--add-opens java.base/jdk.internal.module=ALL-UNNAMED
--add-opens java.base/jdk.internal.ref=ALL-UNNAMED
--add-opens java.base/jdk.internal.reflect=ALL-UNNAMED
--add-opens java.base/sun.nio.ch=ALL-UNNAMED
--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED
### GC logging options -- uncomment to enable
# Java 11 (and newer) GC logging options:
# See description of https://bugs.openjdk.java.net/browse/JDK-8046148 for details about the syntax
# The following is the equivalent to -XX:+PrintGCDetails -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=10M
#-Xlog:gc=info,heap*=trace,age*=debug,safepoint=info,promotion*=trace:file=/var/log/cassandra/gc.log:time,uptime,pid,tid,level:filecount=10,filesize=10485760
# Notes for Java 8 migration:
#
# -XX:+PrintGCDetails maps to -Xlog:gc*:... - i.e. add a '*' after "gc"
# -XX:+PrintGCDateStamps maps to decorator 'time'
#
# -XX:+PrintHeapAtGC maps to 'heap' with level 'trace'
# -XX:+PrintTenuringDistribution maps to 'age' with level 'debug'
# -XX:+PrintGCApplicationStoppedTime maps to 'safepoint' with level 'info'
# -XX:+PrintPromotionFailure maps to 'promotion' with level 'trace'
# -XX:PrintFLSStatistics=1 maps to 'freelist' with level 'trace'
### Netty Options
# On Java >= 9 Netty requires the io.netty.tryReflectionSetAccessible system property to be set to true to enable
# creation of direct buffers using Unsafe. Without it, this falls back to ByteBuffer.allocateDirect which has
# inferior performance and risks exceeding MaxDirectMemory
-Dio.netty.tryReflectionSetAccessible=true
# Revert changes in defaults introduced in https://netty.io/news/2022/03/10/4-1-75-Final.html
-Dio.netty.allocator.useCacheForAllThreads=true
-Dio.netty.allocator.maxOrder=11
# Need to explicitly allow security manager on JDK21; deprecated for removal
-Djava.security.manager=allow
# The newline in the end of file is intentional

4
debian/control vendored
View File

@ -3,7 +3,7 @@ Section: misc
Priority: extra
Maintainer: Eric Evans <eevans@apache.org>
Uploaders: Sylvain Lebresne <slebresne@apache.org>
Build-Depends: debhelper (>= 11), openjdk-17-jdk-headless | openjdk-11-jdk-headless | java17-sdk | java11-sdk, ant (>= 1.10), ant-optional (>= 1.10), dh-python, python3-dev (>= 3.6), quilt, bash-completion
Build-Depends: debhelper (>= 11), openjdk-21-jdk-headless | openjdk-17-jdk-headless | openjdk-11-jdk-headless | java21-sdk | java17-sdk | java11-sdk, ant (>= 1.10), ant-optional (>= 1.10), dh-python, python3-dev (>= 3.6), quilt, bash-completion
Homepage: https://cassandra.apache.org
Vcs-Git: https://gitbox.apache.org/repos/asf/cassandra.git
Vcs-Browser: https://gitbox.apache.org/repos/asf?p=cassandra.git
@ -11,7 +11,7 @@ Standards-Version: 3.8.3
Package: cassandra
Architecture: all
Depends: openjdk-17-jre-headless | openjdk-11-jre-headless | java17-runtime | java11-runtime, adduser, python3 (>= 3.6), procps, ${misc:Depends}
Depends: openjdk-21-jre-headless | openjdk-17-jre-headless | openjdk-11-jre-headless | java21-runtime | java17-runtime | java11-runtime, adduser, python3 (>= 3.6), procps, ${misc:Depends}
Recommends: ntp | time-daemon
Suggests: cassandra-tools
Conflicts: apache-cassandra1

View File

@ -1,14 +1,13 @@
= jvm-* files
Several files for JVM configuration are included in Cassandra. The
`jvm-server.options` file, and corresponding files `jvm8-server.options`
and `jvm11-server.options` are the main file for settings that affect
`jvm-server.options` file, and corresponding JDK specific files
`jvmN-server.options` are the main file for settings that affect
the operation of the Cassandra JVM on cluster nodes. The file includes
startup parameters, general JVM settings such as garbage collection, and
heap settings. The `jvm-clients.options` and corresponding
`jvm8-clients.options` and `jvm11-clients.options` files can be used to
configure JVM settings for clients like `nodetool` and the `sstable`
tools.
heap settings. Likewise, the `jvm-clients.options` and corresponding
`jvmN-clients.options` files can be used to configure JVM settings for
clients like `nodetool` and the `sstable` tools.
See each file for examples of settings.

View File

@ -190,9 +190,11 @@ To use `BinAuditLogger` as a logger in AuditLogging, set the logger to `BinAudit
oldest file. Default is set to `16L * 1024L * 1024L * 1024L`
`roll_cycle`::
How often to roll Audit log segments so they can potentially be
reclaimed. Available options are: MINUTELY, HOURLY, DAILY,
LARGE_DAILY, XLARGE_DAILY, HUGE_DAILY.For more options, refer:
net.openhft.chronicle.queue.RollCycles. Default is set to `"HOURLY"`
reclaimed. Some available options are:
`FIVE_MINUTELY, FAST_HOURLY, FAST_DAILY,
LargeRollCycles.LARGE_DAILY, LargeRollCycles.XLARGE_DAILY, LargeRollCycles.HUGE_DAILY.`
For more options, refer: net.openhft.chronicle.queue.RollCycles.
Default is set to `"FAST_HOURLY"`
== Configuring FileAuditLogger

View File

@ -151,6 +151,7 @@
-Dcassandra.storagedir=$PROJECT_DIR$/data
-Dlogback.configurationFile=file://$PROJECT_DIR$/conf/logback.xml
-XX:HeapDumpPath=build/test
-Dnet.bytebuddy.experimental=true
-ea" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" />
@ -217,6 +218,8 @@
-XX:MaxMetaspaceSize=2G
-XX:ReservedCodeCacheSize=256M
-XX:Tier4CompileThreshold=1000
-XX:SoftRefLRUPolicyMSPerMB=0
-Dnet.bytebuddy.experimental=true
-ea" />
<option name="PARAMETERS" value="" />
<fork_mode value="class" />
@ -248,6 +251,7 @@
-Dlogback.configurationFile=file://$PROJECT_DIR$/conf/logback.xml
-XX:HeapDumpPath=build/test
-Xmx1G
-Dnet.bytebuddy.experimental=true
-ea" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />

View File

@ -59,7 +59,7 @@ set -e # enable immediate exit if venv setup fails
# fresh virtualenv and test logs results everytime
rm -fr ${DIST_DIR}/venv ${DIST_DIR}/test/{html,output,logs}
# re-use when possible the pre-installed virtualenv found in the cassandra-ubuntu2004_test docker image
# re-use when possible the pre-installed virtualenv found in the cassandra12004_test docker image
virtualenv-clone ${BUILD_HOME}/env${python_version} ${BUILD_DIR}/venv || virtualenv --python=python3 ${BUILD_DIR}/venv
source ${BUILD_DIR}/venv/bin/activate

View File

@ -121,57 +121,39 @@ if [ -z $JAVA ] ; then
exit 1;
fi
# TODO: Factor this out to something we source so we don't have the duplication all over our scripts
# Matches variable 'java.supported' in build.xml
java_versions_supported=11,17
java_versions_supported=(11 17 21)
java_version_string=$(IFS=" "; echo "${java_versions_supported[*]}")
# Determine the sort of JVM we'll be running on.
java_ver_output=`"${JAVA:-java}" -version 2>&1`
jvmver=`echo "$java_ver_output" | grep '[openjdk|java] version' | awk -F'"' 'NR==1 {print $2}' | cut -d\- -f1`
JVM_VERSION=${jvmver%_*}
short=$(echo "${jvmver}" | cut -c1-2)
JAVA_VERSION=$(java -version 2>&1 | grep '[openjdk|java] version' | cut -d '"' -f2 | cut -d '.' -f1)
# Unsupported JDKs below the upper supported version are not allowed
if [ "$short" != "$(echo "$java_versions_supported" | cut -d, -f1)" ] && [ "$JVM_VERSION" \< "$(echo "$java_versions_supported" | cut -d, -f2)" ] ; then
echo "Unsupported Java $JVM_VERSION. Supported are $java_versions_supported"
exit 1;
supported=0
for version in "${java_versions_supported[@]}"; do
if [ "$version" -eq "$JAVA_VERSION" ]; then
supported=1
fi
# Allow execution of supported Java versions, and newer if CASSANDRA_JDK_UNSUPPORTED is set
is_supported_version=$(echo "$java_versions_supported" | tr "," '\n' | grep -F -x "$short")
if [ -z "$is_supported_version" ] ; then
done
if [[ "$supported" -eq 0 ]]; then
if [ -z "$CASSANDRA_JDK_UNSUPPORTED" ]; then
echo "Unsupported Java $JVM_VERSION. Supported are $java_versions_supported"
echo "Unsupported Java $JAVA_VERSION. Supported are $java_version_string"
echo "If you would like to test with newer Java versions set CASSANDRA_JDK_UNSUPPORTED to any value (for example, CASSANDRA_JDK_UNSUPPORTED=true). Unset the parameter for default behavior"
exit 1;
exit 1
else
echo "######################################################################"
echo "Warning! You are using JDK$short. This Cassandra version only supports $java_versions_supported."
echo "Warning! You are using JDK$JAVA_VERSION. This Cassandra version only supports $java_version_string"
echo "######################################################################"
fi
fi
JAVA_VERSION=$short
jvm=`echo "$java_ver_output" | grep -A 1 '[openjdk|java] version' | awk 'NR==2 {print $1}'`
case "$jvm" in
OpenJDK)
JVM_VENDOR=OpenJDK
# this will be "64-Bit" or "32-Bit"
JVM_ARCH=`echo "$java_ver_output" | awk 'NR==3 {print $2}'`
;;
"Java(TM)")
JVM_VENDOR=Oracle
# this will be "64-Bit" or "32-Bit"
JVM_ARCH=`echo "$java_ver_output" | awk 'NR==3 {print $3}'`
;;
*)
# Help fill in other JVM values
JVM_VENDOR=other
JVM_ARCH=unknown
;;
esac
# Read user-defined JVM options from jvm-server.options file
JVM_OPTS_FILE=$CASSANDRA_CONF/jvm${jvmoptions_variant:--clients}.options
if [ $JAVA_VERSION -ge 17 ] ; then
if [ $JAVA_VERSION -ge 21 ] ; then
JVM_DEP_OPTS_FILE=$CASSANDRA_CONF/jvm21${jvmoptions_variant:--clients}.options
elif [ $JAVA_VERSION -ge 17 ] ; then
JVM_DEP_OPTS_FILE=$CASSANDRA_CONF/jvm17${jvmoptions_variant:--clients}.options
elif [ $JAVA_VERSION -ge 11 ] ; then
JVM_DEP_OPTS_FILE=$CASSANDRA_CONF/jvm11${jvmoptions_variant:--clients}.options

View File

@ -49,7 +49,7 @@ BuildRoot: %{_tmppath}/%{relname}root-%(%{__id_u} -n)
BuildRequires: ant >= 1.9
BuildRequires: ant-junit >= 1.9
Requires: (java-11-headless or java-17-headless)
Requires: (java-11-headless or java-17-headless or java-21-headless)
Requires: python(abi) >= 3.6
Requires: procps-ng >= 3.3
Requires(pre): user(cassandra)

View File

@ -4779,27 +4779,46 @@ public class DatabaseDescriptor
public static void setGCLogThreshold(int threshold)
{
if (threshold <= 0)
throw new IllegalArgumentException("Threshold value for gc_log_threshold must be greater than 0");
long gcWarnThresholdInMs = getGCWarnThreshold();
if (gcWarnThresholdInMs != 0 && threshold > gcWarnThresholdInMs)
throw new IllegalArgumentException("Threshold value for gc_log_threshold (" + threshold + ") must be less than gc_warn_threshold which is currently "
+ gcWarnThresholdInMs);
validateGCParams(threshold, getGCWarnThreshold());
conf.gc_log_threshold = new DurationSpec.IntMillisecondsBound(threshold);
}
public static void validateGCParams(long logThreshold, long warnThreshold)
{
if (logThreshold <= 0)
throw new IllegalArgumentException("Threshold value for gc_log*_threshold must be greater than 0");
if (logThreshold > Integer.MAX_VALUE)
throw new IllegalArgumentException("Threshold value for gc_log*_threshold must be less than Integer.MAX_VALUE");
if (warnThreshold <= 0)
throw new IllegalArgumentException("Threshold value for gc_warn*_threshold must be greater than 0");
if (warnThreshold > Integer.MAX_VALUE)
throw new IllegalArgumentException("Threshold value for gc_warn*_threshold must be less than Integer.MAX_VALUE");
if (warnThreshold != 0 && logThreshold > warnThreshold)
throw new IllegalArgumentException("Threshold value for gc_log*_threshold (" + logThreshold + ") must be less than gc_warn*_threshold which is currently "
+ warnThreshold);
}
public static EncryptionContext getEncryptionContext()
{
return encryptionContext;
}
public static long getGCWarnThreshold()
{
return conf.gc_warn_threshold.toMilliseconds();
}
public static void setGCWarnThreshold(int threshold)
public static void setGCWarnThreshold(long threshold)
{
if (threshold < 0)
throw new IllegalArgumentException("Threshold value for gc_warn_threshold must be greater than or equal to 0");
if (threshold > Integer.MAX_VALUE)
throw new IllegalArgumentException("Threshold must be less than Integer.MAX_VALUE");
long gcLogThresholdInMs = getGCLogThreshold();
if (threshold != 0 && threshold <= gcLogThresholdInMs)
throw new IllegalArgumentException("Threshold value for gc_warn_threshold (" + threshold + ") must be greater than gc_log_threshold which is currently "
@ -4844,11 +4863,6 @@ public class DatabaseDescriptor
conf.gc_concurrent_phase_warn_threshold = new DurationSpec.IntMillisecondsBound(threshold);
}
public static EncryptionContext getEncryptionContext()
{
return encryptionContext;
}
public static boolean isCDCEnabled()
{
return conf.cdc_enabled;

View File

@ -640,6 +640,7 @@ public abstract class CommitLogSegment
{
TableMetadata m = Schema.instance.getTableMetadata(tableId);
sb.append(m == null ? "<deleted>" : m.name).append(" (").append(tableId)
.append(", keyspace: ").append(m.keyspace)
.append(", dirty: ").append(tableDirty.get(tableId))
.append(", clean: ").append(tableClean.get(tableId))
.append("), ");

View File

@ -790,7 +790,7 @@ abstract class AbstractPatriciaTrie<K, V> extends AbstractTrie<K, V>
* This is implemented by going always to the left until
* we encounter a valid uplink. That uplink is the first key.
*/
TrieEntry<K, V> firstEntry()
public TrieEntry<K, V> firstEntry()
{
// if Trie is empty, no first node.
return isEmpty() ? null : followLeft(root);

View File

@ -422,7 +422,7 @@ public class PatriciaTrie<K, V> extends AbstractPatriciaTrie<K, V> implements Se
* <p>This is implemented by going always to the right until
* we encounter a valid uplink. That uplink is the last key.
*/
private TrieEntry<K, V> lastEntry()
public TrieEntry<K, V> lastEntry()
{
return followRight(root.left);
}

View File

@ -517,4 +517,10 @@ public class RepairSession extends AsyncFuture<RepairSessionResult> implements I
delegate.shutdown();
}
}
@VisibleForTesting
public int syncingCount()
{
return syncingTasks.size();
}
}

View File

@ -123,15 +123,17 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean
final GarbageCollectorMXBean gcBean;
final boolean assumeGCIsPartiallyConcurrent;
final boolean assumeGCIsOldGen;
final boolean isZGC;
private String[] keys;
long lastGcTotalDuration = 0;
GCState(GarbageCollectorMXBean gcBean, boolean assumeGCIsPartiallyConcurrent, boolean assumeGCIsOldGen)
GCState(GarbageCollectorMXBean gcBean, boolean assumeGCIsPartiallyConcurrent, boolean assumeGCIsOldGen, boolean isZGC)
{
this.gcBean = gcBean;
this.assumeGCIsPartiallyConcurrent = assumeGCIsPartiallyConcurrent;
this.assumeGCIsOldGen = assumeGCIsOldGen;
this.isZGC = isZGC;
}
String[] keys(GarbageCollectionNotificationInfo info)
@ -144,6 +146,11 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean
return keys;
}
public boolean isZGC()
{
return isZGC;
}
}
final AtomicReference<State> state = new AtomicReference<>(new State());
@ -158,7 +165,7 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean
for (ObjectName name : MBeanWrapper.instance.queryNames(gcName, null))
{
GarbageCollectorMXBean gc = ManagementFactory.newPlatformMXBeanProxy(MBeanWrapper.instance.getMBeanServer(), name.getCanonicalName(), GarbageCollectorMXBean.class);
gcStates.put(gc.getName(), new GCState(gc, assumeGCIsPartiallyConcurrent(gc), assumeGCIsOldGen(gc)));
gcStates.put(gc.getName(), new GCState(gc, assumeGCIsPartiallyConcurrent(gc), assumeGCIsOldGen(gc), isZGC(gc)));
}
ObjectName me = new ObjectName(MBEAN_NAME);
if (!MBeanWrapper.instance.isRegistered(me))
@ -182,12 +189,17 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean
}
}
private static boolean isZGC(GarbageCollectorMXBean gc)
{
return gc.getName().contains("ZGC");
}
/*
* Assume that a GC type is at least partially concurrent and so a side channel method
* should be used to calculate application stopped time due to the GC.
*
* If the GC isn't recognized then assume that is concurrent and we need to do our own calculation
* via the the side channel.
* via the side channel.
*/
private static boolean assumeGCIsPartiallyConcurrent(GarbageCollectorMXBean gc)
{
@ -202,9 +214,17 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean
case "G1 Young Generation":
// CMS young generation collector
case "ParNew":
// gen zgc
case "ZGC Minor Pauses":
case "ZGC Major Pauses":
// zgc
case "ZGC Pauses":
return false;
case "ConcurrentMarkSweep":
case "G1 Old Generation":
case "ZGC Minor Cycles":
case "ZGC Major Cycles":
case "ZGC Cycles":
return true;
default:
// Assume possibly concurrent if unsure
@ -226,11 +246,18 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean
case "PS Scavenge":
case "G1 Young Generation":
case "ParNew":
case "ZGC Minor Cycles":
case "ZGC Minor Pauses":
return false;
case "MarkSweepCompact":
case "PS MarkSweep":
case "ConcurrentMarkSweep":
case "G1 Old Generation":
case "ZGC Major Cycles":
case "ZGC Major Pauses":
// assume non-generational zgc is old gen
case "ZGC Cycles":
case "ZGC Pauses":
return true;
default:
// Assume not old gen otherwise, don't call
@ -425,9 +452,15 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean
}
}
/**
* While we _technically_ could only set the threshold based on which GC we're running, there's really no
* perceptable value-add from doing that. Responsibility for enforcing the validity of the params is entrusted
* to the {@link DatabaseDescriptor}
*/
@Override
public void setGcWarnThresholdInMs(long threshold)
{
DatabaseDescriptor.setGCWarnThreshold((int)threshold);
DatabaseDescriptor.setGCWarnThreshold(threshold);
}
public long getGcWarnThresholdInMs()

View File

@ -1216,7 +1216,7 @@ public interface StorageServiceMBean extends NotificationEmitter
* Start the fully query logger.
*
* @param path Path where the full query log will be stored. If null cassandra.yaml value is used.
* @param rollCycle How often to create a new file for query data (MINUTELY, DAILY, HOURLY)
* @param rollCycle How often to create a new file for query data (FIVE_MINUTELY, FAST_DAILY, FAST_HOURLY)
* @param blocking Whether threads submitting queries to the query log should block if they can't be drained to the filesystem or alternatively drops samples and log
* @param maxQueueWeight How many bytes of query data to queue before blocking or dropping samples
* @param maxLogSize How many bytes of log data to store before dropping segments. Might not be respected if a log file hasn't rolled so it can be deleted.

View File

@ -176,7 +176,7 @@ public class AuditLogViewer
private static class AuditLogViewerOptions
{
private final List<String> pathList;
private String rollCycle = "HOURLY";
private String rollCycle = "FAST_HOURLY";
private boolean follow;
private boolean ignoreUnsupported;
@ -238,7 +238,7 @@ public class AuditLogViewer
{
Options options = new Options();
options.addOption(new Option("r", ROLL_CYCLE, true, "How often to roll the log file was rolled. May be necessary for Chronicle to correctly parse file names. (MINUTELY, HOURLY, DAILY). Default HOURLY."));
options.addOption(new Option("r", ROLL_CYCLE, true, "How often to roll the log file was rolled. May be necessary for Chronicle to correctly parse file names. (FIVE_MINUTELY, FAST_HOURLY, FAST_DAILY). Default FAST_HOURLY."));
options.addOption(new Option("f", FOLLOW, false, "Upon reacahing the end of the log continue indefinitely waiting for more records"));
options.addOption(new Option("i", IGNORE, false, "Silently ignore unsupported records"));
options.addOption(new Option("h", HELP_OPTION, false, "display this help message"));

View File

@ -49,7 +49,7 @@ public class EnableAuditLog extends AbstractCommand
@Option(paramLabel = "excluded_users", names = { "--excluded-users" }, description = "Comma separated list of users to be excluded for audit log. If not set the value from cassandra.yaml will be used")
private String excluded_users = null;
@Option(paramLabel = "roll_cycle", names = { "--roll-cycle" }, description = "How often to roll the log file (MINUTELY, HOURLY, DAILY).")
@Option(paramLabel = "roll_cycle", names = { "--roll-cycle" }, description = "How often to roll the log file (FAST_MINUTELY, FAST_HOURLY, FAST_DAILY).")
private String rollCycle = null;
@Option(paramLabel = "blocking", names = { "--blocking" }, description = "If the queue is full whether to block producers or drop samples [true|false].")

View File

@ -26,7 +26,7 @@ import picocli.CommandLine.Option;
@Command(name = "enablefullquerylog", description = "Enable full query logging, defaults for the options are configured in cassandra.yaml")
public class EnableFullQueryLog extends AbstractCommand
{
@Option(paramLabel = "roll_cycle", names = { "--roll-cycle" }, description = "How often to roll the log file (MINUTELY, HOURLY, DAILY).")
@Option(paramLabel = "roll_cycle", names = { "--roll-cycle" }, description = "How often to roll the log file (FAST_MINUTELY, FAST_HOURLY, FAST_DAILY).")
private String rollCycle = null;
@Option(paramLabel = "blocking", names = { "--blocking" }, description = "If the queue is full whether to block producers or drop samples [true|false].")

View File

@ -63,7 +63,7 @@ public final class JavaUtils
* @return the java version number
* @throws NumberFormatException if the version cannot be retrieved
*/
private static int parseJavaVersion(String jreVersion)
public static int parseJavaVersion(String jreVersion)
{
String version;
if (jreVersion.startsWith("1."))

View File

@ -1630,6 +1630,12 @@ public class MerkleTree
return getHelper(root, fullRange.left, fullRange.right, t);
}
@VisibleForTesting
public boolean isReleased()
{
return root == null;
}
private TreeRange getHelper(Node node, Token pleft, Token pright, Token t)
{
int depth = 0;

View File

@ -458,4 +458,19 @@ public class MerkleTrees implements Iterable<Map.Entry<Range<Token>, MerkleTree>
return rt1.compareTo(rt2);
}
}
/**
* For purposes of our checking in test, either "nothing is or was ever here" or "what was here is now gone" suffice.
*/
@VisibleForTesting
public boolean isReleased()
{
if (merkleTrees.isEmpty())
return true;
boolean result = true;
for (MerkleTree mt : merkleTrees.values())
result &= mt.isReleased();
return result;
}
}

View File

@ -37,6 +37,11 @@ import static org.github.jamm.utils.ArrayMeasurementUtils.computeArraySize;
*/
public class ObjectSizes
{
/**
* For debugging purposes, you can construct this with .printVisitedTree() to get a printout of all the objects
* and their calculated size on heap to debug jamm related issues. See:
* <a href="https://github.com/jbellis/jamm/blob/master/README.md#visited-object-tree">README.md on github</a>
*/
private static final MemoryMeter meter = MemoryMeter.builder().withGuessing(Guess.INSTRUMENTATION_AND_SPECIFICATION,
Guess.UNSAFE)
.build();

View File

@ -38,6 +38,7 @@ import net.openhft.chronicle.queue.ExcerptAppender;
import net.openhft.chronicle.queue.RollCycles;
import net.openhft.chronicle.queue.impl.single.SingleChronicleQueue;
import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder;
import net.openhft.chronicle.queue.rollcycles.TestRollCycles;
import net.openhft.chronicle.wire.WireOut;
import net.openhft.chronicle.wire.WriteMarshallable;
import net.openhft.posix.PosixAPI;
@ -55,6 +56,7 @@ import org.apache.cassandra.utils.concurrent.UncheckedInterruptedException;
import org.apache.cassandra.utils.concurrent.WeightedQueue;
import static java.lang.String.format;
import static net.openhft.chronicle.queue.rollcycles.TestRollCycles.TEST_SECONDLY;
import static org.apache.cassandra.config.CassandraRelevantProperties.CHRONICLE_ANNOUNCER_DISABLE;
import static org.apache.cassandra.utils.LocalizeString.toUpperCaseLocalized;
@ -140,7 +142,11 @@ public class BinLog implements Runnable
Preconditions.checkNotNull(options.roll_cycle, "roll_cycle was null");
Preconditions.checkArgument(options.max_queue_weight > 0, "max_queue_weight must be > 0");
SingleChronicleQueueBuilder builder = SingleChronicleQueueBuilder.single(path.toFile()); // checkstyle: permit this invocation
builder.rollCycle(RollCycles.valueOf(options.roll_cycle));
// RollCycles.TEST_SECONDLY is deprecated; avoid logging a warning here in cases where test code may be referencing the old value.
builder.rollCycle(options.roll_cycle.equals("TEST_SECONDLY")
? TEST_SECONDLY
: RollCycles.valueOf(options.roll_cycle));
sampleQueue = new WeightedQueue<>(options.max_queue_weight);
this.archiver = archiver;
@ -394,7 +400,10 @@ public class BinLog implements Runnable
Preconditions.checkNotNull(rollCycle, "rollCycle was null");
rollCycle = toUpperCaseLocalized(rollCycle);
Preconditions.checkNotNull(RollCycles.valueOf(rollCycle), "unrecognized roll cycle");
this.rollCycle = rollCycle;
// Avoid using deprecated RollCycles.TEST_SECONDLY in test cases where we pass the text blindly; logs a warning
this.rollCycle = rollCycle.equals("TEST_SECONDLY")
? TestRollCycles.TEST_SECONDLY.toString()
: rollCycle;
return this;
}

View File

@ -31,11 +31,12 @@ public class BinLogOptions
*/
public boolean allow_nodetool_archive_command = false;
/**
* How often to roll BinLog segments so they can potentially be reclaimed. Available options are:
* MINUTELY, HOURLY, DAILY, LARGE_DAILY, XLARGE_DAILY, HUGE_DAILY.
* For more options, refer: net.openhft.chronicle.queue.RollCycles
* How often to roll BinLog segments so they can potentially be reclaimed. Some available options are:
* FIVE_MINUTELY, FAST_HOURLY, FAST_DAILY, LargeRollCycles.LARGE_DAILY, LargeRollCycles.XLARGE_DAILY, LargeRollCycles.HUGE_DAILY.
* See FAQ: <a href="https://github.com/OpenHFT/Chronicle-Queue/blob/50af322d0022fb8d265779ed6f4c1073d32b6b54/docs/FAQ.adoc" />
* For more options, refer: {@link net.openhft.chronicle.queue.RollCycles}
*/
public String roll_cycle = "HOURLY";
public String roll_cycle = "FAST_HOURLY";
/**
* Indicates if the BinLog should block if the it falls behind or should drop bin log records.
* Default is set to true so that BinLog records wont be lost

View File

@ -328,6 +328,40 @@ public class BTreeSet<V> extends AbstractSet<V> implements NavigableSet<V>, List
{
throw new UnsupportedOperationException();
}
public BTreeSet<V> reversed()
{
throw new UnsupportedOperationException();
}
public V removeLast()
{
throw new UnsupportedOperationException();
}
public V removeFirst()
{
throw new UnsupportedOperationException();
}
public V getLast()
{
throw new UnsupportedOperationException();
}
public V getFirst()
{
throw new UnsupportedOperationException();
}
public void addLast(V v)
{
throw new UnsupportedOperationException();
}
public void addFirst(V v)
{
throw new UnsupportedOperationException();
}
public static class BTreeRange<V> extends BTreeSet<V>
{

View File

@ -125,6 +125,10 @@ public final class Ref<T> implements RefCounted<T>
public static final boolean DEBUG_EVENTS_ENABLED = TEST_DEBUG_REF_EVENTS.getBoolean();
static OnLeak ON_LEAK;
/** NOT INTENDED FOR USE OUTSIDE TESTS AND DEBUGGING */
@VisibleForTesting
private static boolean TEST_TRACE_ENABLED = false;
@Shared(scope = SIMULATION)
public interface OnLeak
{
@ -146,6 +150,14 @@ public final class Ref<T> implements RefCounted<T>
this.referent = referent;
}
/**
* Generally don't go around mutating this willy-nilly in non-test code please.
*/
@VisibleForTesting
public static void enableTestTracing() { TEST_TRACE_ENABLED = true; }
@VisibleForTesting
public static void disableTestTracing() { TEST_TRACE_ENABLED = false; }
/**
* Must be called exactly once, when the logical operation for which this Ref was created has terminated.
* Failure to abide by this contract will result in an error (eventually) being reported, assuming a
@ -646,6 +658,25 @@ public final class Ref<T> implements RefCounted<T>
field = p.right;
}
if (TEST_TRACE_ENABLED)
{
logger.debug("[Ref tracing for {}, Object: {}]", rootObject, child);
if (field != null && child != null)
{
logger.debug(" - Visiting field '{}' of object {} -> value class {}",
field.getName(),
inProgress.o.getClass().getName(),
child.getClass().getName());
}
else if (field != null)
{
// Field exists but the next child is null still useful to know the path.
logger.debug(" - Visiting field '{}' of object {} -> value is null",
field.getName(),
inProgress.o.getClass().getName());
}
}
if (child != null && visited.add(child))
{
path.offer(inProgress);

View File

@ -83,7 +83,8 @@ OPTIONS
Path to the JMX password file
--roll-cycle <roll_cycle>
How often to roll the log file (MINUTELY, HOURLY, DAILY).
How often to roll the log file (FAST_MINUTELY, FAST_HOURLY,
FAST_DAILY).
-u <username>, --username <username>
Remote jmx agent username

View File

@ -55,7 +55,8 @@ OPTIONS
Path to the JMX password file
--roll-cycle <roll_cycle>
How often to roll the log file (MINUTELY, HOURLY, DAILY).
How often to roll the log file (FAST_MINUTELY, FAST_HOURLY,
FAST_DAILY).
-u <username>, --username <username>
Remote jmx agent username

View File

@ -48,7 +48,7 @@ import static org.apache.cassandra.simulator.asm.InterceptClasses.Cached.Kind.UN
// WARNING: does not implement IClassTransformer directly as must be accessible to bootstrap class loader
public class InterceptClasses implements BiFunction<String, byte[], byte[]>
{
public static final int BYTECODE_VERSION = Opcodes.ASM7;
public static final int BYTECODE_VERSION = Opcodes.ASM9;
// TODO (cleanup): use annotations
private static final Pattern MONITORS = Pattern.compile( "org[/.]apache[/.]cassandra[/.]utils[/.]concurrent[/.].*" +

View File

@ -243,6 +243,12 @@ public class ShadowingTransformer extends ClassTransformer
super.visitInnerClass(name, toShadowType(outerName), innerName, access);
}
@Override
public void visitPermittedSubclass(String permittedSubclass)
{
super.visitPermittedSubclass(toShadowType(permittedSubclass));
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value)
{

View File

@ -21,6 +21,7 @@ package org.apache.cassandra.simulator.systems;
import java.util.ArrayDeque;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.IntSupplier;
import java.util.function.LongConsumer;
import java.util.function.ToIntFunction;
@ -487,13 +488,22 @@ public interface InterceptorOfGlobalMethods extends InterceptorOfSystemMethods,
private final IntSupplier nextId;
private final WeakIdentityHashMap<Object, Integer> saved = new WeakIdentityHashMap<>();
private final ReentrantLock mapLock = new ReentrantLock();
public IdentityHashCode(IntSupplier nextId)
{
this.nextId = nextId;
}
public synchronized int applyAsInt(Object value)
/**
* As {@link #saved} is not thread safe, we want to preserve weak reference semantics, and we want to gracefully
* support virtual threads, we need to use another locking mechanism other than synchronized since that is a risk
* of deadlock in JDK21 as virtual threads block on held monitors and won't release.
*/
public int applyAsInt(Object value)
{
mapLock.lock();
try
{
Integer id = saved.get(value);
if (id == null)
@ -503,6 +513,11 @@ public interface InterceptorOfGlobalMethods extends InterceptorOfSystemMethods,
}
return id;
}
finally
{
mapLock.unlock();
}
}
}
}

View File

@ -49,7 +49,8 @@ import static org.apache.cassandra.simulator.RandomSource.Choices.uniform;
// TODO (cleanup): when we encounter an exception and unwind the simulation, we should restore normal time to go with normal waits etc.
public class SimulatedTime
{
private static final Pattern PERMITTED_TIME_THREADS = Pattern.compile("(logback|SimulationLiveness|Reconcile)[-:][0-9]+|RMI Scheduler\\(\\d+\\)");
private static final Pattern PERMITTED_TIME_THREADS = Pattern.compile("(logback|SimulationLiveness|Reconcile|Reference-Reaper)[-:][0-9]+|RMI Scheduler\\(\\d+\\)");
private static final Pattern PERMITTED_TIME_CLEANER_THREADS = Pattern.compile("(LocalPool-Cleaner[-a-z]+[-:][0-9]+|Common-Cleaner)");
@Shared(scope = Shared.Scope.SIMULATION)
public interface Listener
@ -148,7 +149,7 @@ public class SimulatedTime
if (interceptibleThread.isIntercepting())
return interceptibleThread.time();
}
if (PERMITTED_TIME_THREADS.matcher(Thread.currentThread().getName()).matches())
if (PERMITTED_TIME_THREADS.matcher(Thread.currentThread().getName()).matches() || PERMITTED_TIME_CLEANER_THREADS.matcher(Thread.currentThread().getName()).matches())
return disabled;
throw new IllegalStateException("Using time is not allowed during simulation");
}

View File

@ -755,7 +755,7 @@ public class AuditLoggerTest extends CQLTester
assertEquals(1, AuthEvents.instance.listenerCount());
Path p = Files.createTempDirectory("fql");
StorageService.instance.enableFullQueryLogger(p.toString(), RollCycles.HOURLY.toString(), false, 1000, 1000, null, 0);
StorageService.instance.enableFullQueryLogger(p.toString(), RollCycles.FAST_HOURLY.toString(), false, 1000, 1000, null, 0);
assertEquals(2, QueryEvents.instance.listenerCount());
assertEquals(1, AuthEvents.instance.listenerCount()); // fql not listening to auth events
StorageService.instance.resetFullQueryLogger();
@ -778,7 +778,7 @@ public class AuditLoggerTest extends CQLTester
{
assertEquals(1, QueryEvents.instance.listenerCount());
assertEquals(1, AuthEvents.instance.listenerCount());
StorageService.instance.enableFullQueryLogger(options.audit_logs_dir, RollCycles.HOURLY.toString(), false, 1000, 1000, null, 0);
StorageService.instance.enableFullQueryLogger(options.audit_logs_dir, RollCycles.FAST_HOURLY.toString(), false, 1000, 1000, null, 0);
fail("Conflicting directories - should throw exception");
}
catch (IllegalStateException e)
@ -796,7 +796,7 @@ public class AuditLoggerTest extends CQLTester
disableAuditLogOptions();
AuditLogOptions options = getBaseAuditLogOptions();
DatabaseDescriptor.setAuditLoggingOptions(options);
StorageService.instance.enableFullQueryLogger(options.audit_logs_dir, RollCycles.HOURLY.toString(), false, 1000, 1000, null, 0);
StorageService.instance.enableFullQueryLogger(options.audit_logs_dir, RollCycles.FAST_HOURLY.toString(), false, 1000, 1000, null, 0);
try
{
assertEquals(1, QueryEvents.instance.listenerCount());

View File

@ -25,8 +25,8 @@ import com.datastax.driver.core.Session;
import net.openhft.chronicle.queue.ChronicleQueue;
import net.openhft.chronicle.queue.ExcerptTailer;
import net.openhft.chronicle.queue.RollCycles;
import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder;
import net.openhft.chronicle.queue.rollcycles.TestRollCycles;
import org.junit.BeforeClass;
import org.junit.Test;
@ -76,7 +76,7 @@ public class BinAuditLoggerTest extends CQLTester
ResultSet rs = session.execute(pstmt.bind(1));
assertEquals(1, rs.all().size());
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
ExcerptTailer tailer = queue.createTailer();
assertTrue(tailer.readDocument(wire -> {

View File

@ -62,7 +62,7 @@ public class CommitlogShutdownTest
@BMRule(name = "Make removing commitlog segments slow",
targetClass = "CommitLogSegment",
targetMethod = "discard",
action = "Thread.sleep(50)")
action = "Thread.sleep(250L)") // We need to add the unit to Thread.sleep calls in ByteBuddy now
public void testShutdownWithPendingTasks() throws Exception
{
new Random().nextBytes(entropy);
@ -78,7 +78,6 @@ public class CommitlogShutdownTest
SchemaLoader.standardCFMD(KEYSPACE1, STANDARD1, 0, AsciiType.instance, BytesType.instance));
CompactionManager.instance.disableAutoCompaction();
ColumnFamilyStore cfs1 = Keyspace.open(KEYSPACE1).getColumnFamilyStore(STANDARD1);
final Mutation m = new RowUpdateBuilder(cfs1.metadata.get(), 0, "k")

View File

@ -61,7 +61,7 @@ public class AntiCompactionBytemanTest extends CQLTester
targetMethod = "antiCompactGroup",
condition = "not flagged(\"done\")",
targetLocation = "AFTER INVOKE prepareToCommit",
action = "Thread.sleep(2000);") } )
action = "Thread.sleep(2000L);") } ) // We need to add the unit to Thread.sleep calls in ByteBuddy now
public void testRedundantTransitions() throws Throwable
{
createTable("create table %s (id int primary key, i int)");

View File

@ -121,7 +121,7 @@ public class CompactionsBytemanTest extends CQLTester
targetMethod = "submitBackground",
targetLocation = "AT INVOKE java.util.concurrent.Future.isCancelled",
condition = "!$cfs.getKeyspaceName().contains(\"system\")",
action = "Thread.sleep(5000)")
action = "Thread.sleep(5000L)") // We need to add the unit to Thread.sleep calls in ByteBuddy now
public void testCompactingCFCounting() throws Throwable
{
createTable("CREATE TABLE %s (k INT, c INT, v INT, PRIMARY KEY (k, c))");

View File

@ -45,13 +45,13 @@ public class MemtableQuickTest extends CQLTester
{
static final Logger logger = LoggerFactory.getLogger(MemtableQuickTest.class);
static final int partitions = 50_000;
static final int partitions = 45_000;
static final int rowsPerPartition = 4;
static final int deletedPartitionsStart = 20_000;
static final int deletedPartitionsStart = 15_000;
static final int deletedPartitionsEnd = deletedPartitionsStart + 10_000;
static final int deletedRowsStart = 40_000;
static final int deletedRowsStart = 35_000;
static final int deletedRowsEnd = deletedRowsStart + 5_000;
@Parameterized.Parameter()

View File

@ -33,8 +33,8 @@ import javax.annotation.Nullable;
import net.openhft.chronicle.queue.ChronicleQueue;
import net.openhft.chronicle.queue.ExcerptTailer;
import net.openhft.chronicle.queue.RollCycles;
import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder;
import net.openhft.chronicle.queue.rollcycles.TestRollCycles;
import net.openhft.chronicle.wire.ValueIn;
import net.openhft.chronicle.wire.WireOut;
@ -323,7 +323,7 @@ public class FullQueryLoggerTest extends CQLTester
private boolean checkForQueries(List<String> queries)
{
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
ExcerptTailer tailer = queue.createTailer();
List<String> expectedQueries = new LinkedList<>(queries);
@ -434,7 +434,7 @@ public class FullQueryLoggerTest extends CQLTester
private void assertRoundTripQuery(@Nullable String keyspace)
{
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
ExcerptTailer tailer = queue.createTailer();
assertTrue(tailer.readDocument(wire ->
@ -473,7 +473,7 @@ public class FullQueryLoggerTest extends CQLTester
Util.spinAssertEquals(true, () ->
{
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
return queue.createTailer().readingDocument().isPresent();
}
@ -497,7 +497,7 @@ public class FullQueryLoggerTest extends CQLTester
Util.spinAssertEquals(true, () ->
{
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
return queue.createTailer().readingDocument().isPresent();
}
@ -509,7 +509,7 @@ public class FullQueryLoggerTest extends CQLTester
private void assertRoundTripBatch(@Nullable String keyspace)
{
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(tempDir.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
ExcerptTailer tailer = queue.createTailer();
assertTrue(tailer.readDocument(wire -> {

View File

@ -22,9 +22,12 @@ import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.awaitility.Awaitility;
import org.jboss.byteman.contrib.bmunit.BMRule;
import org.jboss.byteman.contrib.bmunit.BMUnitConfig;
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
import org.junit.After;
import org.junit.Before;
@ -91,12 +94,14 @@ public class HintServiceBytemanTest
HintsService.instance.startDispatch();
}
@Test
// When this test hangs it does it _hard_. Working now but don't want to make the worker in CI hang out for full timeout.
@Test (timeout = 300000)
@BMUnitConfig(bmunitVerbose=true, verbose=true)
@BMRule(name = "Delay delivering hints",
targetClass = "DispatchHintsTask",
targetMethod = "run",
action = "Thread.sleep(DatabaseDescriptor.getHintsFlushPeriodInMS() * 3L)")
public void testListPendingHints() throws InterruptedException, ExecutionException
public void testListPendingHints() throws InterruptedException, ExecutionException, TimeoutException
{
HintsService.instance.resumeDispatch();
MockMessagingSpy spy = sendHintsAndResponses(metadata, 20000, -1);
@ -111,7 +116,9 @@ public class HintServiceBytemanTest
assertEquals(1, info.totalFiles);
assertEquals(info.oldestTimestamp, info.newestTimestamp); // there is 1 descriptor with only 1 timestamp
spy.interceptMessageOut(20000).get();
// JDK21 genZGC uncovered some flakiness / hanging here waiting on Condition
spy.interceptMessageOut(20000).get(60, TimeUnit.SECONDS);
spy.printMessageCounts();
assertEquals(Collections.emptyList(), HintsService.instance.getPendingHints());
}
}

View File

@ -32,7 +32,9 @@ import com.google.common.util.concurrent.MoreExecutors;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import accord.primitives.Keys;
import accord.primitives.TxnId;
@ -64,6 +66,7 @@ import org.apache.cassandra.tcm.ClusterMetadata;
import org.apache.cassandra.transport.Dispatcher;
import org.apache.cassandra.utils.MockFailureDetector;
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.apache.cassandra.Util.spinAssertEquals;
import static org.apache.cassandra.config.CassandraRelevantProperties.HINT_DISPATCH_INTERVAL_MS;
import static org.apache.cassandra.hints.HintsTestUtil.sendHintsAndResponses;
@ -83,6 +86,14 @@ public class HintsServiceTest
private final MockFailureDetector failureDetector = new MockFailureDetector();
private static TableMetadata metadata;
// Had some trouble with this test OOM'ing and misbehaving; trying to tighten things up a bit. It's good now but leaving
// this here to defend against future long CI hangs making workers burn cycles.
@Rule
public final Timeout perTestTimeout = Timeout.builder()
.withTimeout(8, MINUTES) // match test.timeout in build.xml
.withLookingForStuckThread(true) // dumps stack of a likely stuck thread
.build();
@BeforeClass
public static void defineSchema()
{

View File

@ -33,7 +33,6 @@ import org.apache.cassandra.locator.InetAddressAndPort;
*/
public class MockMessagingService
{
private MockMessagingService()
{
}

View File

@ -36,12 +36,37 @@ import org.slf4j.LoggerFactory;
import static org.apache.cassandra.utils.concurrent.BlockingQueues.newBlockingQueue;
/**
* Allows inspecting the behavior of mocked messaging by observing {@link MatcherResponse}.
* Test utility that spies on mocked messaging interactions.
*
* <p>This class records inbound mocked messages and outbound messages that would have been
* sent, allowing tests to capture, assert or wait for specific communication patterns.</p>
*
* <h2>Debug logging</h2>
* <p>The internal {@code debugLog} method writes detailed information about the spys
* activity. By default, the logger uses TRACE level; to make the output visible at INFO
* level, set the environment variable {@code MOCK_MESSAGING_SPY_DEBUG=true} before starting
* the JVM.
*
* @see MatcherResponse
* @see MockMessagingService
*/
public class MockMessagingSpy
{
private static final Logger logger = LoggerFactory.getLogger(MockMessagingSpy.class);
// checkstyle: suppress below 'blockSystemPropertyUsage'
private static boolean DEBUG_ENABLED = Boolean.parseBoolean(System.getenv("MOCK_MESSAGING_SPY_DEBUG"));
private void debugLog(String format, Object... args)
{
if (DEBUG_ENABLED)
logger.info(format, args);
else
logger.trace(format, args);
}
public static void enableDebug() {DEBUG_ENABLED = true; }
public static void disableDebug() {DEBUG_ENABLED = false; }
private final AtomicInteger messagesIntercepted = new AtomicInteger();
private final AtomicInteger mockedMessageResponses = new AtomicInteger();
@ -142,17 +167,22 @@ public class MockMessagingSpy
return mockedMessageResponses.get();
}
public void printMessageCounts()
{
logger.info("Messages intercepted: {}. Mocked Message responses: {}", messagesIntercepted(), mockedMessageResponses());
}
void matchingMessage(Message<?> message)
{
messagesIntercepted.incrementAndGet();
logger.trace("Received matching message: {}", message);
int count = messagesIntercepted.incrementAndGet();
debugLog("messagesInterceptedCount: {}. Received matching message: {}", count, message);
interceptedMessages.add(message);
}
void matchingResponse(Message<?> response)
{
mockedMessageResponses.incrementAndGet();
logger.trace("Responding to intercepted message: {}", response);
int count = mockedMessageResponses.incrementAndGet();
debugLog("mockedMessageResponseCount: {}. Responding to intercepted message: {}", count, response);
deliveredResponses.add(response);
}

View File

@ -266,6 +266,10 @@ public class RepairJobTest
long singleTreeSize = ObjectSizes.measureDeep(mockTrees.get(addr1));
assertEquals(0, session.syncingCount());
for (var mt : mockTrees.values())
assertThat(mt.isReleased()).isFalse();
// Use addr4 instead of one of the provided trees to force everything to be remote sync tasks as
// LocalSyncTasks try to reach over the network.
List<SyncTask> syncTasks = RepairJob.createStandardSyncTasks(SharedContext.Global.instance, sessionJobDesc, mockTreeResponses,
@ -275,30 +279,41 @@ public class RepairJobTest
session.pullRepair,
session.previewKind);
// All trees in our mockTrees should be released after SyncTask creation
for (var mt : mockTrees.values())
assertThat(mt.isReleased()).isTrue();
assertThat(session.syncingCount()).isEqualTo(0);
// SyncTasks themselves should not contain significant memory
SyncTaskListAssert.assertThat(syncTasks).hasSizeLessThan(0.2 * singleTreeSize);
// Remember the size of the session before we've executed any tasks
long sizeBeforeExecution = ObjectSizes.measureDeep(session);
// We can't directly check the memory size in the session post JDK21; jamm has trouble walking the internal
// object graph of a ConcurrentHashMap's implementation post JDK21 and has bugs with the @Contended case (which
// indicates we should consider moving away from it... jamm, that is. Which we've discussed as a project).
// Instead, we treat the presence or removal of SyncTasks as indicative of the memory usage since the reference
// to the MerkleTrees lives on there after creation.
// block syncComplete execution until test has verified session still retains the trees
CompletableFuture<?> future = new CompletableFuture<>();
session.registerSyncCompleteCallback(future::get);
ListenableFuture<List<SyncStat>> syncResults = job.executeTasks(syncTasks);
// Immediately following execution the internal execution queue should still retain the trees
long sizeDuringExecution = ObjectSizes.measureDeep(session);
assertThat(sizeDuringExecution).isGreaterThan(sizeBeforeExecution + (syncTasks.size() * singleTreeSize));
ListenableFuture<List<SyncStat>> syncResults = job.executeTasks(syncTasks);
// Immediately following execution the SyncTasks should still be live and thus taking memory
assertThat(session.syncingCount()).isNotEqualTo(0);
// unblock syncComplete callback, session should remove trees
future.complete(null);
// The session retains memory in the contained executor until the threads expire, so we wait for the threads
// that ran the Tree -> SyncTask conversions to die and release the memory
long millisUntilFreed;
// Confirm that it's the thread timeout mechanism that's causing the SyncTasks to retire
assertThat(session.syncingCount()).isNotEqualTo(0);
for (millisUntilFreed = 0; millisUntilFreed < TEST_TIMEOUT_S * 1000; millisUntilFreed += THREAD_TIMEOUT_MILLIS)
{
TimeUnit.MILLISECONDS.sleep(THREAD_TIMEOUT_MILLIS);
if (ObjectSizes.measureDeep(session) < (sizeDuringExecution - (syncTasks.size() * singleTreeSize)))
if (session.syncingCount() == 0)
break;
}

View File

@ -17,6 +17,7 @@
*/
package org.apache.cassandra.service;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@ -30,7 +31,6 @@ import static org.junit.Assert.assertTrue;
public class GCInspectorTest
{
GCInspector gcInspector;
@BeforeClass
@ -48,8 +48,8 @@ public class GCInspectorTest
@Test
public void ensureStaticFieldsHydrateFromConfig()
{
assertEquals(DatabaseDescriptor.getGCLogThreshold(), gcInspector.getGcLogThresholdInMs());
assertEquals(DatabaseDescriptor.getGCWarnThreshold(), gcInspector.getGcWarnThresholdInMs());
Assert.assertEquals(DatabaseDescriptor.getGCLogThreshold(), gcInspector.getGcLogThresholdInMs());
Assert.assertEquals(DatabaseDescriptor.getGCWarnThreshold(), gcInspector.getGcWarnThresholdInMs());
assertEquals(DatabaseDescriptor.getGCConcurrentPhaseLogThreshold(), gcInspector.getGcConcurrentPhaseLogThresholdInMs());
assertEquals(DatabaseDescriptor.getGCConcurrentPhaseWarnThreshold(), gcInspector.getGcConcurrentPhaseWarnThresholdInMs());
}
@ -65,11 +65,11 @@ public class GCInspectorTest
{
assertThatThrownBy(() -> gcInspector.setGcWarnThresholdInMs(gcInspector.getGcLogThresholdInMs()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Threshold value for gc_warn_threshold (200) must be greater than gc_log_threshold which is currently 200");
.hasMessageContaining("must be greater than");
assertThatThrownBy(() -> gcInspector.setGcConcurrentPhaseWarnThresholdInMs(gcInspector.getGcConcurrentPhaseLogThresholdInMs()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Threshold value for gc_concurrent_phase_warn_threshold (1000) must be greater than gc_concurrent_phase_log_threshold which is currently 1000");
.hasMessageContaining("must be greater than");
}
@Test
@ -85,24 +85,33 @@ public class GCInspectorTest
assertEquals(1000, DatabaseDescriptor.getGCConcurrentPhaseLogThreshold());
}
/**
* We keep the concurrent log values the same for JDK21 since we have to infer
* See {@code GCInspector#assumeGCIsPartiallyConcurrent()}
*/
@Test
public void ensureLogLessThanWarn()
{
assertEquals(200, gcInspector.getGcLogThresholdInMs());
gcInspector.setGcWarnThresholdInMs(1000);
assertEquals(1000, gcInspector.getGcWarnThresholdInMs());
int gcLog = 200;
int gcWarn = 1000;
int gcConcurrentLog = 1000;
int gcConcurrentWarn = 2000;
Assert.assertEquals(gcLog, gcInspector.getGcLogThresholdInMs());
gcInspector.setGcWarnThresholdInMs(gcWarn);
assertEquals(gcWarn, gcInspector.getGcWarnThresholdInMs());
assertThatThrownBy(() -> gcInspector.setGcLogThresholdInMs(gcInspector.getGcWarnThresholdInMs() + 1))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Threshold value for gc_log_threshold (1001) must be less than gc_warn_threshold which is currently 1000");
.hasMessageContaining("must be less than");
assertEquals(1000, gcInspector.getGcConcurrentPhaseLogThresholdInMs());
gcInspector.setGcConcurrentPhaseWarnThresholdInMs(2000);
assertEquals(2000, gcInspector.getGcConcurrentPhaseWarnThresholdInMs());
assertEquals(gcConcurrentLog, gcInspector.getGcConcurrentPhaseLogThresholdInMs());
gcInspector.setGcConcurrentPhaseWarnThresholdInMs(gcConcurrentWarn);
assertEquals(gcConcurrentWarn, gcInspector.getGcConcurrentPhaseWarnThresholdInMs());
assertThatThrownBy(() -> gcInspector.setGcConcurrentPhaseLogThresholdInMs(gcInspector.getGcConcurrentPhaseWarnThresholdInMs() + 1))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Threshold value for gc_concurrent_phase_log_threshold (2001) must be less than gc_concurrent_phase_warn_threshold which is currently 2000");
.hasMessageContaining("must be less than");
}
@Test

View File

@ -31,8 +31,8 @@ import com.google.common.collect.Lists;
import net.openhft.chronicle.core.io.IORuntimeException;
import net.openhft.chronicle.queue.ChronicleQueue;
import net.openhft.chronicle.queue.ExcerptAppender;
import net.openhft.chronicle.queue.RollCycles;
import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder;
import net.openhft.chronicle.queue.rollcycles.TestRollCycles;
import net.openhft.chronicle.wire.WireOut;
import org.apache.commons.io.FileUtils;
@ -98,7 +98,8 @@ public class AuditLogViewerTest
" -i,--ignore Silently ignore unsupported records\n" +
" -r,--roll_cycle <arg> How often to roll the log file was rolled. May be\n" +
" necessary for Chronicle to correctly parse file\n" +
" names. (MINUTELY, HOURLY, DAILY). Default HOURLY.\n";
" names. (FIVE_MINUTELY, FAST_HOURLY, FAST_DAILY).\n" +
" Default FAST_HOURLY.\n";
Assertions.assertThat(tool.getStdout()).isEqualTo(help);
}
@ -162,7 +163,7 @@ public class AuditLogViewerTest
records.add("Test foo bar 1");
records.add("Test foo bar 2");
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
ExcerptAppender appender = queue.acquireAppender();
@ -171,7 +172,7 @@ public class AuditLogViewerTest
//Read those written records
List<String> actualRecords = new ArrayList<>();
AuditLogViewer.dump(ImmutableList.of(path.toString()), RollCycles.TEST_SECONDLY.toString(), false, false, actualRecords::add);
AuditLogViewer.dump(ImmutableList.of(path.toString()), TestRollCycles.TEST_SECONDLY.toString(), false, false, actualRecords::add);
assertRecordsMatch(records, actualRecords);
}
@ -180,12 +181,12 @@ public class AuditLogViewerTest
@Test (expected = IORuntimeException.class)
public void testRejectFutureVersionRecord()
{
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
ExcerptAppender appender = queue.acquireAppender();
appender.writeDocument(createFutureRecord());
AuditLogViewer.dump(ImmutableList.of(path.toString()), RollCycles.TEST_SECONDLY.toString(), false, false, dummy -> {});
AuditLogViewer.dump(ImmutableList.of(path.toString()), TestRollCycles.TEST_SECONDLY.toString(), false, false, dummy -> {});
}
catch (Exception e)
{
@ -201,7 +202,7 @@ public class AuditLogViewerTest
records.add("Test foo bar 1");
records.add("Test foo bar 2");
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
ExcerptAppender appender = queue.acquireAppender();
@ -213,7 +214,7 @@ public class AuditLogViewerTest
//Read those written records
List<String> actualRecords = new ArrayList<>();
AuditLogViewer.dump(ImmutableList.of(path.toString()), RollCycles.TEST_SECONDLY.toString(), false, true, actualRecords::add);
AuditLogViewer.dump(ImmutableList.of(path.toString()), TestRollCycles.TEST_SECONDLY.toString(), false, true, actualRecords::add);
// Assert all current records are present
assertRecordsMatch(records, actualRecords);
@ -223,12 +224,12 @@ public class AuditLogViewerTest
@Test (expected = IORuntimeException.class)
public void testRejectUnknownTypeRecord()
{
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
ExcerptAppender appender = queue.acquireAppender();
appender.writeDocument(createUnknownTypeRecord());
AuditLogViewer.dump(ImmutableList.of(path.toString()), RollCycles.TEST_SECONDLY.toString(), false, false, dummy -> {});
AuditLogViewer.dump(ImmutableList.of(path.toString()), TestRollCycles.TEST_SECONDLY.toString(), false, false, dummy -> {});
}
catch (Exception e)
{
@ -244,7 +245,7 @@ public class AuditLogViewerTest
records.add("Test foo bar 1");
records.add("Test foo bar 2");
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
ExcerptAppender appender = queue.acquireAppender();
@ -256,7 +257,7 @@ public class AuditLogViewerTest
//Read those written records
List<String> actualRecords = new ArrayList<>();
AuditLogViewer.dump(ImmutableList.of(path.toString()), RollCycles.TEST_SECONDLY.toString(), false, true, actualRecords::add);
AuditLogViewer.dump(ImmutableList.of(path.toString()), TestRollCycles.TEST_SECONDLY.toString(), false, true, actualRecords::add);
// Assert all supported records are present
assertRecordsMatch(records, actualRecords);

View File

@ -18,6 +18,10 @@
package org.apache.cassandra.tools;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import com.datastax.driver.core.exceptions.NoHostAvailableException;
import org.hamcrest.CoreMatchers;
@ -31,6 +35,20 @@ import static org.junit.Assert.assertThat;
public class BulkLoaderTest extends OfflineToolUtils
{
private static final String[] ALLOWED_BULK_LOADER_THREADS = new String[]{
"ObjectCleanerThread",
"globalEventExecutor-[1-9]-[1-9]",
"globalEventExecutor-[1-9]-[1-9]",
"Shutdown-checker",
"cluster[0-9]-connection-reaper-[0-9]",
"Attach Listener",
"process reaper",
"JNA Cleaner",
};
// the driver isn't expected to terminate threads on close synchronously (CASSANDRA-19000)
private static final String SYNC_DRIVER_THREAD = "cluster[0-9]-nio-worker-[0-9]";
@Test
public void testBulkLoader_NoArgs()
{
@ -38,10 +56,10 @@ public class BulkLoaderTest extends OfflineToolUtils
assertEquals(1, tool.getExitCode());
assertThat(tool.getCleanedStderr(), CoreMatchers.containsString("Missing sstable directory argument"));
assertNoUnexpectedThreadsStarted(new String[] { "ObjectCleanerThread",
assertNoUnexpectedThreadsStarted(false, "ObjectCleanerThread",
"Shutdown-checker",
"cluster[0-9]-connection-reaper-[0-9]" },
false);
"cluster[0-9]-connection-reaper-[0-9]");
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -63,15 +81,8 @@ public class BulkLoaderTest extends OfflineToolUtils
if (!(tool.getException().getCause().getCause().getCause() instanceof NoHostAvailableException))
throw tool.getException();
assertNoUnexpectedThreadsStarted(new String[] { "ObjectCleanerThread",
"globalEventExecutor-[1-9]-[1-9]",
"globalEventExecutor-[1-9]-[1-9]",
"Shutdown-checker",
"cluster[0-9]-connection-reaper-[0-9]",
"Attach Listener",
"process reaper",
"JNA Cleaner"},
false);
assertNoUnexpectedThreadsStarted(false, ALLOWED_BULK_LOADER_THREADS);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -95,17 +106,7 @@ public class BulkLoaderTest extends OfflineToolUtils
if (!(tool.getException().getCause().getCause().getCause() instanceof NoHostAvailableException))
throw tool.getException();
assertNoUnexpectedThreadsStarted(new String[] { "ObjectCleanerThread",
"globalEventExecutor-[1-9]-[1-9]",
"globalEventExecutor-[1-9]-[1-9]",
"Shutdown-checker",
"cluster[0-9]-connection-reaper-[0-9]",
"Attach Listener",
"process reaper",
"JNA Cleaner",
// the driver isn't expected to terminate threads on close synchronously (CASSANDRA-19000)
"cluster[0-9]-nio-worker-[0-9]" },
false);
assertNoUnexpectedThreadsStarted(false, appendToAllowedThreads(SYNC_DRIVER_THREAD));
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -129,17 +130,7 @@ public class BulkLoaderTest extends OfflineToolUtils
if (!(tool.getException().getCause().getCause().getCause() instanceof NoHostAvailableException))
throw tool.getException();
assertNoUnexpectedThreadsStarted(new String[] { "ObjectCleanerThread",
"globalEventExecutor-[1-9]-[1-9]",
"globalEventExecutor-[1-9]-[1-9]",
"Shutdown-checker",
"cluster[0-9]-connection-reaper-[0-9]",
"Attach Listener",
"process reaper",
"JNA Cleaner",
// the driver isn't expected to terminate threads on close synchronously (CASSANDRA-19000)
"cluster[0-9]-nio-worker-[0-9]" },
false);
assertNoUnexpectedThreadsStarted(false, appendToAllowedThreads(SYNC_DRIVER_THREAD));
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -216,4 +207,11 @@ public class BulkLoaderTest extends OfflineToolUtils
assertEquals(6, DatabaseDescriptor.getEntireSSTableInterDCStreamThroughputOutboundMebibytesPerSec(), 0.0);
throw tool.getException().getCause().getCause().getCause();
}
private String[] appendToAllowedThreads(String... optionalThreads)
{
var result = new ArrayList<>(Arrays.asList(ALLOWED_BULK_LOADER_THREADS));
Collections.addAll(result, optionalThreads);
return result.toArray(String[]::new);
}
}

View File

@ -29,7 +29,7 @@ public class GetVersionTest extends OfflineToolUtils
{
ToolResult tool = ToolRunner.invokeClass(GetVersion.class);
tool.assertOnCleanExit();
assertNoUnexpectedThreadsStarted(null, false);
assertNoUnexpectedThreadsStarted(false);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();

View File

@ -27,15 +27,13 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import com.google.common.collect.Iterables;
import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.config.CassandraRelevantProperties;
@ -44,7 +42,6 @@ import org.apache.cassandra.io.util.File;
import static org.apache.cassandra.utils.FBUtilities.preventIllegalAccessWarnings;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
@ -52,6 +49,8 @@ import static org.junit.Assert.fail;
*/
public abstract class OfflineToolUtils
{
private static final Logger logger = LoggerFactory.getLogger(OfflineToolUtils.class);
static
{
preventIllegalAccessWarnings();
@ -75,7 +74,7 @@ public abstract class OfflineToolUtils
"Background_Reporter:[1-9]",
"EXPIRING-MAP-REAPER:[1-9]",
"ObjectCleanerThread",
"process reaper", // spawned by the jvm when executing external processes
"process reaper", // spawned by the jvm when executing external processes and may still be active when we check
// and may still be active when we check
"Attach Listener", // spawned in intellij IDEA
"JNA Cleaner", // spawned by JNA
@ -89,39 +88,48 @@ public abstract class OfflineToolUtils
"((Native|Slab|Heap)Pool|Logged)Cleaner"
};
public void assertNoUnexpectedThreadsStarted(String[] optionalThreadNames, boolean allowNonDefaultMemtableThreads)
/** We have some threads that show up in the presence of other JDK's; account for those here */
private static final String[] EXTRA_JDK_THREADS = new String[]{
"Native reference cleanup thread", // Corretto janitor thread
};
/**
* When unexpected threads or core singleton objects are inadvertantly initialized during tool runs it can lead to
* the tool hanging on shutdown. We have a whitelisted number of threads above along with whatever initial threads
* were there on first tool creation we can diff against; if we find _anything_ new, it's an error condition - this
* needs to either be added to the list above or debugged and fixed.
*/
public void assertNoUnexpectedThreadsStarted(boolean allowNonDefaultMemtableThreads, String... optionalThreadNames)
{
ThreadMXBean threads = ManagementFactory.getThreadMXBean();
Set<String> initial = initialThreads
.stream()
var allowedThreadNames = initialThreads.stream()
.map(ThreadInfo::getThreadName)
.collect(Collectors.toSet());
Set<String> current = Arrays.stream(threads.getThreadInfo(threads.getAllThreadIds()))
.filter(Objects::nonNull)
.map(ThreadInfo::getThreadName)
.collect(Collectors.toSet());
Iterable<String> optionalNames = optionalThreadNames != null
? Arrays.asList(optionalThreadNames)
: Collections.emptyList();
Collections.addAll(allowedThreadNames, EXTRA_JDK_THREADS);
Collections.addAll(allowedThreadNames, optionalThreadNames);
if (allowNonDefaultMemtableThreads && DatabaseDescriptor.getMemtableConfigurations().containsKey("default"))
optionalNames = Iterables.concat(optionalNames, Arrays.asList(NON_DEFAULT_MEMTABLE_THREADS));
Collections.addAll(allowedThreadNames, NON_DEFAULT_MEMTABLE_THREADS);
List<Pattern> optional = StreamSupport.stream(optionalNames.spliterator(), false)
var allowedRegexes = allowedThreadNames.stream()
.map(Pattern::compile)
.collect(Collectors.toList());
current.removeAll(initial);
Set<String> remain = current.stream()
.filter(threadName -> optional.stream().noneMatch(pattern -> pattern.matcher(threadName).matches()))
var threads = ManagementFactory.getThreadMXBean();
var badThreads = Arrays.stream(threads.getThreadInfo(threads.getAllThreadIds()))
.filter(Objects::nonNull)
.filter(threadInfo -> allowedRegexes.stream().noneMatch(pattern -> pattern.matcher(threadInfo.getThreadName()).matches()))
.collect(Collectors.toSet());
if (!remain.isEmpty())
System.err.println("Unexpected thread names: " + remain);
assertTrue("Wrong thread status, active threads unaccounted for: " + remain, remain.isEmpty());
if (!badThreads.isEmpty())
{
logger.error("Found unexpected disallowed threads during check. Printing thread details.");
badThreads.forEach(info -> logger.error(info.toString()));
var errorMessage = new StringBuilder("Bad threads found:");
badThreads.forEach(ti -> errorMessage.append("\n ").append(ti.getThreadName()));
errorMessage.append("\n-Tools should not start threads that initialize singletons or other system resources");
Assert.fail(errorMessage.toString());
}
}
public void assertSchemaNotLoaded()
@ -239,7 +247,7 @@ public abstract class OfflineToolUtils
protected void assertCorrectEnvPostTest()
{
assertNoUnexpectedThreadsStarted(OPTIONAL_THREADS_WITH_SCHEMA, true);
assertNoUnexpectedThreadsStarted(true, OPTIONAL_THREADS_WITH_SCHEMA);
assertSchemaLoaded();
assertServerNotLoaded();
}

View File

@ -37,7 +37,7 @@ public class SSTableExpiredBlockersTest extends OfflineToolUtils
assertThat(tool.getCleanedStderr(), CoreMatchers.containsStringIgnoringCase("Missing arguments"));
assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, false);
assertNoUnexpectedThreadsStarted(false);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();

View File

@ -184,7 +184,7 @@ public class SSTableExportSchemaLoadingTest extends OfflineToolUtils
*/
private void assertPostTestEnv()
{
assertNoUnexpectedThreadsStarted(OPTIONAL_THREADS_WITH_SCHEMA, true);
assertNoUnexpectedThreadsStarted(true, OPTIONAL_THREADS_WITH_SCHEMA);
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
assertKeyspaceNotLoaded();

View File

@ -108,7 +108,7 @@ public class SSTableExportTest extends OfflineToolUtils
*/
private void assertPostTestEnv()
{
assertNoUnexpectedThreadsStarted(OPTIONAL_THREADS_WITH_SCHEMA, false);
assertNoUnexpectedThreadsStarted(false, OPTIONAL_THREADS_WITH_SCHEMA);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();

View File

@ -36,7 +36,7 @@ public class SSTableLevelResetterTest extends OfflineToolUtils
assertThat(tool.getStdout(), CoreMatchers.containsStringIgnoringCase("usage:"));
Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, false);
assertNoUnexpectedThreadsStarted(false);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();

View File

@ -54,7 +54,7 @@ public class SSTableMetadataViewerTest extends OfflineToolUtils
assertThat(tool.getCleanedStderr(), CoreMatchers.containsStringIgnoringCase("Options:"));
assertEquals(1, tool.getExitCode());
}
assertNoUnexpectedThreadsStarted(null, false);
assertNoUnexpectedThreadsStarted(false);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -218,7 +218,7 @@ public class SSTableMetadataViewerTest extends OfflineToolUtils
private void assertGoodEnvPostTest()
{
assertNoUnexpectedThreadsStarted(OPTIONAL_THREADS_WITH_SCHEMA, false);
assertNoUnexpectedThreadsStarted(false, OPTIONAL_THREADS_WITH_SCHEMA);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();

View File

@ -36,7 +36,7 @@ public class SSTableOfflineRelevelTest extends OfflineToolUtils
assertThat(tool.getStdout(), CoreMatchers.containsStringIgnoringCase("usage:"));
Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, false);
assertNoUnexpectedThreadsStarted(false);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();

View File

@ -101,7 +101,7 @@ public class SSTablePartitionsTest extends OfflineToolUtils
@After
public void assertPostTestEnv()
{
assertNoUnexpectedThreadsStarted(OPTIONAL_THREADS_WITH_SCHEMA, false);
assertNoUnexpectedThreadsStarted(false, OPTIONAL_THREADS_WITH_SCHEMA);
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
assertKeyspaceNotLoaded();

View File

@ -41,7 +41,7 @@ public class SSTableRepairedAtSetterTest extends OfflineToolUtils
assertThat(tool.getStdout(), CoreMatchers.containsStringIgnoringCase("usage:"));
Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, false);
assertNoUnexpectedThreadsStarted(false);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -79,7 +79,7 @@ public class SSTableRepairedAtSetterTest extends OfflineToolUtils
"--is-repaired",
findOneSSTable("legacy_sstables", "legacy_ma_simple"));
tool.assertOnCleanExit();
assertNoUnexpectedThreadsStarted(OPTIONAL_THREADS_WITH_SCHEMA, false);
assertNoUnexpectedThreadsStarted(false, OPTIONAL_THREADS_WITH_SCHEMA);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -95,7 +95,7 @@ public class SSTableRepairedAtSetterTest extends OfflineToolUtils
"--is-unrepaired",
findOneSSTable("legacy_sstables", "legacy_ma_simple"));
tool.assertOnCleanExit();
assertNoUnexpectedThreadsStarted(OPTIONAL_THREADS_WITH_SCHEMA, false);
assertNoUnexpectedThreadsStarted(false, OPTIONAL_THREADS_WITH_SCHEMA);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -113,7 +113,7 @@ public class SSTableRepairedAtSetterTest extends OfflineToolUtils
String file = tmpFile.absolutePath();
ToolResult tool = ToolRunner.invokeClass(SSTableRepairedAtSetter.class, "--really-set", "--is-repaired", "-f", file);
tool.assertOnCleanExit();
assertNoUnexpectedThreadsStarted(OPTIONAL_THREADS_WITH_SCHEMA, false);
assertNoUnexpectedThreadsStarted(false, OPTIONAL_THREADS_WITH_SCHEMA);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();

View File

@ -66,6 +66,7 @@ public class ToolRunner
protected static final Logger logger = LoggerFactory.getLogger(ToolRunner.class);
public static final ImmutableList<String> DEFAULT_CLEANERS = ImmutableList.of("(?im)^picked up.*\\R",
"(?im)^.*package jdk.internal.util.jar not in java.base*\\R",
"(?im)^.*Not generating a deterministic id for table.*\\R",
"(?im)^.*`USE <keyspace>` with prepared statements is.*\\R");

View File

@ -33,7 +33,7 @@ public class ToolsSchemaLoadingTest extends OfflineToolUtils
assertThat(tool.getStdout(), CoreMatchers.containsStringIgnoringCase("usage:"));
assertThat(tool.getCleanedStderr(), CoreMatchers.containsStringIgnoringCase("Missing arguments"));
assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, false);
assertNoUnexpectedThreadsStarted(false);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -48,7 +48,7 @@ public class ToolsSchemaLoadingTest extends OfflineToolUtils
assertThat(tool.getStdout(), CoreMatchers.containsStringIgnoringCase("usage:"));
assertThat(tool.getCleanedStderr(), CoreMatchers.containsStringIgnoringCase("Missing arguments"));
assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, false);
assertNoUnexpectedThreadsStarted(false);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -63,7 +63,7 @@ public class ToolsSchemaLoadingTest extends OfflineToolUtils
assertThat(tool.getStdout(), CoreMatchers.containsStringIgnoringCase("usage:"));
assertThat(tool.getCleanedStderr(), CoreMatchers.containsStringIgnoringCase("No sstables to split"));
assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, false);
assertNoUnexpectedThreadsStarted(false);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -78,7 +78,7 @@ public class ToolsSchemaLoadingTest extends OfflineToolUtils
assertThat(tool.getStdout(), CoreMatchers.containsStringIgnoringCase("usage:"));
assertThat(tool.getCleanedStderr(), CoreMatchers.containsStringIgnoringCase("Missing arguments"));
assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, false);
assertNoUnexpectedThreadsStarted(false);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@ -93,7 +93,7 @@ public class ToolsSchemaLoadingTest extends OfflineToolUtils
assertThat(tool.getStdout(), CoreMatchers.containsStringIgnoringCase("usage:"));
assertThat(tool.getCleanedStderr(), CoreMatchers.containsStringIgnoringCase("Missing arguments"));
assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, false);
assertNoUnexpectedThreadsStarted(false);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();

View File

@ -112,7 +112,7 @@ public class GetAuditLogTest extends CQLTester
final String output = getAuditLogOutput.replaceAll("( )+", " ").trim();
assertThat(output).startsWith("enabled true");
assertThat(output).contains("logger BinAuditLogger");
assertThat(output).contains("roll_cycle HOURLY");
assertThat(output).contains("roll_cycle FAST_HOURLY");
assertThat(output).contains("block true");
assertThat(output).contains("max_log_size 17179869184");
assertThat(output).contains("max_queue_weight 268435456");
@ -131,7 +131,7 @@ public class GetAuditLogTest extends CQLTester
final String output = getAuditLogOutput.replaceAll("( )+", " ").trim();
assertThat(output).startsWith("enabled true");
assertThat(output).contains("logger BinAuditLogger");
assertThat(output).contains("roll_cycle HOURLY");
assertThat(output).contains("roll_cycle FAST_HOURLY");
assertThat(output).contains("block true");
assertThat(output).contains("max_log_size 17179869184");
assertThat(output).contains("max_queue_weight 268435456");
@ -150,7 +150,7 @@ public class GetAuditLogTest extends CQLTester
final String output = getAuditLogOutput.replaceAll("( )+", " ").trim();
assertThat(output).startsWith("enabled false");
assertThat(output).contains("logger BinAuditLogger");
assertThat(output).contains("roll_cycle HOURLY");
assertThat(output).contains("roll_cycle FAST_HOURLY");
assertThat(output).contains("block true");
assertThat(output).contains("max_log_size 17179869184");
assertThat(output).contains("max_queue_weight 268435456");

View File

@ -17,14 +17,11 @@
*/
package org.apache.cassandra.transport;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Map;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
@ -48,8 +45,8 @@ import org.apache.cassandra.transport.messages.QueryMessage;
import org.apache.cassandra.transport.messages.ResultMessage;
import org.apache.cassandra.utils.ByteArrayUtil;
import org.apache.cassandra.utils.MD5Digest;
import org.apache.cassandra.utils.ReflectionUtils;
import static org.apache.cassandra.config.CassandraRelevantProperties.CUSTOM_QUERY_HANDLER_CLASS;
import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
public class MessagePayloadTest extends CQLTester
@ -57,47 +54,11 @@ public class MessagePayloadTest extends CQLTester
public static Map<String, ByteBuffer> requestPayload;
public static Map<String, ByteBuffer> responsePayload;
private static Field cqlQueryHandlerField;
private static boolean modifiersAccessible;
@BeforeClass
public static void makeCqlQueryHandlerAccessible()
public static void setUpClass()
{
try
{
cqlQueryHandlerField = ClientState.class.getDeclaredField("cqlQueryHandler");
cqlQueryHandlerField.setAccessible(true);
Field modifiersField = ReflectionUtils.getModifiersField();
modifiersAccessible = modifiersField.isAccessible();
modifiersField.setAccessible(true);
modifiersField.setInt(cqlQueryHandlerField, cqlQueryHandlerField.getModifiers() & ~Modifier.FINAL);
}
catch (IllegalAccessException | NoSuchFieldException e)
{
throw new RuntimeException(e);
}
}
@AfterClass
public static void resetCqlQueryHandlerField()
{
if (cqlQueryHandlerField == null)
return;
try
{
Field modifiersField = ReflectionUtils.getModifiersField();
modifiersField.setAccessible(true);
modifiersField.setInt(cqlQueryHandlerField, cqlQueryHandlerField.getModifiers() | Modifier.FINAL);
cqlQueryHandlerField.setAccessible(false);
modifiersField.setAccessible(modifiersAccessible);
}
catch (IllegalAccessException | NoSuchFieldException e)
{
throw new RuntimeException(e);
}
CUSTOM_QUERY_HANDLER_CLASS.setString("org.apache.cassandra.transport.MessagePayloadTest$TestQueryHandler");
CQLTester.setUpClass();
}
@After
@ -115,10 +76,6 @@ public class MessagePayloadTest extends CQLTester
@Test
public void testMessagePayloadBeta() throws Throwable
{
QueryHandler queryHandler = (QueryHandler) cqlQueryHandlerField.get(null);
cqlQueryHandlerField.set(null, new TestQueryHandler());
try
{
requireNetwork();
@ -187,18 +144,9 @@ public class MessagePayloadTest extends CQLTester
client.close();
}
}
finally
{
cqlQueryHandlerField.set(null, queryHandler);
}
}
@Test
public void testMessagePayload() throws Throwable
{
QueryHandler queryHandler = (QueryHandler) cqlQueryHandlerField.get(null);
cqlQueryHandlerField.set(null, new TestQueryHandler());
try
{
requireNetwork();
@ -256,18 +204,9 @@ public class MessagePayloadTest extends CQLTester
client.close();
}
}
finally
{
cqlQueryHandlerField.set(null, queryHandler);
}
}
@Test
public void testMessagePayloadVersion3() throws Throwable
{
QueryHandler queryHandler = (QueryHandler) cqlQueryHandlerField.get(null);
cqlQueryHandlerField.set(null, new TestQueryHandler());
try
{
requireNetwork();
@ -363,11 +302,6 @@ public class MessagePayloadTest extends CQLTester
client.close();
}
}
finally
{
cqlQueryHandlerField.set(null, queryHandler);
}
}
private static void payloadEquals(Map<String, ByteBuffer> map1, Map<String, ByteBuffer> map2)
{

View File

@ -50,6 +50,8 @@ import org.apache.cassandra.utils.MerkleTree.TreeRange;
import org.apache.cassandra.utils.MerkleTree.TreeRangeIterator;
import static com.google.common.collect.Lists.newArrayList;
import static org.apache.cassandra.config.CassandraRelevantProperties.JAVA_VERSION;
import static org.apache.cassandra.utils.JavaUtils.parseJavaVersion;
import static org.apache.cassandra.utils.MerkleTree.RECOMMENDED_DEPTH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -619,8 +621,12 @@ public class MerkleTreeTest
Assert.assertEquals(12, MerkleTree.estimatedMaxDepthForBytes(Murmur3Partitioner.instance,
1048576, 32));
// With 100 mebibytes we should get a limit of 19
Assert.assertEquals(19, MerkleTree.estimatedMaxDepthForBytes(Murmur3Partitioner.instance,
// With 100 mebibytes we should get a limit of 19 on JDK's < 21, 18 on JDK21
// Object size impl details can be expected to change on different JDK's so this impl will be brittle
// in the face of future JDK changes.
int version = parseJavaVersion(JAVA_VERSION.getString());
int expectedLimit = version < 21 ? 19 : 18;
Assert.assertEquals(expectedLimit, MerkleTree.estimatedMaxDepthForBytes(Murmur3Partitioner.instance,
100 * 1048576, 32));
// With 300 mebibytes we should get the old limit of 20

View File

@ -30,8 +30,8 @@ import java.util.function.Supplier;
import net.openhft.chronicle.queue.ChronicleQueue;
import net.openhft.chronicle.queue.ExcerptTailer;
import net.openhft.chronicle.queue.RollCycles;
import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder;
import net.openhft.chronicle.queue.rollcycles.TestRollCycles;
import net.openhft.chronicle.wire.WireOut;
import org.junit.After;
@ -75,7 +75,7 @@ public class BinLogTest
{
path = tempDir();
binLog = new BinLog.Builder().path(path)
.rollCycle(RollCycles.TEST_SECONDLY.toString())
.rollCycle(TestRollCycles.TEST_SECONDLY.toString())
.maxQueueWeight(10)
.maxLogSize(1024 * 1024 * 128)
.blocking(false)
@ -110,13 +110,13 @@ public class BinLogTest
@Test(expected = IllegalArgumentException.class)
public void testConstructorZeroWeight() throws Exception
{
new BinLog.Builder().path(tempDir()).rollCycle(RollCycles.TEST_SECONDLY.toString()).maxQueueWeight(0).build(false);
new BinLog.Builder().path(tempDir()).rollCycle(TestRollCycles.TEST_SECONDLY.toString()).maxQueueWeight(0).build(false);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructorLogSize() throws Exception
{
new BinLog.Builder().path(tempDir()).rollCycle(RollCycles.TEST_SECONDLY.toString()).maxLogSize(0).build(false);
new BinLog.Builder().path(tempDir()).rollCycle(TestRollCycles.TEST_SECONDLY.toString()).maxLogSize(0).build(false);
}
/**
@ -383,7 +383,7 @@ public class BinLogTest
public void testCleanupOnOversize() throws Exception
{
tearDown();
binLog = new BinLog.Builder().path(path).rollCycle(RollCycles.TEST_SECONDLY.toString()).maxQueueWeight(1).maxLogSize(10000).blocking(false).build(false);
binLog = new BinLog.Builder().path(path).rollCycle(TestRollCycles.TEST_SECONDLY.toString()).maxQueueWeight(1).maxLogSize(10000).blocking(false).build(false);
for (int ii = 0; ii < 5; ii++)
{
binLog.put(record(String.valueOf(ii)));
@ -496,7 +496,7 @@ public class BinLogTest
List<String> readBinLogRecords(Path path)
{
List<String> records = new ArrayList<String>();
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(RollCycles.TEST_SECONDLY).build())
try (ChronicleQueue queue = SingleChronicleQueueBuilder.single(path.toFile()).rollCycle(TestRollCycles.TEST_SECONDLY).build())
{
ExcerptTailer tailer = queue.createTailer();
while (true)

View File

@ -52,6 +52,8 @@ import org.apache.cassandra.utils.ObjectSizes;
import org.apache.cassandra.utils.Pair;
import org.apache.cassandra.utils.concurrent.Ref.Visitor;
import static org.apache.cassandra.config.CassandraRelevantProperties.JAVA_VERSION;
import static org.apache.cassandra.utils.JavaUtils.parseJavaVersion;
import static org.assertj.core.api.Assertions.assertThat;
@SuppressWarnings({"unused", "unchecked", "rawtypes"})
@ -468,10 +470,10 @@ public class RefCountedTest
private Set<Ref.GlobalState> testCycles(Function<LambdaTestClass, Runnable> runOnCloseSupplier)
{
LambdaTestClass test = new LambdaTestClass();
Runnable weakRef = runOnCloseSupplier.apply(test);
Runnable supplierRef = runOnCloseSupplier.apply(test);
RefCounted.Tidy tidier = new RefCounted.Tidy()
{
Runnable ref = weakRef;
Runnable ref = supplierRef;
public void tidy()
{
@ -505,7 +507,17 @@ public class RefCountedTest
public void testCycles()
{
assertThat(testCycles(LambdaTestClass::getRunOnCloseLambdaWithThis)).isNotEmpty(); // sanity test
assertThat(testCycles(LambdaTestClass::getRunOnCloseInner)).isNotEmpty(); // sanity test
// Behavior changed in JDK21; this was a sanity check to explore the way things worked but doesn't impact
// the correctness of the final actual check of the test.
int version = parseJavaVersion(JAVA_VERSION.getString());
boolean runOnCloseInnerState = version >= 21;
var result = testCycles(LambdaTestClass::getRunOnCloseInner);
if (runOnCloseInnerState)
assertThat(result).isEmpty();
else
assertThat(result).isNotEmpty();
assertThat(testCycles(LambdaTestClass::getRunOnCloseLambda)).isEmpty();
}

View File

@ -85,57 +85,37 @@ if [ -z $JAVA ] ; then
fi
# Matches variable 'java.supported' in build.xml
java_versions_supported=11,17
java_versions_supported="11 17 21"
java_version_string=$(IFS=" "; echo "${java_versions_supported}")
# Determine the sort of JVM we'll be running on.
java_ver_output=`"${JAVA:-java}" -version 2>&1`
jvmver=`echo "$java_ver_output" | grep '[openjdk|java] version' | awk -F'"' 'NR==1 {print $2}' | cut -d\- -f1`
JVM_VERSION=${jvmver%_*}
short=$(echo "${jvmver}" | cut -c1-2)
JAVA_VERSION=$(java -version 2>&1 | grep '[openjdk|java] version' | cut -d '"' -f2 | cut -d '.' -f1)
# Unsupported JDKs below the upper supported version are not allowed
if [ "$short" != "$(echo "$java_versions_supported" | cut -d, -f1)" ] && [ "$JVM_VERSION" \< "$(echo "$java_versions_supported" | cut -d, -f2)" ] ; then
echo "Unsupported Java $JVM_VERSION. Supported are $java_versions_supported"
exit 1;
supported=0
for version in ${java_versions_supported}; do
if [ "$version" -eq "$JAVA_VERSION" ]; then
supported=1
fi
done
# Allow execution of supported Java versions, and newer if CASSANDRA_JDK_UNSUPPORTED is set
is_supported_version=$(echo "$java_versions_supported" | tr "," '\n' | grep -F -x "$short")
if [ -z "$is_supported_version" ] ; then
if [ "$supported" -eq 0 ]; then
if [ -z "$CASSANDRA_JDK_UNSUPPORTED" ]; then
echo "Unsupported Java $JVM_VERSION. Supported are $java_versions_supported"
echo "Unsupported Java $JAVA_VERSION. Supported are $java_version_string"
echo "If you would like to test with newer Java versions set CASSANDRA_JDK_UNSUPPORTED to any value (for example, CASSANDRA_JDK_UNSUPPORTED=true). Unset the parameter for default behavior"
exit 1;
exit 1
else
echo "######################################################################"
echo "Warning! You are using JDK$short. This Cassandra version only supports $java_versions_supported."
echo "Warning! You are using JDK$JAVA_VERSION. This Cassandra version only supports $java_version_string"
echo "######################################################################"
fi
fi
JAVA_VERSION=$short
jvm=`echo "$java_ver_output" | grep -A 1 '[openjdk|java] version' | awk 'NR==2 {print $1}'`
case "$jvm" in
OpenJDK)
JVM_VENDOR=OpenJDK
# this will be "64-Bit" or "32-Bit"
JVM_ARCH=`echo "$java_ver_output" | awk 'NR==3 {print $2}'`
;;
"Java(TM)")
JVM_VENDOR=Oracle
# this will be "64-Bit" or "32-Bit"
JVM_ARCH=`echo "$java_ver_output" | awk 'NR==3 {print $3}'`
;;
*)
# Help fill in other JVM values
JVM_VENDOR=other
JVM_ARCH=unknown
;;
esac
# Read user-defined JVM options from jvm-server.options file
JVM_OPTS_FILE=$CASSANDRA_CONF/jvm${jvmoptions_variant:--clients}.options
if [ $JAVA_VERSION -ge 17 ] ; then
if [ $JAVA_VERSION -ge 21 ] ; then
JVM_DEP_OPTS_FILE=$CASSANDRA_CONF/jvm21${jvmoptions_variant:--clients}.options
elif [ $JAVA_VERSION -ge 17 ] ; then
JVM_DEP_OPTS_FILE=$CASSANDRA_CONF/jvm17${jvmoptions_variant:--clients}.options
elif [ $JAVA_VERSION -ge 11 ] ; then
JVM_DEP_OPTS_FILE=$CASSANDRA_CONF/jvm11${jvmoptions_variant:--clients}.options

View File

@ -60,8 +60,8 @@ public class Dump implements Runnable
@Parameters(paramLabel = "path", description = "Path containing the full query logs to dump.", arity = "1..*")
private List<String> arguments = new ArrayList<>();
@Option(paramLabel = "roll_cycle", names = { "--roll-cycle" }, description = "How often to roll the log file was rolled. May be necessary for Chronicle to correctly parse file names. (MINUTELY, HOURLY, DAILY). Default HOURLY.")
private String rollCycle = "HOURLY";
@Option(paramLabel = "roll_cycle", names = { "--roll-cycle" }, description = "How often to roll the log file was rolled. May be necessary for Chronicle to correctly parse file names. (FAST_MINUTELY, FAST_HOURLY, FAST_DAILY). Default FAST_HOURLY.")
private String rollCycle = "FAST_HOURLY";
@Option(paramLabel = "follow", names = { "--follow" }, description = "Upon reacahing the end of the log continue indefinitely waiting for more records")
private boolean follow = false;