-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CNDB-12425: A few reproduction tests and a preliminary patch, WIP #1529
base: main
Are you sure you want to change the base?
Conversation
…t include: - feature flag - checks we are on the new messaging version added for ANNOptions - we fall back to allow filtering only on Index Creation. Currently we also fall back to ALLOW FILTERING if we use nodetool to rebuild indexes
9b73538
to
e03373a
Compare
|
✔️ Build ds-cassandra-pr-gate/PR-1529 approved by ButlerApproved by Butler |
@@ -382,6 +396,17 @@ public boolean isIndexQueryable(Index index) | |||
return isIndexQueryable(index.getIndexMetadata().name); | |||
} | |||
|
|||
/** | |||
+ * Checks if the specified index is building. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting issue, I will fix it
@@ -77,7 +76,7 @@ public void tesConcurrencyFactor() | |||
// verify that a low concurrency factor is not capped by the max concurrency factor | |||
PartitionRangeReadCommand command = command(cfs, 50, 50); | |||
try (RangeCommandIterator partitions = RangeCommands.rangeCommandIterator(command, ONE, System.nanoTime(), ReadTracker.NOOP); | |||
ReplicaPlanIterator ranges = new ReplicaPlanIterator(command.dataRange().keyRange(), command.indexQueryPlan(), keyspace, ONE)) | |||
ReplicaPlanIterator ranges = new ReplicaPlanIterator(command.dataRange().keyRange(), command.indexQueryPlan(), keyspace, ONE, false)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be command.rowFilter().allowFiltering
searcher = indexSearcher(); | ||
Index index = indexQueryPlan.getFirst(); | ||
Tracing.trace("Executing read on {}.{} using index {}", cfs.metadata.keyspace, cfs.metadata.name, index.getIndexMetadata().name); | ||
if (cfs.indexManager.isQueryableThroughIndex(indexQueryPlan, rowFilter().allowFiltering)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Collapsed the two ifs, no need of nesting here
@@ -362,13 +365,24 @@ public synchronized Future<?> addIndex(IndexMetadata indexDef, boolean isNewCF) | |||
* @param queryPlan a query plan | |||
* @throws IndexNotAvailableException if the query plan has any index that is not queryable | |||
*/ | |||
public void checkQueryability(Index.QueryPlan queryPlan) | |||
public boolean isQueryableThroughIndex(Index.QueryPlan queryPlan, boolean allowsFiltering) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method can now return true or false, or throw an exception, and it also throws a client warning. That looks like too many side effects for a method starting with boolean is...
, which might suggest a simpler behaviour. I would either:
a) Split it into two simpler separate boolean methods to know if all the indexes in the plan are building/queryable, and let ReadCommand#executeLocally
do the AF check and throw exceptions and warnings.
b) Transform it into a SecondaryIndexManger#searcherFor(Index.QueryPlan, boolean)
method keeping most of it's responsibilities, returning the searcher if it's possible to build it, null if it's building, and exception if it's not queryable.
+ */ | ||
public boolean isIndexBuilding(Index index) | ||
{ | ||
return isIndexBuilding(index.getIndexMetadata().name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: double tab
+ * @param index the index | ||
+ * @return <code>true</code> if the specified index is building, <code>false</code> otherwise | ||
+ */ | ||
public boolean isIndexBuilding(Index index) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: can we put the two overloads of isIndexBuilding
together?
@@ -1814,13 +1839,16 @@ public static void shutdownAndWait(long timeout, TimeUnit units) throws Interrup | |||
* @param indexQueryPlan index query plan used in the read command | |||
* @param level consistency level of read command | |||
*/ | |||
public static <E extends Endpoints<E>> E filterForQuery(E liveEndpoints, Keyspace keyspace, Index.QueryPlan indexQueryPlan, ConsistencyLevel level) | |||
public static <E extends Endpoints<E>> E filterForQuery(E liveEndpoints, Keyspace keyspace, Index.QueryPlan indexQueryPlan, ConsistencyLevel level, boolean allowsFiltering) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: break the long line and add the new allowsFiltering
param to the method's JavaDoc.
@@ -723,11 +723,11 @@ public static ReplicaPlan.ForRangeRead forSingleReplicaRead(Keyspace keyspace, A | |||
* The candidate collection can be used for speculation, although at present | |||
* it would break EACH_QUORUM to do so without further filtering | |||
*/ | |||
public static ReplicaPlan.ForTokenRead forRead(Keyspace keyspace, Token token, Index.QueryPlan indexQueryPlan, ConsistencyLevel consistencyLevel, SpeculativeRetryPolicy retry) | |||
public static ReplicaPlan.ForTokenRead forRead(Keyspace keyspace, Token token, Index.QueryPlan indexQueryPlan, ConsistencyLevel consistencyLevel, SpeculativeRetryPolicy retry, boolean allowsFiltering) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: break the long line.
@@ -743,11 +743,11 @@ public static ReplicaPlan.ForTokenRead forRead(Keyspace keyspace, Token token, I | |||
* | |||
* There is no speculation for range read queries at present, so we never 'always speculate' here, and a failed response fails the query. | |||
*/ | |||
public static ReplicaPlan.ForRangeRead forRangeRead(Keyspace keyspace, Index.QueryPlan indexQueryPlan, ConsistencyLevel consistencyLevel, AbstractBounds<PartitionPosition> range, int vnodeCount) | |||
public static ReplicaPlan.ForRangeRead forRangeRead(Keyspace keyspace, Index.QueryPlan indexQueryPlan, ConsistencyLevel consistencyLevel, AbstractBounds<PartitionPosition> range, int vnodeCount, boolean allowsFiltering) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: break the long line.
|
||
private final FilterElement root; | ||
|
||
protected RowFilter(FilterElement root) | ||
public final boolean allowFiltering; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a mixed use of allowFiltering
and allowsFiltering
around. I would homogenize it, so it's easier to search.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ALLOW FILTERING
has always been kind of a transversal concept while it was a CQL thing. Putting it in the RowFilter
somehow feels like it finally has a clear home. I think it would be super nice to add some brief JavaDoc here saying what ALLOW FILTERING
is, for the sake of newcomers.
protected RowFilter(FilterElement root) | ||
public final boolean allowFiltering; | ||
|
||
protected RowFilter(FilterElement root, boolean allowFitlering) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: s/allowFitlering/allowFiltering
@@ -1836,19 +1841,22 @@ public void serialize(RowFilter filter, DataOutputPlus out, int version) throws | |||
{ | |||
out.writeBoolean(false); // Old "is for thrift" boolean | |||
FilterElement.serializer.serialize(filter.root, out, version); | |||
out.writeBoolean(filter.allowFiltering); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should depend on the messaging version
} | ||
|
||
public RowFilter deserialize(DataInputPlus in, int version, TableMetadata metadata) throws IOException | ||
{ | ||
in.readBoolean(); // Unused | ||
FilterElement operation = FilterElement.serializer.deserialize(in, version, metadata); | ||
return new RowFilter(operation); | ||
boolean allowFiltering = in.readBoolean(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should depend on the messaging version
} | ||
|
||
public long serializedSize(RowFilter filter, int version) | ||
{ | ||
return 1 // unused boolean | ||
+ FilterElement.serializer.serializedSize(filter.root, version); | ||
+ FilterElement.serializer.serializedSize(filter.root, version) | ||
+ 1; // for allowFiltering |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should depend on the messaging version. Also, it's probably better to use TypeSizes.BOOL_SIZE
} | ||
|
||
// Verify that all provided indexes belong to this group | ||
assert indexes.size() < indices.size() && indices.containsAll(saiIndexes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can simply add this to the loop above:
assert indices.contains(index) : "Index does not belong to this group";
* @return a new query plan for the specified {@link RowFilter} and {@link Index}, {@code null} otherwise | ||
*/ | ||
@Nullable | ||
QueryPlan queryPlanForIndices(RowFilter rowFilter, Set<Index> indexes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still thinking about how could make this the only method and get rid of queryPlanFor(RowFilter)
@@ -120,6 +120,25 @@ public Index.QueryPlan queryPlanFor(RowFilter rowFilter) | |||
return null; | |||
} | |||
|
|||
@Override | |||
public Index.QueryPlan queryPlanForIndices(RowFilter rowFilter, Set<Index> indexes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one looks like almost a duplicate of Index.QueryPlan queryPlanFor
, which kinds of reinforces the idea that we could have a single signature for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is wrong in my opinion. This class is about single index, we can never build plan of a subset which would be 0 indexes... I have it throwing unsupported in my next changes. But I agree we may want to combine into one method, though it may be a bit confusing and overloaded.
As I mentioned - the current state is draft with main functionality for feedback - the actual polishing is in the making :-)
What is the issue
...
Queries with ALLOW FILTERING are rejected while we have an index that can be used in the future for the same query, still building
What does this PR fix and why was it fixed
CNDB-12425: A preliminary patch to facilitate discussions. It does not include:
Checklist before you submit for review
NoSpamLogger
for log lines that may appear frequently in the logs