Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e59a7ad
implement API endpoint for nodetool compaction stop
Oct 30, 2025
1621d35
include CassandraCompactionManagerOperations.java modification for no…
Oct 30, 2025
ff07a40
clean imports, add annotations, improve naming for constants
Oct 31, 2025
fc26e34
add compaction type enum support, add full compaction integration tes…
Nov 10, 2025
faa9f7c
remove redundant JSON response fields for compaction stop endpoint
Nov 19, 2025
3e60ced
Merge branch 'trunk' into CASSSIDECAR-360
shalnisundram Nov 19, 2025
a6b5497
include compaction stop import
Nov 19, 2025
f404939
add SidecarClientTest test for compaction stop, assumeTrue() for inte…
Dec 3, 2025
0a9b3f4
make minor structural changes, adjust tests
Dec 4, 2025
39c9242
throttle compaction via nodetool compactiontrhoughput to slow compact…
Dec 8, 2025
a439508
fix enum errors in integration tests
Dec 11, 2025
08fce25
shorten integration test duration for triggering and testing compacti…
shalnisundram Dec 15, 2025
6a023d6
eliminiate redundant tests and settings in CompactionStopIntegrationT…
shalnisundram Dec 16, 2025
b4bb71e
return trimmed compaction ID, throw errors, add new lines
shalnisundram Dec 17, 2025
dcf5c94
change post to put request, clean up, edit compaction types
shalnisundram Dec 22, 2025
4d9101d
resolve checksytle errors
shalnisundram Dec 22, 2025
f83d1bb
apply formatting changes
shalnisundram Dec 22, 2025
1ed12a2
edit enums in tests, make bug fix for post to put request change
shalnisundram Dec 22, 2025
9767b72
limit CompactionType functionality to adapter-specific checks for sup…
shalnisundram Jan 2, 2026
bddf663
limit CompactionType enum to use in cassandra version-specific adapte…
shalnisundram Jan 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,11 @@ public CassandraAdapter(DnsResolver dnsResolver,
this.tableOperations = Objects.requireNonNull(createTableOperations(jmxClient), "tableOperations is required");
this.compactionManagerOperations = Objects.requireNonNull(createCompactionManagerOperations(jmxClient), "compactionManagerOperations is required");
this.metricsOperations = Objects.requireNonNull(createMetricsOperations(jmxClient, tableSchemaFetcher), "metricsOperations is required");
this.compactionStatsOperations = Objects.requireNonNull(createCompactionStatsOperations(storageOperations, metricsOperations,
compactionManagerOperations), "compactionStatsOperations is required");
this.compactionStatsOperations
= Objects.requireNonNull(createCompactionStatsOperations(storageOperations,
metricsOperations,
compactionManagerOperations),
"compactionStatsOperations is required");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.cassandra.sidecar.adapters.base;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.cassandra.sidecar.adapters.base.jmx.CompactionManagerJmxOperations;
import org.apache.cassandra.sidecar.common.server.CompactionManagerOperations;
Expand Down Expand Up @@ -53,4 +55,56 @@ public List<Map<String, String>> getCompactions()
return jmxClient.proxy(CompactionManagerJmxOperations.class, COMPACTION_MANAGER_OBJ_NAME)
.getCompactions();
}

/**
* {@inheritDoc}
*/
@Override
public void stopCompactionById(String compactionId)
{
// compactionId takes precedence over type if both are provided
if (compactionId != null && !compactionId.trim().isEmpty())
{
CompactionManagerJmxOperations proxy = jmxClient.proxy(CompactionManagerJmxOperations.class,
COMPACTION_MANAGER_OBJ_NAME);
proxy.stopCompactionById(compactionId);
}
else
{
throw new IllegalArgumentException("compaction process with compaction ID "
+ compactionId + " is null or empty");
}
}

