mirror of https://github.com/apache/cassandra
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_cai@apple.com> Co-Authored-By: Michael Kjellman <kjellman@apple.com>
This commit is contained in:
parent
6cf352ea9c
commit
da95e4b3fb
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -485,6 +485,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()}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue