From 94c579211b0c280c04e6b208dacd05118efaec5e Mon Sep 17 00:00:00 2001 From: David Capwell Date: Fri, 29 May 2026 15:30:12 -0700 Subject: [PATCH] CASSANDRA-21412: Journal compaction did not get a reference to segments to segfault due to use-after-free --- .../apache/cassandra/journal/Compactor.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/java/org/apache/cassandra/journal/Compactor.java b/src/java/org/apache/cassandra/journal/Compactor.java index ffc48ff5f2e1..be7d21847396 100644 --- a/src/java/org/apache/cassandra/journal/Compactor.java +++ b/src/java/org/apache/cassandra/journal/Compactor.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -29,6 +30,7 @@ import org.apache.cassandra.concurrent.ScheduledExecutorPlus; import org.apache.cassandra.concurrent.Shutdownable; +import org.apache.cassandra.utils.concurrent.Ref; import org.apache.cassandra.utils.concurrent.WaitQueue; import static org.apache.cassandra.concurrent.ExecutorFactory.Global.executorFactory; @@ -87,6 +89,24 @@ public void run() toCompact.subList(limit, toCompact.size()).clear(); } + // Hold refs on all segments to prevent them from being cleaned up (mmap unmapped) + // while the compactor is still reading from them. Segments whose ref can't be + // acquired have already been released and must be skipped. + List>> refs = new ArrayList<>(toCompact.size()); + Iterator> it = toCompact.iterator(); + while (it.hasNext()) + { + StaticSegment segment = it.next(); + Ref> ref = segment.tryRef(); + if (ref == null) + it.remove(); + else + refs.add(ref); + } + + if (toCompact.isEmpty()) + return; + try { Collection> newSegments = segmentCompactor.compact(toCompact); @@ -104,6 +124,11 @@ public void run() { throw new RuntimeException("Could not compact segments: " + toCompact); } + finally + { + for (Ref> ref : refs) + ref.release(); + } } @Override