From 1c5286f4d107f5df6abf021a10f5cf67a9fe4686 Mon Sep 17 00:00:00 2001 From: Dmitry Konstantinov Date: Fri, 22 Aug 2025 14:02:27 +0100 Subject: [PATCH] Fix IndexOutOfBoundsException in sstablemetadata tool when a range tombstone is a max clustering value patch by Dmitry Konstantinov; reviewed by Stefan Miklosovic for CASSANDRA-20855 --- CHANGES.txt | 1 + .../tools/SSTableMetadataViewer.java | 33 ++++++----- .../nb-1-big-CompressionInfo.db | Bin 0 -> 47 bytes .../CASSANDRA_20855/nb-1-big-Data.db | Bin 0 -> 83 bytes .../CASSANDRA_20855/nb-1-big-Digest.crc32 | 1 + .../CASSANDRA_20855/nb-1-big-Filter.db | Bin 0 -> 16 bytes .../CASSANDRA_20855/nb-1-big-Index.db | Bin 0 -> 14 bytes .../CASSANDRA_20855/nb-1-big-Statistics.db | Bin 0 -> 4858 bytes .../CASSANDRA_20855/nb-1-big-Summary.db | Bin 0 -> 74 bytes .../CASSANDRA_20855/nb-1-big-TOC.txt | 8 +++ .../tools/SSTableMetadataViewerTest.java | 55 ++++++++++++++++++ 11 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-CompressionInfo.db create mode 100644 test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Data.db create mode 100644 test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Digest.crc32 create mode 100644 test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Filter.db create mode 100644 test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Index.db create mode 100644 test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Statistics.db create mode 100644 test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Summary.db create mode 100644 test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-TOC.txt diff --git a/CHANGES.txt b/CHANGES.txt index 6296bb94f6..72696ad020 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.0.19 + * Fix IndexOutOfBoundsException in sstablemetadata tool when a range tombstone is a max clustering value (CASSANDRA-20855) * Update Jackson to 2.19.2 (CASSANDRA-20848) * Update commons-lang3 to 3.18.0 (CASSANDRA-20849) * Add NativeTransportMaxConcurrentConnectionsPerIp to StorageProxyMBean (CASSANDRA-20642) diff --git a/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java b/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java index bad7b13150..e3c7d76633 100755 --- a/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java +++ b/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java @@ -355,21 +355,9 @@ public class SSTableMetadataViewer if (validation != null && header != null) printMinMaxToken(descriptor, FBUtilities.newPartitioner(descriptor), header.getKeyType()); - if (header != null && header.getClusteringTypes().size() == stats.minClusteringValues.size()) - { - List> clusteringTypes = header.getClusteringTypes(); - List minClusteringValues = stats.minClusteringValues; - List maxClusteringValues = stats.maxClusteringValues; - String[] minValues = new String[clusteringTypes.size()]; - String[] maxValues = new String[clusteringTypes.size()]; - for (int i = 0; i < clusteringTypes.size(); i++) - { - minValues[i] = clusteringTypes.get(i).getString(minClusteringValues.get(i)); - maxValues[i] = clusteringTypes.get(i).getString(maxClusteringValues.get(i)); - } - field("minClusteringValues", Arrays.toString(minValues)); - field("maxClusteringValues", Arrays.toString(maxValues)); - } + printClusteringValues(header, "minClusteringValues", stats.minClusteringValues); + printClusteringValues(header, "maxClusteringValues", stats.maxClusteringValues); + field("Estimated droppable tombstones", stats.getEstimatedDroppableTombstoneRatio((int) (System.currentTimeMillis() / 1000) - this.gc)); field("SSTable Level", stats.sstableLevel); @@ -436,6 +424,21 @@ public class SSTableMetadataViewer } } + private void printClusteringValues(SerializationHeader.Component header, String name, List clusteringValues) + { + if (header != null && header.getClusteringTypes().size() >= clusteringValues.size()) + { + List> clusteringTypes = header.getClusteringTypes(); + int size = Math.min(clusteringTypes.size(), clusteringValues.size()); + String[] values = new String[size]; + for (int i = 0; i < size; i++) + { + values[i] = clusteringTypes.get(i).getString(clusteringValues.get(i)); + } + field(name, Arrays.toString(values)); + } + } + private void field(String field, Object value) { field(field, value, null); diff --git a/test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-CompressionInfo.db b/test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-CompressionInfo.db new file mode 100644 index 0000000000000000000000000000000000000000..7d7289b0c5c513e7fbd27e7fba1253035b2db5ab GIT binary patch literal 47 ocmZSJ^@%cZ&d)64-sGIpVkrjoctbvhUra{vhMW=% l9IR!DIi;ygj0}w041Go{8jCd*8%LW7CZm| literal 0 HcmV?d00001 diff --git a/test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Digest.crc32 b/test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Digest.crc32 new file mode 100644 index 0000000000..441a80dd5f --- /dev/null +++ b/test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Digest.crc32 @@ -0,0 +1 @@ +3617993137 \ No newline at end of file diff --git a/test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Filter.db b/test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Filter.db new file mode 100644 index 0000000000000000000000000000000000000000..678c0aafe072f94d546aca818837d8e4ce5bf7db GIT binary patch literal 16 XcmZQzU|?lnU|?iqV&D*PU|;|M0hj<{ literal 0 HcmV?d00001 diff --git a/test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Index.db b/test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Index.db new file mode 100644 index 0000000000000000000000000000000000000000..d533e13df5e38dbb1041e53d4111dd672890ba66 GIT binary patch literal 14 VcmZSJDo89UiO){0j5lOp0018{1Nr~} literal 0 HcmV?d00001 diff --git a/test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Statistics.db b/test/data/sstable_metadata/CASSANDRA_20855/nb-1-big-Statistics.db new file mode 100644 index 0000000000000000000000000000000000000000..9f1f6998b8a500a90268e52172323d85e3ff66f2 GIT binary patch literal 4858 zcmeI$ZA=qq902fp?ylvq-|l-X|L~^(c+S@s_qYU>X-- zA4Uvg%NUyZGPi^n6bVyjVa$DSgUvZnvJ7U1!K?$vGTWKy@MUy&gG>MaC;Pz1edv>1 zp8MVZf9>-;_uSo+V;F`{SiMBS%#^iaMa0b}ZmhV~iW|o;+B8+{TT{%MO2=-UP$gLH zHl0;)I)#c7hoCF5yL8W2JIbpa`fS1BDs`1sR@fYd#=2XkGf}S(j=Ig_kEr~9|Fk-q zkiLm-%?De`c8bT^#7!#FAHqUgY6vW1gHYj-7)I`ld{`;(%+?{4Ln((-R#Dbaj-VVx zc`@asl$TRZq?|-~Gv!RmFH+t;Yk6GvQSnyFXDJV36Y6@9XQ;S~@ z2#)gw*a|(iG8H?7>Tl>H91kDBR(Y|XcoSRuA@;(Tv15j?pInEXa2#7#h@Em2JEIRf zdja;YXl!Q=c9VeJPR-u|BaVCHkV)Jh*oFDnNAdh5-XBn$&6DTd%whI2HdlBR^D)AB8^xn~79uac8H2oZI2U>O zAimy-Q}}x8TfRW~sbjw&KbMZ%_fm`p#rOQKMSdfz3;FPajmYjV@%W6o(Rh;Z`S)Nx zF_;b_A6Rx0`P)nDq1lxe(DRjjU-LbTb1^k&esDcI!(g1R2}^@kyfTdXtE?=of$vurs9xqRZw#I+D1$ys8^*D6%R~;tkQ+bD%L4ViQ_%`(Y^F!N! z$trbm543gbR(SuDj_eEY{wMzTH1PgsZJwK-f%Dn1(`j|UoQrtg1?E=_YNhwTT==P} zeen7y{%UE3?~jnxk>lxdvRH?(_v|VR)kVHQ?<>x=zFP6nQr# z!}(m1Yiw@;`HjWyfid7?KaKXa17G~;<1W}<&!xnnlt7$l8?HRg05)@IT56E2CT=H3P&Pm5w<-lwmTyvoT39h-&aFF1d3ynu`%@tg8feG>d zUUQK{6B*kdGK~H_qf9jwWwnpY)R&39^Jm`y@xzGR6~nkCp}}_7E?Rmolk^*FY87&D z=7UT?lGWC-YNyNcs;$Ha(Rac6bHh)>&T_A#se`|D7#u3T_9?LwKZAphBo`L$IxcFvh| SPGktTS16lv`oY+%xBme~ file.isFile() && file.getName().endsWith("-Data.db")); + return sstableFiles[0].getAbsolutePath(); + } }