This is an automated email from the ASF dual-hosted git repository.

maedhroz 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 ed00bf9a93 Minor improvements and hardening for IndexHints - Enforce a 
more reasonable limit on the number of included/excluded indexes - Serialize 
vints rather than shorts in IndexSetSerializer - Return Iterable from 
notExcluded() to avoid set creation - Avoid redundant iteration in 
MessagingService#endpointsWithConnectionsOnVersionBelow()
ed00bf9a93 is described below

commit ed00bf9a931f50ac3396ad9bf40d4fabdbd938e0
Author: Caleb Rackliffe <calebrackli...@gmail.com>
AuthorDate: Fri Sep 5 14:24:15 2025 -0500

    Minor improvements and hardening for IndexHints
    - Enforce a more reasonable limit on the number of included/excluded indexes
    - Serialize vints rather than shorts in IndexSetSerializer
    - Return Iterable from notExcluded() to avoid set creation
    - Avoid redundant iteration in 
MessagingService#endpointsWithConnectionsOnVersionBelow()
    
    patch by Caleb Rackliffe; reviewed by Marcus Eriksson for CASSANDRA-20888
---
 CHANGES.txt                                        |  1 +
 .../cassandra/config/DatabaseDescriptor.java       |  5 ++++
 .../cql3/restrictions/MergedRestriction.java       |  6 +++--
 .../cql3/restrictions/SimpleRestriction.java       |  3 +--
 .../org/apache/cassandra/db/filter/IndexHints.java | 29 ++++++++++++++++------
 .../org/apache/cassandra/net/MessagingService.java | 25 ++++++++++++++-----
 6 files changed, 51 insertions(+), 18 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 8cbd1e173b..c09abf651d 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 5.1
+ * Minor improvements and hardening for IndexHints (CASSANDRA-20888)
  * Stop repair scheduler if two major versions are detected (CASSANDRA-20048)
  * Optimize audit logic for batch operations especially when audit is not 
enabled for DML (CASSANDRA-20885)
  * Implement nodetool history (CASSANDRA-20851)
diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java 
b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
index 5811cd3243..ec76193e10 100644
--- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
+++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
@@ -5906,6 +5906,11 @@ public class DatabaseDescriptor
         return conf.sai_sstable_indexes_per_query_fail_threshold;
     }
 
