Skip to content

Commit ed00bf9

Browse files
committed
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
1 parent b4f6c7c commit ed00bf9

File tree

6 files changed

+51
-18
lines changed

6 files changed

+51
-18
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
5.1
2+
* Minor improvements and hardening for IndexHints (CASSANDRA-20888)
23
* Stop repair scheduler if two major versions are detected (CASSANDRA-20048)
34
* Optimize audit logic for batch operations especially when audit is not enabled for DML (CASSANDRA-20885)
45
* Implement nodetool history (CASSANDRA-20851)

src/java/org/apache/cassandra/config/DatabaseDescriptor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5906,6 +5906,11 @@ public static int getSaiSSTableIndexesPerQueryFailThreshold()
59065906
return conf.sai_sstable_indexes_per_query_fail_threshold;
59075907
}
59085908

5909+
public static int getSecondaryIndexesPerTableFailThreshold()
5910+
{
5911+
return conf.secondary_indexes_per_table_fail_threshold;
5912+
}
5913+
59095914
@VisibleForTesting
59105915
public static void setTriggersPolicy(Config.TriggersPolicy policy)
59115916
{

src/java/org/apache/cassandra/cql3/restrictions/MergedRestriction.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,12 @@ public boolean needsFiltering(Index.Group indexGroup, IndexHints indexHints)
282282
{
283283
// multiple contains might require filtering on some indexes, since that is equivalent to a disjunction (or)
284284
boolean hasMultipleContains = containsCount > 1;
285-
Set<Index> nonExcluded = indexHints.nonExcluded(indexGroup.getIndexes());
286285

287-
for (Index index : nonExcluded)
286+
for (Index index : indexGroup.getIndexes())
288287
{
288+
if (indexHints.excludes(index))
289+
continue;
290+
289291
if (isSupportedBy(index) && !(hasMultipleContains && index.filtersMultipleContains()))
290292
return false;
291293
}

src/java/org/apache/cassandra/cql3/restrictions/SimpleRestriction.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.util.ArrayList;
2323
import java.util.Collections;
2424
import java.util.List;
25-
import java.util.Set;
2625
import java.util.stream.Collectors;
2726

2827
import com.google.common.collect.RangeSet;
@@ -172,7 +171,7 @@ public void addFunctionsTo(List<Function> functions)
172171
@Override
173172
public boolean needsFiltering(Index.Group indexGroup, IndexHints indexHints)
174173
{
175-
Set<Index> nonExcluded = indexHints.nonExcluded(indexGroup.getIndexes());
174+
Iterable<Index> nonExcluded = indexHints.nonExcluded(indexGroup.getIndexes());
176175
for (ColumnMetadata column : columns())
177176
{
178177
if (!isSupportedBy(nonExcluded, column))

src/java/org/apache/cassandra/db/filter/IndexHints.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.google.common.collect.Iterables;
3333
import com.google.common.collect.Sets;
3434

35+
import org.apache.cassandra.config.DatabaseDescriptor;
3536
import org.apache.cassandra.cql3.QualifiedName;
3637
import org.apache.cassandra.db.TypeSizes;
3738
import org.apache.cassandra.exceptions.InvalidRequestException;
@@ -44,6 +45,7 @@
4445
import org.apache.cassandra.schema.IndexMetadata;
4546
import org.apache.cassandra.schema.TableMetadata;
4647
import org.apache.cassandra.utils.FBUtilities;
48+
import org.apache.cassandra.utils.vint.VIntCoding;
4749

4850
import static java.lang.String.format;
4951

@@ -57,7 +59,7 @@ public class IndexHints
5759
public static final String WRONG_KEYSPACE_ERROR = "Index %s is not in the same keyspace as the queried table.";
5860
public static final String MISSING_INDEX_ERROR = "Table %s doesn't have an index named %s";
5961
public static final String NON_INCLUDABLE_INDEXES_ERROR = "It's not possible to use all the specified included indexes with this query.";
60-
public static final String TOO_MANY_INDEXES_ERROR = format("Cannot have more than %d included/excluded indexes, found ", Short.MAX_VALUE);
62+
public static final String TOO_MANY_INDEXES_ERROR = "Cannot have more than 'secondary_indexes_per_table_fail_threshold' included/excluded indexes, found ";
6163

6264
public static final IndexHints NONE = new IndexHints(Collections.emptySet(), Collections.emptySet())
6365
{
@@ -169,8 +171,11 @@ public boolean excludes(String indexName)
169171
* @param indexes a set of indexes
170172
* @return the indexes that are not excluded by these hints
171173
*/
172-
public <T extends Index> Set<T> nonExcluded(Iterable<T> indexes)
174+
public <T extends Index> Iterable<T> nonExcluded(Iterable<T> indexes)
173175
{
176+
if (excluded.isEmpty())
177+
return indexes;
178+
174179
Set<T> result = new HashSet<>();
175180
for (T index : indexes)
176181
{
@@ -370,10 +375,10 @@ public static IndexHints fromCQLNames(Set<QualifiedName> included,
370375
TableMetadata table,
371376
IndexRegistry indexRegistry)
372377
{
373-
if (included != null && included.size() > Short.MAX_VALUE)
378+
if (included != null && included.size() > maxIncludedOrExcludedIndexCount())
374379
throw new InvalidRequestException(TOO_MANY_INDEXES_ERROR + included.size());
375380

376-
if (excluded != null && excluded.size() > Short.MAX_VALUE)
381+
if (excluded != null && excluded.size() > maxIncludedOrExcludedIndexCount())
377382
throw new InvalidRequestException(TOO_MANY_INDEXES_ERROR + excluded.size());
378383

379384
IndexHints hints = IndexHints.create(fetchIndexes(included, table, indexRegistry),
@@ -399,6 +404,14 @@ public static IndexHints fromCQLNames(Set<QualifiedName> included,
399404
return hints;
400405
}
401406

407+
private static int maxIncludedOrExcludedIndexCount()
408+
{
409+
int guardrail = DatabaseDescriptor.getSecondaryIndexesPerTableFailThreshold();
410+
411+
// If no guardrail is configured, use a value that safely fits in a single byte for serialization:
412+
return guardrail > 0 ? guardrail : 128;
413+
}
414+
402415
private static Set<IndexMetadata> fetchIndexes(Set<QualifiedName> indexNames, TableMetadata table, IndexRegistry indexRegistry)
403416
{
404417
if (indexNames == null || indexNames.isEmpty())
@@ -573,16 +586,16 @@ private void serialize(Set<IndexMetadata> indexes, DataOutputPlus out, int versi
573586
return;
574587

575588
int n = indexes.size();
576-
assert n < Short.MAX_VALUE : TOO_MANY_INDEXES_ERROR + n;
589+
assert n < maxIncludedOrExcludedIndexCount() : TOO_MANY_INDEXES_ERROR + n;
577590

578-
out.writeShort(n);
591+
out.writeVInt32(n);
579592
for (IndexMetadata index : indexes)
580593
IndexMetadata.serializer.serialize(index, out, version);
581594
}
582595

583596
private Set<IndexMetadata> deserialize(DataInputPlus in, int version, TableMetadata table) throws IOException
584597
{
585-
short n = in.readShort();
598+
int n = in.readVInt32();
586599
Set<IndexMetadata> indexes = new HashSet<>(n);
587600
for (short i = 0; i < n; i++)
588601
{
@@ -597,7 +610,7 @@ private long serializedSize(Set<IndexMetadata> indexes, int version)
597610
if (indexes.isEmpty())
598611
return 0;
599612

600-
long size = TypeSizes.SHORT_SIZE;
613+
long size = VIntCoding.computeVIntSize(indexes.size());
601614
for (IndexMetadata index : indexes)
602615
size += IndexMetadata.serializer.serializedSize(index, version);
603616
return size;

src/java/org/apache/cassandra/net/MessagingService.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -788,13 +788,26 @@ public Set<InetAddressAndPort> endpointsWithConnectionsOnVersionBelow(int versio
788788
Set<InetAddressAndPort> nodes = new HashSet<>();
789789
for (InetAddressAndPort node : ClusterMetadata.current().directory.allAddresses())
790790
{
791-
ConnectionType.MESSAGING_TYPES.forEach(type -> {
792-
OutboundConnections connections = getOutbound(node, false);
793-
OutboundConnection connection = connections != null ? connections.connectionFor(type) : null;
794-
if (connection != null && connection.messagingVersion() < version)
795-
nodes.add(node);
796-
});
791+
if (hasConnectionWithVersionBelow(node, version))
792+
nodes.add(node);
797793
}
798794
return nodes;
799795
}
796+
797+
private boolean hasConnectionWithVersionBelow(InetAddressAndPort node, int version)
798+
{
799+
OutboundConnections connections = getOutbound(node, false);
800+
801+
if (connections == null)
802+
return false;
803+
804+
for (ConnectionType type : ConnectionType.MESSAGING_TYPES)
805+
{
806+
OutboundConnection connection = connections.connectionFor(type);
807+
if (connection != null && connection.messagingVersion() < version)
808+
return true;
809+
}
810+
811+
return false;
812+
}
800813
}

0 commit comments

Comments
 (0)