This is an automated email from the ASF dual-hosted git repository. djoshi 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 da95e4b Add tunable initial size and growth factor to RangeTombstoneList da95e4b is described below commit da95e4b3fb36294b5117846b8fbb8cdc01e427d5 Author: Yifan Cai <yifan_...@apple.com> AuthorDate: Tue Apr 28 13:51:15 2020 -0700 Add tunable initial size and growth factor to RangeTombstoneList Added `initial_range_tombstone_list_allocation_size` and `range_tombstone_list_growth_factor` in config, which can be altered via JMX. Patch By Michael Kjellman and Yifan Cai; Reviewed by Dinesh Joshi for CASSANDRA-15763 Co-Authored-By: Yifan Cai <yifan_...@apple.com> Co-Authored-By: Michael Kjellman <kjell...@apple.com> --- CHANGES.txt | 1 + src/java/org/apache/cassandra/config/Config.java | 9 +++ .../cassandra/config/DatabaseDescriptor.java | 19 +++++ .../apache/cassandra/db/MutableDeletionInfo.java | 5 +- .../apache/cassandra/db/RangeTombstoneList.java | 8 +- .../apache/cassandra/service/StorageService.java | 35 +++++++++ .../cassandra/service/StorageServiceMBean.java | 11 +++ .../cassandra/db/RangeTombstoneListTest.java | 91 +++++++++++++++++++++- 8 files changed, 172 insertions(+), 7 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 9b682b9..0c50b0a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.0-alpha5 + * Add tunable initial size and growth factor to RangeTombstoneList (CASSANDRA-15763) * Improve debug logging in SSTableReader for index summary (CASSANDRA-15755) * bin/sstableverify should support user provided token ranges (CASSANDRA-15753) * Improve logging when mutation passed to commit log is too large (CASSANDRA-14781) diff --git a/src/java/org/apache/cassandra/config/Config.java b/src/java/org/apache/cassandra/config/Config.java index 3525715..ed637b0 100644 --- a/src/java/org/apache/cassandra/config/Config.java +++ b/src/java/org/apache/cassandra/config/Config.java @@ -486,6 +486,15 @@ public class Config public volatile int validation_preview_purge_head_start_in_sec = 60 * 60; /** + * The intial capacity for creating RangeTombstoneList. + */ + public volatile int initial_range_tombstone_list_allocation_size = 1; + /** + * The growth factor to enlarge a RangeTombstoneList. + */ + public volatile double range_tombstone_list_growth_factor = 1.5; + + /** * @deprecated migrate to {@link DatabaseDescriptor#isClientInitialized()} */ @Deprecated diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index 698fb45..85a107f 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -3090,4 +3090,23 @@ public class DatabaseDescriptor return Math.max(seconds, 0); } + public static int getInitialRangeTombstoneListAllocationSize() + { + return conf.initial_range_tombstone_list_allocation_size; + } + + public static void setInitialRangeTombstoneListAllocationSize(int size) + { + conf.initial_range_tombstone_list_allocation_size = size; + } + + public static double getRangeTombstoneListGrowthFactor() + { + return conf.range_tombstone_list_growth_factor; + } + + public static void setRangeTombstoneListGrowthFactor(double resizeFactor) + { + conf.range_tombstone_list_growth_factor = resizeFactor; + } } diff --git a/src/java/org/apache/cassandra/db/MutableDeletionInfo.java b/src/java/org/apache/cassandra/db/MutableDeletionInfo.java index 39728c5..356d763 100644 --- a/src/java/org/apache/cassandra/db/MutableDeletionInfo.java +++ b/src/java/org/apache/cassandra/db/MutableDeletionInfo.java @@ -22,6 +22,7 @@ import java.util.Iterator; import com.google.common.base.Objects; +import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.db.rows.*; import org.apache.cassandra.db.rows.EncodingStats; import org.apache.cassandra.utils.ObjectSizes; @@ -113,8 +114,8 @@ public class MutableDeletionInfo implements DeletionInfo public void add(RangeTombstone tombstone, ClusteringComparator comparator) { - if (ranges == null) - ranges = new RangeTombstoneList(comparator, 1); + if (ranges == null) // Introduce getInitialRangeTombstoneAllocationSize + ranges = new RangeTombstoneList(comparator, DatabaseDescriptor.getInitialRangeTombstoneListAllocationSize()); ranges.add(tombstone); } diff --git a/src/java/org/apache/cassandra/db/RangeTombstoneList.java b/src/java/org/apache/cassandra/db/RangeTombstoneList.java index 401ff7b..7034d22 100644 --- a/src/java/org/apache/cassandra/db/RangeTombstoneList.java +++ b/src/java/org/apache/cassandra/db/RangeTombstoneList.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Iterator; +import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.utils.AbstractIterator; import com.google.common.collect.Iterators; @@ -667,7 +668,12 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable */ private void growToFree(int i) { - int newLength = (capacity() * 3) / 2 + 1; + // Introduce getRangeTombstoneResizeFactor + int newLength = (int) Math.ceil(capacity() * DatabaseDescriptor.getRangeTombstoneListGrowthFactor()); + // Fallback to the original calculation if the newLength calculated from the resize factor is not valid. + if (newLength <= capacity()) + newLength = ((capacity() * 3) / 2) + 1; + grow(i, newLength); } diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index 08f0612..c01665b 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -5415,6 +5415,41 @@ public class StorageService extends NotificationBroadcasterSupport implements IE logger.info("Updated batch_size_warn_threshold_in_kb to {}", threshold); } + public int getInitialRangeTombstoneListAllocationSize() + { + return DatabaseDescriptor.getInitialRangeTombstoneListAllocationSize(); + } + + public void setInitialRangeTombstoneListAllocationSize(int size) + { + if (size < 0 || size > 1024) + { + throw new IllegalStateException("Not updating initial_range_tombstone_allocation_size as it must be in the range [0, 1024] inclusive"); + } + int originalSize = DatabaseDescriptor.getInitialRangeTombstoneListAllocationSize(); + DatabaseDescriptor.setInitialRangeTombstoneListAllocationSize(size); + logger.info("Updated initial_range_tombstone_allocation_size from {} to {}", originalSize, size); + } + + public double getRangeTombstoneResizeListGrowthFactor() + { + return DatabaseDescriptor.getRangeTombstoneListGrowthFactor(); + } + + public void setRangeTombstoneListResizeGrowthFactor(double growthFactor) throws IllegalStateException + { + if (growthFactor < 1.2 || growthFactor > 5) + { + throw new IllegalStateException("Not updating range_tombstone_resize_factor as growth factor must be in the range [1.2, 5.0] inclusive"); + } + else + { + double originalGrowthFactor = DatabaseDescriptor.getRangeTombstoneListGrowthFactor(); + DatabaseDescriptor.setRangeTombstoneListGrowthFactor(growthFactor); + logger.info("Updated range_tombstone_resize_factor from {} to {}", originalGrowthFactor, growthFactor); + } + } + public void setHintedHandoffThrottleInKB(int throttleInKB) { DatabaseDescriptor.setHintedHandoffThrottleInKB(throttleInKB); diff --git a/src/java/org/apache/cassandra/service/StorageServiceMBean.java b/src/java/org/apache/cassandra/service/StorageServiceMBean.java index 74307fc..432b0bc 100644 --- a/src/java/org/apache/cassandra/service/StorageServiceMBean.java +++ b/src/java/org/apache/cassandra/service/StorageServiceMBean.java @@ -771,4 +771,15 @@ public interface StorageServiceMBean extends NotificationEmitter */ public void stopFullQueryLogger(); + /** Sets the initial allocation size of backing arrays for new RangeTombstoneList objects */ + public void setInitialRangeTombstoneListAllocationSize(int size); + + /** Returns the initial allocation size of backing arrays for new RangeTombstoneList objects */ + public int getInitialRangeTombstoneListAllocationSize(); + + /** Sets the resize factor to use when growing/resizing a RangeTombstoneList */ + public void setRangeTombstoneListResizeGrowthFactor(double growthFactor); + + /** Returns the resize factor to use when growing/resizing a RangeTombstoneList */ + public double getRangeTombstoneResizeListGrowthFactor(); } diff --git a/test/unit/org/apache/cassandra/db/RangeTombstoneListTest.java b/test/unit/org/apache/cassandra/db/RangeTombstoneListTest.java index d3dc835..d4f7e59 100644 --- a/test/unit/org/apache/cassandra/db/RangeTombstoneListTest.java +++ b/test/unit/org/apache/cassandra/db/RangeTombstoneListTest.java @@ -19,22 +19,39 @@ package org.apache.cassandra.db; import java.nio.ByteBuffer; -import java.util.*; -import java.util.regex.Pattern; +import java.util.Iterator; +import java.util.Random; +import java.util.function.Consumer; import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.google.common.base.Joiner; - +import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.*; +import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.db.marshal.Int32Type; +import org.apache.cassandra.distributed.impl.IsolatedExecutor; +import org.apache.cassandra.service.StorageService; import org.apache.cassandra.utils.ByteBufferUtil; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + public class RangeTombstoneListTest { private static final ClusteringComparator cmp = new ClusteringComparator(Int32Type.instance); + @BeforeClass + public static void beforeClass() + { + // Needed to initialize initial_range_tombstone_allocation_size and range_tombstone_resize_factor + DatabaseDescriptor.daemonInitialization(); + } + @Test public void sortedAdditionTest() { @@ -539,6 +556,72 @@ public class RangeTombstoneListTest assertEquals(6, l.searchDeletionTime(clustering(1000)).markedForDeleteAt()); } + @Test + public void testSetResizeFactor() + { + double original = DatabaseDescriptor.getRangeTombstoneListGrowthFactor(); + final StorageService storageService = StorageService.instance; + final Consumer<Throwable> expectIllegalStateExceptio = exception -> { + assertSame(IllegalStateException.class, exception.getClass()); + assertEquals("Not updating range_tombstone_resize_factor as growth factor must be in the range [1.2, 5.0] inclusive" , exception.getMessage()); + }; + try + { + // prevent bad ones + assertHasException(() -> storageService.setRangeTombstoneListResizeGrowthFactor(-1), expectIllegalStateExceptio); + assertHasException(() -> storageService.setRangeTombstoneListResizeGrowthFactor(0), expectIllegalStateExceptio); + assertHasException(() -> storageService.setRangeTombstoneListResizeGrowthFactor(1.1), expectIllegalStateExceptio); + assertHasException(() -> storageService.setRangeTombstoneListResizeGrowthFactor(5.1), expectIllegalStateExceptio); + + // accept good ones + storageService.setRangeTombstoneListResizeGrowthFactor(1.2); + storageService.setRangeTombstoneListResizeGrowthFactor(2.0); + storageService.setRangeTombstoneListResizeGrowthFactor(5.0); + } + finally + { + storageService.setRangeTombstoneListResizeGrowthFactor(original); + } + } + + @Test + public void testSetInitialAllocationSize() + { + int original = DatabaseDescriptor.getInitialRangeTombstoneListAllocationSize(); + final StorageService storageService = StorageService.instance; + final Consumer<Throwable> expectIllegalStateExceptio = exception -> { + assertSame(String.format("The actual exception message:<%s>", exception.getMessage()), IllegalStateException.class, exception.getClass()); + assertEquals("Not updating initial_range_tombstone_allocation_size as it must be in the range [0, 1024] inclusive" , exception.getMessage()); + }; + try + { + // prevent bad ones + assertHasException(() -> storageService.setInitialRangeTombstoneListAllocationSize(-1), expectIllegalStateExceptio); + assertHasException(() -> storageService.setInitialRangeTombstoneListAllocationSize(1025), expectIllegalStateExceptio); + + // accept good ones + storageService.setInitialRangeTombstoneListAllocationSize(1); + storageService.setInitialRangeTombstoneListAllocationSize(1024); + } + finally + { + storageService.setInitialRangeTombstoneListAllocationSize(original); + } + } + + private void assertHasException(IsolatedExecutor.ThrowingRunnable block, Consumer<Throwable> verifier) + { + try + { + block.run(); + fail("Expect the code block to throw but not"); + } + catch (Throwable throwable) + { + verifier.accept(throwable); + } + } + private static void assertRT(RangeTombstone expected, RangeTombstone actual) { assertTrue(String.format("%s != %s", toString(expected), toString(actual)), cmp.compare(expected.deletedSlice().start(), actual.deletedSlice().start()) == 0); --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org