+    public static int getSecondaryIndexesPerTableFailThreshold()
+    {
+        return conf.secondary_indexes_per_table_fail_threshold;
+    }
+
     @VisibleForTesting
     public static void setTriggersPolicy(Config.TriggersPolicy policy)
     {
diff --git 
a/src/java/org/apache/cassandra/cql3/restrictions/MergedRestriction.java 
b/src/java/org/apache/cassandra/cql3/restrictions/MergedRestriction.java
index 587bb01ea1..bb352cb076 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/MergedRestriction.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/MergedRestriction.java
@@ -282,10 +282,12 @@ public final class MergedRestriction implements 
SingleRestriction
     {
         // multiple contains might require filtering on some indexes, since 
that is equivalent to a disjunction (or)
         boolean hasMultipleContains = containsCount > 1;
-        Set<Index> nonExcluded = 
indexHints.nonExcluded(indexGroup.getIndexes());
 
-        for (Index index : nonExcluded)
+        for (Index index : indexGroup.getIndexes())
         {
+            if (indexHints.excludes(index))
+                continue;
+
             if (isSupportedBy(index) && !(hasMultipleContains && 
index.filtersMultipleContains()))
                 return false;
         }
diff --git 
a/src/java/org/apache/cassandra/cql3/restrictions/SimpleRestriction.java 
b/src/java/org/apache/cassandra/cql3/restrictions/SimpleRestriction.java
index 85d75fb07f..5c41ef36cc 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/SimpleRestriction.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/SimpleRestriction.java
@@ -22,7 +22,6 @@ import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 import java.util.stream.Collectors;
 
 import com.google.common.collect.RangeSet;
@@ -172,7 +171,7 @@ public final class SimpleRestriction implements 
SingleRestriction
     @Override
     public boolean needsFiltering(Index.Group indexGroup, IndexHints 
indexHints)
     {
-        Set<Index> nonExcluded = 
indexHints.nonExcluded(indexGroup.getIndexes());
+        Iterable<Index> nonExcluded = 
indexHints.nonExcluded(indexGroup.getIndexes());
         for (ColumnMetadata column : columns())
         {
             if (!isSupportedBy(nonExcluded, column))
diff --git a/src/java/org/apache/cassandra/db/filter/IndexHints.java 
b/src/java/org/apache/cassandra/db/filter/IndexHints.java
index 4ca4f98fae..7deb84b001 100644
--- a/src/java/org/apache/cassandra/db/filter/IndexHints.java
+++ b/src/java/org/apache/cassandra/db/filter/IndexHints.java
@@ -32,6 +32,7 @@ import javax.annotation.Nullable;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 
+import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.cql3.QualifiedName;
 import org.apache.cassandra.db.TypeSizes;
 import org.apache.cassandra.exceptions.InvalidRequestException;
@@ -44,6 +45,7 @@ import org.apache.cassandra.net.MessagingService;
 import org.apache.cassandra.schema.IndexMetadata;
 import org.apache.cassandra.schema.TableMetadata;
 import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.vint.VIntCoding;
 
 import static java.lang.String.format;
 
@@ -57,7 +59,7 @@ public class IndexHints
     public static final String WRONG_KEYSPACE_ERROR = "Index %s is not in the 
same keyspace as the queried table.";
     public static final String MISSING_INDEX_ERROR = "Table %s doesn't have an 
index named %s";
     public static final String NON_INCLUDABLE_INDEXES_ERROR = "It's not 
possible to use all the specified included indexes with this query.";
-    public static final String TOO_MANY_INDEXES_ERROR = format("Cannot have 
more than %d included/excluded indexes, found ", Short.MAX_VALUE);
+    public static final String TOO_MANY_INDEXES_ERROR = "Cannot have more than 
'secondary_indexes_per_table_fail_threshold' included/excluded indexes, found ";
 
     public static final IndexHints NONE = new 
IndexHints(Collections.emptySet(), Collections.emptySet())
     {
@@ -169,8 +171,11 @@ public class IndexHints
      * @param indexes a set of indexes
      * @return the indexes that are not excluded by these hints
      */
-    public <T extends Index> Set<T> nonExcluded(Iterable<T> indexes)
+    public <T extends Index> Iterable<T> nonExcluded(Iterable<T> indexes)
     {
+        if (excluded.isEmpty())
+            return indexes;
+
         Set<T> result = new HashSet<>();
         for (T index : indexes)
         {
@@ -370,10 +375,10 @@ public class IndexHints
                                           TableMetadata table,
                                           IndexRegistry indexRegistry)
     {
-        if (included != null && included.size() > Short.MAX_VALUE)
+        if (included != null && included.size() > 
maxIncludedOrExcludedIndexCount())
             throw new InvalidRequestException(TOO_MANY_INDEXES_ERROR + 
included.size());
 
-        if (excluded != null && excluded.size() > Short.MAX_VALUE)
+        if (excluded != null && excluded.size() > 
maxIncludedOrExcludedIndexCount())
             throw new InvalidRequestException(TOO_MANY_INDEXES_ERROR + 
excluded.size());
 
         IndexHints hints = IndexHints.create(fetchIndexes(included, table, 
indexRegistry),
@@ -399,6 +404,14 @@ public class IndexHints
         return hints;
     }
 
+    private static int maxIncludedOrExcludedIndexCount()
+    {
+        int guardrail = 
DatabaseDescriptor.getSecondaryIndexesPerTableFailThreshold();
+
+        // If no guardrail is configured, use a value that safely fits in a 
single byte for serialization:
+        return guardrail > 0 ? guardrail : 128;
+    }
+
     private static Set<IndexMetadata> fetchIndexes(Set<QualifiedName> 
indexNames, TableMetadata table, IndexRegistry indexRegistry)
     {
         if (indexNames == null || indexNames.isEmpty())
@@ -573,16 +586,16 @@ public class IndexHints
                 return;
 
             int n = indexes.size();
-            assert n < Short.MAX_VALUE : TOO_MANY_INDEXES_ERROR + n;
+            assert n < maxIncludedOrExcludedIndexCount() : 
TOO_MANY_INDEXES_ERROR + n;
 
-            out.writeShort(n);
+            out.writeVInt32(n);
             for (IndexMetadata index : indexes)
                 IndexMetadata.serializer.serialize(index, out, version);
         }
 
         private Set<IndexMetadata> deserialize(DataInputPlus in, int version, 
TableMetadata table) throws IOException
         {
-            short n = in.readShort();
+            int n = in.readVInt32();
             Set<IndexMetadata> indexes = new HashSet<>(n);
             for (short i = 0; i < n; i++)
             {
@@ -597,7 +610,7 @@ public class IndexHints
             if (indexes.isEmpty())
                 return 0;
 
-            long size = TypeSizes.SHORT_SIZE;
+            long size = VIntCoding.computeVIntSize(indexes.size());
             for (IndexMetadata index : indexes)
                 size += IndexMetadata.serializer.serializedSize(index, 
version);
             return size;
diff --git a/src/java/org/apache/cassandra/net/MessagingService.java 
b/src/java/org/apache/cassandra/net/MessagingService.java
index eef34378ed..a636005bee 100644
--- a/src/java/org/apache/cassandra/net/MessagingService.java
+++ b/src/java/org/apache/cassandra/net/MessagingService.java
@@ -788,13 +788,26 @@ public class MessagingService extends 
MessagingServiceMBeanImpl implements Messa
         Set<InetAddressAndPort> nodes = new HashSet<>();
         for (InetAddressAndPort node : 
ClusterMetadata.current().directory.allAddresses())
         {
-            ConnectionType.MESSAGING_TYPES.forEach(type -> {
-                OutboundConnections connections = getOutbound(node, false);
-                OutboundConnection connection = connections != null ? 
connections.connectionFor(type) : null;
-                if (connection != null && connection.messagingVersion() < 
version)
-                    nodes.add(node);
-            });
+            if (hasConnectionWithVersionBelow(node, version))
+                nodes.add(node);
         }
         return nodes;
     }
+
+    private boolean hasConnectionWithVersionBelow(InetAddressAndPort node, int 
version)
+    {
+        OutboundConnections connections = getOutbound(node, false);
+
+        if (connections == null)
+            return false;
+
+        for (ConnectionType type : ConnectionType.MESSAGING_TYPES)
+        {
+            OutboundConnection connection = connections.connectionFor(type);
+            if (connection != null && connection.messagingVersion() < version)
+                return true;
+        }
+
+        return false;
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to