diff --git a/.github/workflows/docker-release.yaml b/.github/workflows/docker-release.yaml
index 7a545e92..6b89f3ad 100644
--- a/.github/workflows/docker-release.yaml
+++ b/.github/workflows/docker-release.yaml
@@ -319,9 +319,9 @@ jobs:
fail-fast: false
max-parallel: 4
matrix:
- cassandra-version: [4.1.0, 4.1.1, 4.1.2, 4.1.3, 4.1.4, 4.1.5]
+ cassandra-version: [4.1.0, 4.1.1, 4.1.2, 4.1.3, 4.1.4, 4.1.5, 4.1.6]
include:
- - cassandra-version: 4.1.5
+ - cassandra-version: 4.1.6
latest: true
runs-on: ubuntu-latest
steps:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa3ae5e7..a6108ce4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ Changelog for Management API, new PRs should update the `main / unreleased` sect
## unreleased
* [FEATURE] [#517](https://github.com/k8ssandra/management-api-for-apache-cassandra/issues/517) Add DSE 6.9.0 to the build matrix
+* [FEATURE] [#527](https://github.com/k8ssandra/management-api-for-apache-cassandra/issues/527) Add Cassandra 4.1.6 to the build matrix
* [ENHANCEMENT] [#516](https://github.com/k8ssandra/management-api-for-apache-cassandra/issues/516) Address warnings in Dockerfiles
* [ENHANCEMENT] [#521](https://github.com/k8ssandra/management-api-for-apache-cassandra/issues/521) Add management-api to Cassandra conf in the Dockerfile, not entrypoint for DSE 6.9, Cassandra 4.1 and Cassandra 5.0. This allows to run the container with readOnlyRootFilesystem.
* [BUGFIX] [#524](https://github.com/k8ssandra/management-api-for-apache-cassandra/issues/524) Fix HintsService Hint_delays- metrics parsing and ReadCoordination metrics parsing
diff --git a/README.md b/README.md
index 1cddd739..3f0af6cb 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@ The following versions of Cassandra and DSE are published to Docker and supporte
| 3.11.12 | 4.0.4 | 4.1.3 | 6.8.29 | |
| 3.11.13 | 4.0.5 | 4.1.4 | 6.8.30 | |
| 3.11.14 | 4.0.6 | 4.1.5 | 6.8.31 | |
-| 3.11.15 | 4.0.7 | | 6.8.32 | |
+| 3.11.15 | 4.0.7 | 4.1.6 | 6.8.32 | |
| 3.11.16 | 4.0.8 | | 6.8.33 | |
| 3.11.17 | 4.0.9 | | 6.8.34 | |
| | 4.0.10 | | 6.8.35 | |
diff --git a/cassandra/Dockerfile-4.1 b/cassandra/Dockerfile-4.1
index 3441365f..ff713bff 100644
--- a/cassandra/Dockerfile-4.1
+++ b/cassandra/Dockerfile-4.1
@@ -1,4 +1,4 @@
-ARG CASSANDRA_VERSION=4.1.5
+ARG CASSANDRA_VERSION=4.1.6
FROM --platform=$BUILDPLATFORM maven:3.8.7-eclipse-temurin-11 AS builder
diff --git a/cassandra/Dockerfile-4.1.ubi8 b/cassandra/Dockerfile-4.1.ubi8
index 7a150b89..db8ff71d 100644
--- a/cassandra/Dockerfile-4.1.ubi8
+++ b/cassandra/Dockerfile-4.1.ubi8
@@ -1,6 +1,6 @@
ARG UBI_MAJOR=8
ARG UBI_BASETAG=latest
-ARG CASSANDRA_VERSION=4.1.5
+ARG CASSANDRA_VERSION=4.1.6
FROM registry.access.redhat.com/ubi${UBI_MAJOR}/ubi-minimal:${UBI_BASETAG} AS builder
ARG URL_PREFIX=https://dlcdn.apache.org/cassandra
diff --git a/management-api-agent-4.1.x/pom.xml b/management-api-agent-4.1.x/pom.xml
index cdec1e08..599dc453 100644
--- a/management-api-agent-4.1.x/pom.xml
+++ b/management-api-agent-4.1.x/pom.xml
@@ -16,7 +16,7 @@
${revision}
datastax-mgmtapi-agent-4.1.x
- 4.1.5
+ 4.1.6
diff --git a/management-api-agent-4.1.x/src/main/java/com/datastax/mgmtapi/shim/RpcStatement41x.java b/management-api-agent-4.1.x/src/main/java/com/datastax/mgmtapi/shim/RpcStatement41x.java
index 11418a49..5c9e6b7b 100644
--- a/management-api-agent-4.1.x/src/main/java/com/datastax/mgmtapi/shim/RpcStatement41x.java
+++ b/management-api-agent-4.1.x/src/main/java/com/datastax/mgmtapi/shim/RpcStatement41x.java
@@ -10,6 +10,7 @@
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.service.QueryState;
+import org.apache.cassandra.transport.Dispatcher.RequestTime;
import org.apache.cassandra.transport.messages.ResultMessage;
public class RpcStatement41x implements RpcStatementShim {
@@ -27,11 +28,22 @@ public void authorize(ClientState clientState) {}
@Override
public void validate(ClientState clientState) {}
- @Override
+ /**
+ * as of Cassandra 4.1.6, CASSANDRA-19534, org.apache.cassandra.cql3.CQLStatement no longer has
+ * the method signature below, so we need to remove the @Override annotation.
+ */
public ResultMessage execute(QueryState queryState, QueryOptions queryOptions, long l) {
return new ResultMessage.Void();
}
+ /**
+ * as of Cassandra 4.1.6, CASSANDRA-19534, org.apache.cassandra.cql3.CQLStatement now has the
+ * method signature below, but it does not exist in Cassandra < 4.1.6.
+ */
+ public ResultMessage execute(QueryState queryState, QueryOptions queryOptions, RequestTime rt) {
+ return new ResultMessage.Void();
+ }
+
@Override
public ResultMessage executeLocally(QueryState queryState, QueryOptions queryOptions) {
return new ResultMessage.Void();
diff --git a/management-api-agent-4.1.x/src/main/java/org/apache/cassandra/transport/UnixSocketServer41x.java b/management-api-agent-4.1.x/src/main/java/org/apache/cassandra/transport/UnixSocketServer41x.java
index 11a8a69f..bd431997 100644
--- a/management-api-agent-4.1.x/src/main/java/org/apache/cassandra/transport/UnixSocketServer41x.java
+++ b/management-api-agent-4.1.x/src/main/java/org/apache/cassandra/transport/UnixSocketServer41x.java
@@ -101,7 +101,33 @@ protected void channelRead0(ChannelHandlerContext ctx, Message.Request request)
// logger.info("Executing {} {} {}", request, connection.getVersion(),
// request.getStreamId());
- Message.Response r = request.execute(qstate, queryStartNanoTime);
+ // In Cassandra 4.1.6, CASSANDRA-19534 changed the Message.Request.execute method signature
+ // to take a new Dispatcher.RequestTime object instead of a primitive long for the Query
+ // start time. We'll need to introduce reflection here to create the correct Objects and
+ // make the correct calls based on which version of 4.1.x we are.
+ Message.Response r = null;
+ try {
+ // First see if we have the Dispatcher.RequestTime class. If so, assume we are 4.1.6+
+ Class dispatcherRequestTime =
+ Class.forName("org.apache.cassandra.transport.Dispatcher$RequestTime");
+ // we are 4.1.6+, get Dispatcher.RequestTime.forImmediateExecution()
+ Method forImmediateExecution =
+ dispatcherRequestTime.getDeclaredMethod("forImmediateExecution");
+ Method requestExecute =
+ Message.Request.class.getDeclaredMethod(
+ "execute", QueryState.class, dispatcherRequestTime);
+ r =
+ (Message.Response)
+ requestExecute.invoke(request, qstate, forImmediateExecution.invoke(null));
+
+ } catch (ClassNotFoundException cfne) {
+ logger.debug(
+ "Dispatcher$RequestTime in 4.1.6+ not found, trying Request.execute from older versions");
+ // we must be 4.1.5-
+ Method requestExecute =
+ Message.Request.class.getDeclaredMethod("execute", QueryState.class, long.class);
+ r = (Message.Response) requestExecute.invoke(request, qstate, queryStartNanoTime);
+ }
// UnixSocket has no auth
response = r instanceof AuthenticateMessage ? new ReadyMessage() : r;
@@ -291,37 +317,24 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List