This is an automated email from the ASF dual-hosted git repository.
jchovatia 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 a06df099f4 No need to evict already prepared statements, as it creates
a race condition between multiple threads
a06df099f4 is described below
commit a06df099f4e1c6265d25c94336c493aded3aa644
Author: Jaydeepkumar Chovatia <[email protected]>
AuthorDate: Sun Jan 21 12:44:56 2024 -0800
No need to evict already prepared statements, as it creates a race
condition between multiple threads
patch by Jaydeepkumar Chovatia; reviewed by Alex Petrov for CASSANDRA-17401
---
CHANGES.txt | 1 +
.../org/apache/cassandra/cql3/QueryProcessor.java | 7 --
.../miscellaneous/PreparedStatementTest.java | 85 ++++++++++++++++++++++
3 files changed, 86 insertions(+), 7 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index c748e17c1f..e78d5bfd6e 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
5.1
+ * No need to evict already prepared statements, as it creates a race
condition between multiple threads (CASSANDRA-17401)
* Include Level information for UnifiedCompactionStrategy in nodetool
tablestats output (CASSANDRA-20820)
* Support low-overhead async profiling (CASSANDRA-20854)
* Minor perf optimizations around memtable put logic (CASSANDRA-21088)
diff --git a/src/java/org/apache/cassandra/cql3/QueryProcessor.java
b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
index 38a0f3545b..606da47305 100644
--- a/src/java/org/apache/cassandra/cql3/QueryProcessor.java
+++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
@@ -803,13 +803,6 @@ public class QueryProcessor implements QueryHandler
return createResultMessage(hashWithKeyspace,
cachedWithKeyspace);
}
}
- else
- {
- // Make sure the missing one is going to be eventually re-prepared
- evictPrepared(hashWithKeyspace);
- evictPrepared(hashWithoutKeyspace);
- }
-
Prepared prepared = parseAndPrepare(queryString, clientState, false);
CQLStatement statement = prepared.statement;
diff --git
a/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/PreparedStatementTest.java
b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/PreparedStatementTest.java
new file mode 100644
index 0000000000..a0bebed43c
--- /dev/null
+++
b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/PreparedStatementTest.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.validation.miscellaneous;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.QueryProcessor;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.transport.messages.ResultMessage;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class PreparedStatementTest extends CQLTester
+{
+ private static final int NUM_THREADS = 50;
+ private final CountDownLatch startLatch = new CountDownLatch(1);
+ private final CountDownLatch finishLatch = new CountDownLatch(NUM_THREADS);
+
+ @Test
+ public void testPreparedStatementStaysInCache() throws Throwable
+ {
+ execute("CREATE TABLE " + KEYSPACE + ".test_fullyqualified(a int
primary key, b int)");
+
+ ClientState state = ClientState.forInternalCalls();
+ Assert.assertEquals(0,
QueryProcessor.instance.getPreparedStatements().size());
+ final ResultMessage.Prepared[] preparedSelect = new
ResultMessage.Prepared[NUM_THREADS];
+ AtomicBoolean preparedStatementPresentInCache = new
AtomicBoolean(true);
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ int threadId = i;
+ Thread thread = new Thread(() -> {
+ try
+ {
+ // Wait until the start signal is given
+ startLatch.await();
+
+ // Code to be executed in each thread
+ preparedSelect[threadId] = QueryProcessor.instance.prepare(
+ String.format("SELECT b FROM %s.test_fullyqualified where
a = 10", KEYSPACE), state);
+ Assert.assertNotNull(preparedSelect[threadId].statementId);
+
if(!QueryProcessor.instance.getPreparedStatements().containsKey(preparedSelect[threadId].statementId))
+ {
+ preparedStatementPresentInCache.set(false);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ finally
+ {
+ // Signal that this thread has finished
+ finishLatch.countDown();
+ }
+ Assert.fail();
+ });
+ thread.start();
+ }
+
+ // Signal all threads to start
+ startLatch.countDown();
+
+ // Wait for all threads to finish
+ finishLatch.await();
+ Assert.assertTrue(preparedStatementPresentInCache.get());
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]