You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by dj...@apache.org on 2020/05/06 23:03:19 UTC

[cassandra] branch trunk updated: Add tunable initial size and growth factor to RangeTombstoneList

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 <yi...@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 <yi...@apple.com>
    Co-Authored-By: Michael Kjellman <kj...@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-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org