From 21fc575e7efe131a9eb712392280cf8b2542d770 Mon Sep 17 00:00:00 2001 From: Nagaraj Lakkarasu Date: Thu, 8 Jan 2026 13:51:16 -0800 Subject: [PATCH] Make active compaction remaining time reported by nodetool compactionstats more accurate Use current compaction throughput (1 minute) instead of configured compaction_throughput to calculate remaining time. This provides more accurate estimates when the actual compaction speed is lower than the configured limit. Falls back to configured throughput if current throughput is unavailable or zero. patch by Nagaraj Lakkarasu; reviewed by (pending) for CASSANDRA-21073 --- .../tools/nodetool/CompactionStats.java | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/java/org/apache/cassandra/tools/nodetool/CompactionStats.java b/src/java/org/apache/cassandra/tools/nodetool/CompactionStats.java index 4dab0158a17..b837d2bc28b 100644 --- a/src/java/org/apache/cassandra/tools/nodetool/CompactionStats.java +++ b/src/java/org/apache/cassandra/tools/nodetool/CompactionStats.java @@ -56,7 +56,21 @@ public void execute(NodeProbe probe) TableBuilder tableBuilder = new TableBuilder(); pendingTasksAndConcurrentCompactorsStats(probe, tableBuilder); compactionsStats(probe, tableBuilder); - reportCompactionTable(probe.getCompactionManagerProxy().getCompactions(), probe.getCompactionThroughputBytes(), humanReadable, vtableOutput, out, tableBuilder); + Map currentCompactionThroughputMetricsMap = probe.getCurrentCompactionThroughputMiBPerSec(); + String currentThroughput1MinStr = currentCompactionThroughputMetricsMap.get("1minute"); + Double currentCompactionThroughputMiBPerSec = null; + try + { + if (currentThroughput1MinStr != null && !currentThroughput1MinStr.isEmpty()) + { + currentCompactionThroughputMiBPerSec = Double.parseDouble(currentThroughput1MinStr); + } + } + catch (NumberFormatException e) + { + // If parsing fails, currentCompactionThroughputMiBPerSec remains null and we'll fall back to configured throughput + } + reportCompactionTable(probe.getCompactionManagerProxy().getCompactions(), probe.getCompactionThroughputBytes(), currentCompactionThroughputMiBPerSec, humanReadable, vtableOutput, out, tableBuilder); } private void pendingTasksAndConcurrentCompactorsStats(NodeProbe probe, TableBuilder tableBuilder) @@ -118,10 +132,15 @@ private void compactionsStats(NodeProbe probe, TableBuilder tableBuilder) public static void reportCompactionTable(List> compactions, long compactionThroughputInBytes, boolean humanReadable, PrintStream out, TableBuilder table) { - reportCompactionTable(compactions, compactionThroughputInBytes, humanReadable, false, out, table); + reportCompactionTable(compactions, compactionThroughputInBytes, null, humanReadable, false, out, table); } public static void reportCompactionTable(List> compactions, long compactionThroughputInBytes, boolean humanReadable, boolean vtableOutput, PrintStream out, TableBuilder table) + { + reportCompactionTable(compactions, compactionThroughputInBytes, null, humanReadable, vtableOutput, out, table); + } + + public static void reportCompactionTable(List> compactions, long compactionThroughputInBytes, Double currentCompactionThroughputMiBPerSec, boolean humanReadable, boolean vtableOutput, PrintStream out, TableBuilder table) { if (compactions.isEmpty()) { @@ -162,9 +181,22 @@ public static void reportCompactionTable(List> compactions, l } String remainingTime = "n/a"; - if (compactionThroughputInBytes != 0) + long throughputInBytes = 0; + + // Use current compaction throughput (1 minute) if available and > 0, otherwise fall back to configured throughput + if (currentCompactionThroughputMiBPerSec != null && currentCompactionThroughputMiBPerSec > 0) + { + // Convert MiB/s to bytes/s (1 MiB = 1024 * 1024 bytes) + throughputInBytes = (long) (currentCompactionThroughputMiBPerSec * 1024 * 1024); + } + else if (compactionThroughputInBytes != 0) + { + throughputInBytes = compactionThroughputInBytes; + } + + if (throughputInBytes > 0) { - long remainingTimeInSecs = remainingBytes / compactionThroughputInBytes; + long remainingTimeInSecs = remainingBytes / throughputInBytes; remainingTime = format("%dh%02dm%02ds", remainingTimeInSecs / 3600, (remainingTimeInSecs % 3600) / 60, (remainingTimeInSecs % 60)); }