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 <[email protected]>
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 <[email protected]>
Co-authored-by: Josh McKenzie <[email protected]>
---
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: [email protected]
For additional commands, e-mail: [email protected]