From 0c2eaa9cbb51f064b439c4d098adb5aa76b65b0f Mon Sep 17 00:00:00 2001 From: Benjamin Lerer Date: Wed, 21 Jan 2015 20:12:55 +0100 Subject: [PATCH] Duplicate rows returned when in clause has repeated values Patch by Benjamin Lerer, reviewed by Robert Stupp for CASSANDRA-6706 --- CHANGES.txt | 1 + .../cql3/statements/SelectStatement.java | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index f1eaa77bb3..9cd8189166 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 2.1.3 + * Duplicate rows returned when in clause has repeated values (CASSANDRA-6707) * Add tooling to detect hot partitions (CASSANDRA-7974) * Fix cassandra-stress user-mode truncation of partition generation (CASSANDRA-8608) * Only stream from unrepaired sstables during inc repair (CASSANDRA-8267) diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index 30259ddf24..633d43c18a 100644 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@ -65,6 +65,13 @@ public class SelectStatement implements CQLStatement private static final int DEFAULT_COUNT_PAGE_SIZE = 10000; + /** + * In the current version a query containing duplicate values in an IN restriction on the partition key will + * cause the same record to be returned multiple time. This behavior will be changed in 3.0 but until then + * we will log a warning the first time this problem occurs. + */ + private static volatile boolean HAS_LOGGED_WARNING_FOR_IN_RESTRICTION_WITH_DUPLICATES; + private final int boundTerms; public final CFMetaData cfm; public final Parameters parameters; @@ -588,6 +595,13 @@ public class SelectStatement implements CQLStatement if (builder.remainingCount() == 1) { + if (values.size() > 1 && !HAS_LOGGED_WARNING_FOR_IN_RESTRICTION_WITH_DUPLICATES && containsDuplicates(values)) + { + // This approach does not fully prevent race conditions but it is not a big deal. + HAS_LOGGED_WARNING_FOR_IN_RESTRICTION_WITH_DUPLICATES = true; + logger.warn("SELECT queries with IN restrictions on the partition key containing duplicate values will return duplicate rows."); + } + for (ByteBuffer val : values) { if (val == null) @@ -609,6 +623,17 @@ public class SelectStatement implements CQLStatement return keys; } + /** + * Checks if the specified list contains duplicate values. + * + * @param values the values to check + * @return true if the specified list contains duplicate values, false otherwise. + */ + private static boolean containsDuplicates(List values) + { + return new HashSet<>(values).size() < values.size(); + } + private ByteBuffer getKeyBound(Bound b, QueryOptions options) throws InvalidRequestException { // Deal with unrestricted partition key components (special-casing is required to deal with 2i queries on the first