diff --git a/CHANGES.txt b/CHANGES.txt index 0e9ef6d5a1..6fd9c15c7c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.11.3 + * Don't regenerate bloomfilter and summaries on startup (CASSANDRA-11163) * RateBasedBackPressure unnecessarily invokes a lock on the Guava RateLimiter (CASSANDRA-14163) * Fix wildcard GROUP BY queries (CASSANDRA-14209) Merged from 3.0: diff --git a/NEWS.txt b/NEWS.txt index 745dad2740..9af8439b24 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -49,6 +49,8 @@ Upgrading --------- - Materialized view users upgrading from 3.0.15 (3.0.X series) or 3.11.1 (3.11.X series) and later that have performed range movements (join, decommission, move, etc), should run repair on the base tables, and subsequently on the views to ensure data affected by CASSANDRA-14251 is correctly propagated to all replicas. + - Changes to bloom_filter_fp_chance will no longer take effect on existing sstables when the node is restarted. Only + compactions/upgradesstables regenerates bloom filters and Summaries sstable components. See CASSANDRA-11163 3.11.2 ====== diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java index c184d5e1d1..67bca77be4 100644 --- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java +++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java @@ -1900,8 +1900,8 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean { if (logger.isTraceEnabled()) logger.trace("using snapshot sstable {}", entries.getKey()); - // open without tracking hotness - sstable = SSTableReader.open(entries.getKey(), entries.getValue(), metadata, true, false); + // open offline so we don't modify components or track hotness. + sstable = SSTableReader.open(entries.getKey(), entries.getValue(), metadata, true, true); refs.tryRef(sstable); // release the self ref as we never add the snapshot sstable to DataTracker where it is otherwise released sstable.selfRef().release(); diff --git a/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java b/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java index d3dd2d3a41..7d7fbf1b42 100644 --- a/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java +++ b/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java @@ -382,19 +382,19 @@ public abstract class SSTableReader extends SSTable implements SelfRefCounted components, CFMetaData metadata) throws IOException { - return open(descriptor, components, metadata, true, true); + return open(descriptor, components, metadata, true, false); } // use only for offline or "Standalone" operations public static SSTableReader openNoValidation(Descriptor descriptor, Set components, ColumnFamilyStore cfs) throws IOException { - return open(descriptor, components, cfs.metadata, false, false); // do not track hotness + return open(descriptor, components, cfs.metadata, false, true); } // use only for offline or "Standalone" operations public static SSTableReader openNoValidation(Descriptor descriptor, CFMetaData metadata) throws IOException { - return open(descriptor, componentsFor(descriptor), metadata, false, false); // do not track hotness + return open(descriptor, componentsFor(descriptor), metadata, false, true); } /** @@ -460,11 +460,22 @@ public abstract class SSTableReader extends SSTable implements SelfRefCounted components, - CFMetaData metadata, - boolean validate, - boolean trackHotness) throws IOException + Set components, + CFMetaData metadata, + boolean validate, + boolean isOffline) throws IOException { // Minimum components without which we can't do anything assert components.contains(Component.DATA) : "Data component is missing for sstable " + descriptor; @@ -514,10 +525,10 @@ public abstract class SSTableReader extends SSTable implements SelfRefCounted components = SSTable.discoverComponentsFor(desc); + components.remove(Component.FILTER); + target = SSTableReader.openNoValidation(desc, components, store); + + assertEquals(bloomModified, Files.getLastModifiedTime(bloomPath).toMillis()); + assertEquals(summaryModified, Files.getLastModifiedTime(summaryPath).toMillis()); + assertEquals(FilterFactory.AlwaysPresent, target.getBloomFilter()); + + target.selfRef().release(); + + // #### online tests #### + // check that summary & bloomfilter are not regenerated when SSTable is opened and BFFP has been changed + target = SSTableReader.open(desc, store.metadata); + + assertEquals(bloomModified, Files.getLastModifiedTime(bloomPath).toMillis()); + assertEquals(summaryModified, Files.getLastModifiedTime(summaryPath).toMillis()); + + target.selfRef().release(); + + // check that bloomfilter is recreated when it doesn't exist and this causes the summary to be recreated + components = SSTable.discoverComponentsFor(desc); + components.remove(Component.FILTER); + + target = SSTableReader.open(desc, components, store.metadata); + + assertTrue("Bloomfilter was not recreated", bloomModified < Files.getLastModifiedTime(bloomPath).toMillis()); + assertTrue("Summary was not recreated", summaryModified < Files.getLastModifiedTime(summaryPath).toMillis()); + + target.selfRef().release(); + + // check that only the summary is regenerated when it is deleted + components.add(Component.FILTER); + summaryModified = Files.getLastModifiedTime(summaryPath).toMillis(); + summaryFile.delete(); + + Thread.sleep(TimeUnit.MILLISECONDS.toMillis(10)); // sleep to ensure modified time will be different + bloomModified = Files.getLastModifiedTime(bloomPath).toMillis(); + + target = SSTableReader.open(desc, components, store.metadata); + + assertEquals(bloomModified, Files.getLastModifiedTime(bloomPath).toMillis()); + assertTrue("Summary was not recreated", summaryModified < Files.getLastModifiedTime(summaryPath).toMillis()); + + target.selfRef().release(); + + // check that summary and bloomfilter is not recreated when the INDEX is missing + components.add(Component.SUMMARY); + components.remove(Component.PRIMARY_INDEX); + + summaryModified = Files.getLastModifiedTime(summaryPath).toMillis(); + target = SSTableReader.open(desc, components, store.metadata, false, false); + + Thread.sleep(TimeUnit.MILLISECONDS.toMillis(10)); // sleep to ensure modified time will be different + assertEquals(bloomModified, Files.getLastModifiedTime(bloomPath).toMillis()); + assertEquals(summaryModified, Files.getLastModifiedTime(summaryPath).toMillis()); + target.selfRef().release(); }