This is an automated email from the ASF dual-hosted git repository. jmckenzie pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/trunk by this push: new e89b214d06 Allow disabling hotness persistence for high sstable counts e89b214d06 is described below commit e89b214d069321c8968871b8eb7d51d4dfba7c33 Author: Josh McKenzie <jmcken...@apache.org> AuthorDate: Tue Sep 13 12:48:00 2022 -0400 Allow disabling hotness persistence for high sstable counts Patch by Caleb Rackliffe; reviewed by Chris Lohfink and Josh McKenzie for CASSANDRA-17868 Co-authored-by: Caleb Rackliffe <calebrackli...@gmail.com> Co-authored-by: Josh McKenzie <jmcken...@apache.org> --- CHANGES.txt | 1 + src/java/org/apache/cassandra/config/Config.java | 2 + .../cassandra/config/DatabaseDescriptor.java | 14 +++++ .../org/apache/cassandra/db/SystemKeyspace.java | 11 +++- .../cassandra/io/sstable/format/SSTableReader.java | 25 +++++---- .../org/apache/cassandra/service/StorageProxy.java | 12 ++++ .../cassandra/service/StorageProxyMBean.java | 3 + .../cassandra/io/sstable/SSTableReaderTest.java | 64 ++++++++++++++++------ 8 files changed, 103 insertions(+), 29 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 10830cedb0..49858daa9a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.2 + * Allow disabling hotness persistence for high sstable counts (CASSANDRA-17868) * Prevent NullPointerException when changing neverPurgeTombstones from true to false (CASSANDRA-17897) * Add metrics around storage usage and compression (CASSANDRA-17898) * Remove usage of deprecated javax certificate classes (CASSANDRA-17867) diff --git a/src/java/org/apache/cassandra/config/Config.java b/src/java/org/apache/cassandra/config/Config.java index c3a406b455..168b62a32a 100644 --- a/src/java/org/apache/cassandra/config/Config.java +++ b/src/java/org/apache/cassandra/config/Config.java @@ -1052,6 +1052,8 @@ public class Config */ public volatile int paxos_repair_parallelism = -1; + public volatile boolean sstable_read_rate_persistence_enabled = false; + public volatile int max_top_size_partition_count = 10; public volatile int max_top_tombstone_partition_count = 10; public volatile DataStorageSpec.LongBytesBound min_tracked_partition_size = new DataStorageSpec.LongBytesBound("1MiB"); diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index 482e95fa75..d38bc46b2d 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -4496,4 +4496,18 @@ public class DatabaseDescriptor else logger.info("Setting dump_heap_on_uncaught_exception to {}", enabled); } + + public static boolean getSStableReadRatePersistenceEnabled() + { + return conf.sstable_read_rate_persistence_enabled; + } + + public static void setSStableReadRatePersistenceEnabled(boolean enabled) + { + if (enabled != conf.sstable_read_rate_persistence_enabled) + { + logger.info("Setting sstable_read_rate_persistence_enabled to {}", enabled); + conf.sstable_read_rate_persistence_enabled = enabled; + } + } } diff --git a/src/java/org/apache/cassandra/db/SystemKeyspace.java b/src/java/org/apache/cassandra/db/SystemKeyspace.java index 4e11c93d93..533d35ee2c 100644 --- a/src/java/org/apache/cassandra/db/SystemKeyspace.java +++ b/src/java/org/apache/cassandra/db/SystemKeyspace.java @@ -81,6 +81,7 @@ import org.apache.cassandra.dht.LocalPartitioner; import org.apache.cassandra.dht.Range; import org.apache.cassandra.dht.Token; import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.io.sstable.SSTable; import org.apache.cassandra.io.sstable.SSTableId; import org.apache.cassandra.io.sstable.SequenceBasedSSTableId; import org.apache.cassandra.io.util.DataInputBuffer; @@ -1476,8 +1477,7 @@ public final class SystemKeyspace */ public static RestorableMeter getSSTableReadMeter(String keyspace, String table, SSTableId id) { - String cql = "SELECT * FROM system.%s WHERE keyspace_name=? and table_name=? and id=?"; - UntypedResultSet results = executeInternal(format(cql, SSTABLE_ACTIVITY_V2), keyspace, table, id.toString()); + UntypedResultSet results = readSSTableActivity(keyspace, table, id); if (results.isEmpty()) return new RestorableMeter(); @@ -1488,6 +1488,13 @@ public final class SystemKeyspace return new RestorableMeter(m15rate, m120rate); } + @VisibleForTesting + public static UntypedResultSet readSSTableActivity(String keyspace, String table, SSTableId id) + { + String cql = "SELECT * FROM system.%s WHERE keyspace_name=? and table_name=? and id=?"; + return executeInternal(format(cql, SSTABLE_ACTIVITY_V2), keyspace, table, id.toString()); + } + /** * Writes the current read rates for a given SSTable to system.sstable_activity */ 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 d7dad42b16..fe8c537b61 100644 --- a/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java +++ b/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java @@ -2160,17 +2160,16 @@ public abstract class SSTableReader extends SSTable implements UnfilteredSource, readMeter = SystemKeyspace.getSSTableReadMeter(desc.ksname, desc.cfname, desc.id); // sync the average read rate to system.sstable_activity every five minutes, starting one minute from now - readMeterSyncFuture = new WeakReference<>(syncExecutor.scheduleAtFixedRate(new Runnable() + readMeterSyncFuture = new WeakReference<>(syncExecutor.scheduleAtFixedRate(this::maybePersistSSTableReadMeter, 1, 5, TimeUnit.MINUTES)); + } + + void maybePersistSSTableReadMeter() + { + if (obsoletion == null && DatabaseDescriptor.getSStableReadRatePersistenceEnabled()) { - public void run() - { - if (obsoletion == null) - { - meterSyncThrottle.acquire(); - SystemKeyspace.persistSSTableReadMeter(desc.ksname, desc.cfname, desc.id, readMeter); - } - } - }, 1, 5, TimeUnit.MINUTES)); + meterSyncThrottle.acquire(); + SystemKeyspace.persistSSTableReadMeter(desc.ksname, desc.cfname, desc.id, readMeter); + } } private void stopReadMeterPersistence() @@ -2389,4 +2388,10 @@ public abstract class SSTableReader extends SSTable implements UnfilteredSource, } return bytes; } + + @VisibleForTesting + public void maybePersistSSTableReadMeter() + { + tidy.global.maybePersistSSTableReadMeter(); + } } diff --git a/src/java/org/apache/cassandra/service/StorageProxy.java b/src/java/org/apache/cassandra/service/StorageProxy.java index 2bf140fc29..4a66b511be 100644 --- a/src/java/org/apache/cassandra/service/StorageProxy.java +++ b/src/java/org/apache/cassandra/service/StorageProxy.java @@ -3179,4 +3179,16 @@ public class StorageProxy implements StorageProxyMBean { DatabaseDescriptor.setDumpHeapOnUncaughtException(enabled); } + + @Override + public boolean getSStableReadRatePersistenceEnabled() + { + return DatabaseDescriptor.getSStableReadRatePersistenceEnabled(); + } + + @Override + public void setSStableReadRatePersistenceEnabled(boolean enabled) + { + DatabaseDescriptor.setSStableReadRatePersistenceEnabled(enabled); + } } diff --git a/src/java/org/apache/cassandra/service/StorageProxyMBean.java b/src/java/org/apache/cassandra/service/StorageProxyMBean.java index 5d7bc69569..4a3adfd5bd 100644 --- a/src/java/org/apache/cassandra/service/StorageProxyMBean.java +++ b/src/java/org/apache/cassandra/service/StorageProxyMBean.java @@ -138,4 +138,7 @@ public interface StorageProxyMBean public boolean getDumpHeapOnUncaughtException(); public void setDumpHeapOnUncaughtException(boolean enabled); + + boolean getSStableReadRatePersistenceEnabled(); + void setSStableReadRatePersistenceEnabled(boolean enabled); } diff --git a/test/unit/org/apache/cassandra/io/sstable/SSTableReaderTest.java b/test/unit/org/apache/cassandra/io/sstable/SSTableReaderTest.java index f064f19fd9..9567541048 100644 --- a/test/unit/org/apache/cassandra/io/sstable/SSTableReaderTest.java +++ b/test/unit/org/apache/cassandra/io/sstable/SSTableReaderTest.java @@ -26,7 +26,7 @@ import java.util.concurrent.*; import java.util.stream.Stream; import com.google.common.collect.Sets; -import org.apache.cassandra.io.util.File; + import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; @@ -34,7 +34,9 @@ import org.junit.rules.ExpectedException; import org.apache.cassandra.SchemaLoader; import org.apache.cassandra.Util; +import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.Operator; +import org.apache.cassandra.cql3.UntypedResultSet; import org.apache.cassandra.db.*; import org.apache.cassandra.db.compaction.CompactionManager; import org.apache.cassandra.db.compaction.OperationType; @@ -50,6 +52,7 @@ import org.apache.cassandra.dht.Token; import org.apache.cassandra.index.Index; import org.apache.cassandra.io.FSReadError; import org.apache.cassandra.io.sstable.format.SSTableReader; +import org.apache.cassandra.io.util.File; import org.apache.cassandra.io.util.FileDataInput; import org.apache.cassandra.io.util.MmappedRegions; import org.apache.cassandra.schema.CachingParams; @@ -59,6 +62,7 @@ import org.apache.cassandra.service.CacheService; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.FilterFactory; +import static java.lang.String.format; import static org.apache.cassandra.cql3.QueryProcessor.executeInternal; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -178,7 +182,7 @@ public class SSTableReaderTest DecoratedKey dk = Util.dk(String.valueOf(j)); FileDataInput file = sstable.getFileDataInput(sstable.getPosition(dk, SSTableReader.Operator.EQ).position); DecoratedKey keyInDisk = sstable.decorateKey(ByteBufferUtil.readWithShortLength(file)); - assert keyInDisk.equals(dk) : String.format("%s != %s in %s", keyInDisk, dk, file.getPath()); + assert keyInDisk.equals(dk) : format("%s != %s in %s", keyInDisk, dk, file.getPath()); } // check no false positives @@ -238,15 +242,41 @@ public class SSTableReaderTest Util.flush(store); - SSTableReader sstable = store.getLiveSSTables().iterator().next(); - assertEquals(0, sstable.getReadMeter().count()); + boolean startState = DatabaseDescriptor.getSStableReadRatePersistenceEnabled(); + try + { + DatabaseDescriptor.setSStableReadRatePersistenceEnabled(true); + + SSTableReader sstable = store.getLiveSSTables().iterator().next(); + assertEquals(0, sstable.getReadMeter().count()); - DecoratedKey key = sstable.decorateKey(ByteBufferUtil.bytes("4")); - Util.getAll(Util.cmd(store, key).build()); - assertEquals(1, sstable.getReadMeter().count()); + DecoratedKey key = sstable.decorateKey(ByteBufferUtil.bytes("4")); + Util.getAll(Util.cmd(store, key).build()); + assertEquals(1, sstable.getReadMeter().count()); - Util.getAll(Util.cmd(store, key).includeRow("0").build()); - assertEquals(2, sstable.getReadMeter().count()); + Util.getAll(Util.cmd(store, key).includeRow("0").build()); + assertEquals(2, sstable.getReadMeter().count()); + + // With persistence enabled, we should be able to retrieve the state of the meter. + sstable.maybePersistSSTableReadMeter(); + + UntypedResultSet meter = SystemKeyspace.readSSTableActivity(store.keyspace.getName(), store.name, sstable.descriptor.id); + assertFalse(meter.isEmpty()); + + Util.getAll(Util.cmd(store, key).includeRow("0").build()); + assertEquals(3, sstable.getReadMeter().count()); + + // After cleaning existing state and disabling persistence, there should be no meter state to read. + SystemKeyspace.clearSSTableReadMeter(store.keyspace.getName(), store.name, sstable.descriptor.id); + DatabaseDescriptor.setSStableReadRatePersistenceEnabled(false); + sstable.maybePersistSSTableReadMeter(); + meter = SystemKeyspace.readSSTableActivity(store.keyspace.getName(), store.name, sstable.descriptor.id); + assertTrue(meter.isEmpty()); + } + finally + { + DatabaseDescriptor.setSStableReadRatePersistenceEnabled(startState); + } } @Test @@ -432,7 +462,7 @@ public class SSTableReaderTest assert target.first.equals(firstKey); assert target.last.equals(lastKey); - executeInternal(String.format("ALTER TABLE \"%s\".\"%s\" WITH bloom_filter_fp_chance = 0.3", ks, cf)); + executeInternal(format("ALTER TABLE \"%s\".\"%s\" WITH bloom_filter_fp_chance = 0.3", ks, cf)); File summaryFile = new File(desc.filenameFor(Component.SUMMARY)); Path bloomPath = new File(desc.filenameFor(Component.FILTER)).toPath(); @@ -613,9 +643,9 @@ public class SSTableReaderTest final int NUM_PARTITIONS = 512; for (int j = 0; j < NUM_PARTITIONS; j++) { - new RowUpdateBuilder(store.metadata(), j, String.format("%3d", j)) + new RowUpdateBuilder(store.metadata(), j, format("%3d", j)) .clustering("0") - .add("val", String.format("%3d", j)) + .add("val", format("%3d", j)) .build() .applyUnsafe(); @@ -631,7 +661,7 @@ public class SSTableReaderTest List<Future<?>> futures = new ArrayList<>(NUM_PARTITIONS * 2); for (int i = 0; i < NUM_PARTITIONS; i++) { - final ByteBuffer key = ByteBufferUtil.bytes(String.format("%3d", i)); + final ByteBuffer key = ByteBufferUtil.bytes(format("%3d", i)); final int index = i; futures.add(executor.submit(new Runnable() @@ -639,7 +669,7 @@ public class SSTableReaderTest public void run() { Row row = Util.getOnlyRowUnfiltered(Util.cmd(store, key).build()); - assertEquals(0, ByteBufferUtil.compare(String.format("%3d", index).getBytes(), row.cells().iterator().next().buffer())); + assertEquals(0, ByteBufferUtil.compare(format("%3d", index).getBytes(), row.cells().iterator().next().buffer())); } })); @@ -690,9 +720,9 @@ public class SSTableReaderTest final int NUM_PARTITIONS = 512; for (int j = 0; j < NUM_PARTITIONS; j++) { - new RowUpdateBuilder(store.metadata(), j, String.format("%3d", j)) + new RowUpdateBuilder(store.metadata(), j, format("%3d", j)) .clustering("0") - .add("val", String.format("%3d", j)) + .add("val", format("%3d", j)) .build() .applyUnsafe(); @@ -791,7 +821,7 @@ public class SSTableReaderTest { File f = new File(notLiveDesc.filenameFor(c)); assertTrue(f.exists()); - assertTrue(f.toString().contains(String.format("-%s-", id))); + assertTrue(f.toString().contains(format("-%s-", id))); f.deleteOnExit(); assertFalse(new File(sstable.descriptor.filenameFor(c)).exists()); } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org