@Override
public void stopCompaction(String compactionType)
{
if (compactionType != null && !compactionType.trim().isEmpty())
{
if (supportedCompactionTypes().contains(compactionType))
{
CompactionManagerJmxOperations proxy = jmxClient.proxy(CompactionManagerJmxOperations.class,
COMPACTION_MANAGER_OBJ_NAME);
String errMsg
= "compaction process with compaction type " + compactionType + " must not be null when compactionId is not provided";
proxy.stopCompaction(Objects.requireNonNull(compactionType, errMsg));
}
else
{
throw new IllegalArgumentException("compaction type " + compactionType + " is not supported");
}
}
else
{
throw new IllegalArgumentException("compaction type " + compactionType + " is null or empty");
}
}

@Override
public List<String> supportedCompactionTypes()
{
return Arrays.stream(CompactionType.values())
.map(CompactionType::name)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@
import org.apache.cassandra.sidecar.db.schema.TableSchemaFetcher;

/**
* Factory to produce the 4.0 adapter
* Factory to produce the Cassandra 5.x adapter
*/
@MinimumVersion("4.0.0")
@MinimumVersion("5.0.0")
public class CassandraFactory implements ICassandraFactory
{
private final DnsResolver dnsResolver;
Expand All @@ -48,12 +48,12 @@ public CassandraFactory(DnsResolver dnsResolver, DriverUtils driverUtils, TableS
}

/**
* Returns a new adapter for Cassandra 4.0 clusters.
* Returns a new adapter for Cassandra 5.x clusters.
*
* @param session the session to the Cassandra database
* @param jmxClient the JMX client to connect to the Cassandra database
* @param localNativeTransportAddress the address and port on which this instance is configured to listen
* @return a new adapter for the 4.0 clusters
* @return a new adapter for the 5.x clusters
*/
@Override
public ICassandraAdapter create(CQLSessionProvider session,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.sidecar.adapters.base;

import java.util.Locale;

import com.fasterxml.jackson.annotation.JsonCreator;

/**
* Supported compaction types based on Cassandra's OperationType enum
*/
public enum CompactionType
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not see MAJOR_COMPACTION type here from OperationType class, is that intentional?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the catch - I may have been looking at another C* version. Just changed it to reflect this list: https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/db/compaction/OperationType.java

{
CLEANUP,
SCRUB,
UPGRADE_SSTABLES,
VERIFY,
RELOCATE,
GARBAGE_COLLECT,
ANTICOMPACTION,
VALIDATION,
INDEX_BUILD,
VIEW_BUILD,
COMPACTION,
TOMBSTONE_COMPACTION,
KEY_CACHE_SAVE,
ROW_CACHE_SAVE,
COUNTER_CACHE_SAVE,
INDEX_SUMMARY;

@Override
public String toString()
{
return name();
}

/**
* Case-insensitive factory method for Jackson deserialization
* @return {@link CompactionType} from string
*/
@JsonCreator
public static CompactionType fromString(String name)
{
if (name == null || name.trim().isEmpty())
{
return null;
}
try
{
return valueOf(name.trim().toUpperCase(Locale.ROOT));
}
catch (IllegalArgumentException unknownEnum)
{
String validTypes = String.join(", ",
java.util.Arrays.stream(CompactionType.values())
.map(CompactionType::name)
.toArray(String[]::new));
throw new IllegalArgumentException(
String.format("Unsupported compactionType: '%s'. Valid types are: %s",
name, validTypes));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,16 @@ public interface CompactionManagerJmxOperations
* @return list of compaction info maps
*/
List<Map<String, String>> getCompactions();

/**
* Stop compaction by type
* @throws IllegalArgumentException when compaction type is null
*/
void stopCompaction(String type);

/**
* Stop compaction by ID
* @throws IllegalArgumentException when compaction ID is null
*/
void stopCompactionById(String compactionId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.cassandra.sidecar.adapters.base;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.apache.cassandra.sidecar.adapters.base.jmx.CompactionManagerJmxOperations;
import org.apache.cassandra.sidecar.common.server.JmxClient;

import static org.apache.cassandra.sidecar.adapters.base.jmx.CompactionManagerJmxOperations.COMPACTION_MANAGER_OBJ_NAME;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
* Tests for {@link CassandraCompactionManagerOperations} class
*/
class CassandraCompactionManagerOperationsTest
{
private CassandraCompactionManagerOperations compactionManagerOperations;
private JmxClient mockJmxClient;
private CompactionManagerJmxOperations mockJmxOperations;

@BeforeEach
void setUp()
{
mockJmxClient = mock(JmxClient.class);
mockJmxOperations = mock(CompactionManagerJmxOperations.class);
compactionManagerOperations = new CassandraCompactionManagerOperations(mockJmxClient);

// Setup JMX proxy mock
when(mockJmxClient.proxy(CompactionManagerJmxOperations.class, COMPACTION_MANAGER_OBJ_NAME))
.thenReturn(mockJmxOperations);
}

@Test
void testStopCompactionByIdOnly()
{
// Test stopCompactionById called when providing compactionId
String compactionId = "abc-123";
compactionManagerOperations.stopCompactionById(compactionId);

verify(mockJmxOperations, times(1)).stopCompactionById(compactionId);
verify(mockJmxOperations, times(0)).stopCompaction(org.mockito.ArgumentMatchers.anyString());
}

@Test
void testStopCompactionByTypeOnly()
{
// Test stopCompaction called when no compactionId provided
String compactionType = "COMPACTION";
compactionManagerOperations.stopCompaction(compactionType);

verify(mockJmxOperations, times(1)).stopCompaction(compactionType);
verify(mockJmxOperations, times(0)).stopCompactionById(org.mockito.ArgumentMatchers.anyString());
}

@Test
void testStopCompactionByIdWithWhitespace()
{
// Test trim does not result in empty string
String compactionId = " abc-123 ";
compactionManagerOperations.stopCompactionById(compactionId);

verify(mockJmxOperations, times(1)).stopCompactionById(compactionId);
verify(mockJmxOperations, times(0)).stopCompaction(org.mockito.ArgumentMatchers.anyString());
}

@Test
void testStopCompactionAllSupportedTypes()
{
// Test no failures upon any supported type being provided as param
String[] supportedTypes = {
"COMPACTION", "VALIDATION", "KEY_CACHE_SAVE", "ROW_CACHE_SAVE",
"COUNTER_CACHE_SAVE", "CLEANUP", "SCRUB", "UPGRADE_SSTABLES",
"INDEX_BUILD", "TOMBSTONE_COMPACTION", "ANTICOMPACTION",
"VERIFY", "VIEW_BUILD", "INDEX_SUMMARY", "RELOCATE",
"GARBAGE_COLLECT"
};

for (String type : supportedTypes)
{
compactionManagerOperations.stopCompaction(type);
verify(mockJmxOperations, times(1)).stopCompaction(type);
}
}

@Test
void testStopCompactionJmxProxyCalledOnce()
{
// Test JMX proxy obtained exactly once per call
compactionManagerOperations.stopCompactionById("test-id");

verify(mockJmxClient, times(1))
.proxy(CompactionManagerJmxOperations.class, COMPACTION_MANAGER_OBJ_NAME);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import org.apache.cassandra.sidecar.adapters.base.CassandraAdapter;
import org.apache.cassandra.sidecar.common.server.CQLSessionProvider;
import org.apache.cassandra.sidecar.common.server.CompactionManagerOperations;
import org.apache.cassandra.sidecar.common.server.ICassandraAdapter;
import org.apache.cassandra.sidecar.common.server.JmxClient;
import org.apache.cassandra.sidecar.common.server.StorageOperations;
Expand All @@ -31,7 +32,7 @@
import org.jetbrains.annotations.NotNull;

/**
* A {@link ICassandraAdapter} implementation for Cassandra 4.1 and later
* A {@link ICassandraAdapter} implementation for Cassandra 4.x
*/
public class Cassandra41Adapter extends CassandraAdapter
{
Expand All @@ -54,4 +55,16 @@ protected StorageOperations createStorageOperations(DnsResolver dnsResolver, Jmx
{
return new Cassandra41StorageOperations(jmxClient, dnsResolver);
}

/**
* {@inheritDoc}
*
* Returns Cassandra 4.x-specific CompactionManagerOperations that excludes unsupported types
*/
@Override
@NotNull
protected CompactionManagerOperations createCompactionManagerOperations(JmxClient jmxClient)
{
return new Cassandra41CompactionManagerOperations(jmxClient);
}
}
Loading