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

frankgh pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-analytics.git


The following commit(s) were added to refs/heads/trunk by this push:
     new b31a451  CASSANDRA-19727: Bulk writer fails validation stage when 
writing to a cluster using RandomPartitioner (#61)
b31a451 is described below

commit b31a451873eb411788a6d94c3cacf881f5c3cb86
Author: Francisco Guerrero <[email protected]>
AuthorDate: Thu Jun 27 15:51:15 2024 -0700

    CASSANDRA-19727: Bulk writer fails validation stage when writing to a 
cluster using RandomPartitioner (#61)
    
    
    Patch by Francisco Guerrero; Reviewed by Yifan Cai for CASSANDRA-19727
---
 CHANGES.txt                                        |  1 +
 .../spark/bulkwriter/SortedSSTableWriter.java      | 12 +++++-
 .../distributed/impl/CassandraCluster.java         | 26 ++++++++++---
 .../testing/ClusterBuilderConfiguration.java       | 13 +++++++
 .../cassandra/testing/TestTokenSupplier.java       | 45 +++++++++++++++++-----
 ...Test.java => CassandraAnalyticsSimpleTest.java} |  5 ++-
 .../cassandra/analytics/RandomPartitionerTest.java | 40 +++++++++++++++++++
 7 files changed, 125 insertions(+), 17 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 2e654ef..614fb8e 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 1.0.0
+ * Bulk writer fails validation stage when writing to a cluster using 
RandomPartitioner (CASSANDRA-19727)
  * Invalid mapping when timestamp is used as a partition key during bulk 
writes (CASSANDRA-19716)
  * NullPointerException when reading static column with null values 
(CASSANDRA-19626)
  * Integrate with the latest sidecar client (CASSANDRA-19616)
diff --git 
a/cassandra-analytics-core/src/main/java/org/apache/cassandra/spark/bulkwriter/SortedSSTableWriter.java
 
b/cassandra-analytics-core/src/main/java/org/apache/cassandra/spark/bulkwriter/SortedSSTableWriter.java
index 839beef..ea2cfc1 100644
--- 
a/cassandra-analytics-core/src/main/java/org/apache/cassandra/spark/bulkwriter/SortedSSTableWriter.java
+++ 
b/cassandra-analytics-core/src/main/java/org/apache/cassandra/spark/bulkwriter/SortedSSTableWriter.java
@@ -42,6 +42,7 @@ import org.apache.cassandra.spark.common.Digest;
 import org.apache.cassandra.spark.common.SSTables;
 import org.apache.cassandra.spark.data.DataLayer;
 import org.apache.cassandra.spark.data.LocalDataLayer;
+import org.apache.cassandra.spark.data.partitioner.Partitioner;
 import org.apache.cassandra.spark.reader.Rid;
 import org.apache.cassandra.spark.reader.StreamScanner;
 import org.apache.cassandra.spark.utils.DigestAlgorithm;
@@ -181,9 +182,18 @@ public class SortedSSTableWriter
             CassandraVersion version = 
CassandraBridgeFactory.getCassandraVersion(writerContext.cluster().getLowestCassandraVersion());
             String keyspace = 
writerContext.job().qualifiedTableName().keyspace();
             String schema = 
writerContext.schema().getTableSchema().createStatement;
+            Partitioner partitioner = writerContext.cluster().getPartitioner();
             Set<String> udtStatements = 
writerContext.schema().getUserDefinedTypeStatements();
             String directory = getOutDir().toString();
-            DataLayer layer = new LocalDataLayer(version, keyspace, schema, 
udtStatements, directory);
+            DataLayer layer = new LocalDataLayer(version,
+                                                 partitioner,
+                                                 keyspace,
+                                                 schema,
+                                                 udtStatements,
+                                                 Collections.emptyList() /* 
requestedFeatures */,
+                                                 false /* 
useSSTableInputStream */,
+                                                 null /* statsClass */,
+                                                 directory);
             try (StreamScanner<Rid> scanner = 
layer.openCompactionScanner(partitionId, Collections.emptyList(), null))
             {
                 while (scanner.hasNext())
diff --git 
a/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/distributed/impl/CassandraCluster.java
 
b/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/distributed/impl/CassandraCluster.java
index 09c5e47..dcb6364 100644
--- 
a/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/distributed/impl/CassandraCluster.java
+++ 
b/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/distributed/impl/CassandraCluster.java
@@ -43,6 +43,7 @@ import org.apache.cassandra.distributed.api.IMessageSink;
 import org.apache.cassandra.distributed.api.TokenSupplier;
 import org.apache.cassandra.distributed.shared.ClusterUtils;
 import org.apache.cassandra.distributed.shared.Versions;
+import org.apache.cassandra.sidecar.adapters.base.Partitioner;
 import org.apache.cassandra.testing.ClusterBuilderConfiguration;
 import org.apache.cassandra.testing.IClusterExtension;
 import org.apache.cassandra.testing.TestTokenSupplier;
@@ -92,16 +93,31 @@ public class CassandraCluster<I extends IInstance> 
implements IClusterExtension<
         int originalNodeCount = nodesPerDc * dcCount;
         int finalNodeCount = dcCount * (nodesPerDc + newNodesPerDc);
 
-        TokenSupplier tokenSupplier = 
TestTokenSupplier.evenlyDistributedTokens(nodesPerDc, newNodesPerDc, dcCount, 
1);
-
         UpgradeableCluster.Builder clusterBuilder = 
UpgradeableCluster.build(originalNodeCount);
         clusterBuilder.withVersion(requestedVersion)
                       
.withDynamicPortAllocation(configuration.dynamicPortAllocation) // to allow 
parallel test runs
                       
.withSharedClasses(EXTRA.or(clusterBuilder.getSharedClasses()))
                       .withDCs(dcCount)
-                      .withDataDirCount(configuration.numDataDirsPerInstance)
-                      .withConfig(config -> 
configuration.features.forEach(config::with))
-                      .withTokenSupplier(tokenSupplier);
+                      .withDataDirCount(configuration.numDataDirsPerInstance);
+
+        TokenSupplier tokenSupplier;
+        Consumer<IInstanceConfig> instanceConfigUpdater;
+        if (configuration.partitioner != null)
+        {
+            tokenSupplier = 
TestTokenSupplier.evenlyDistributedTokens(Partitioner.fromClassName(configuration.partitioner),
+                                                                      
nodesPerDc, newNodesPerDc, dcCount, 1);
+            instanceConfigUpdater = instanceConfig -> {
+                instanceConfig.set("partitioner", configuration.partitioner);
+                configuration.features.forEach(instanceConfig::with);
+            };
+        }
+        else
+        {
+            tokenSupplier = 
TestTokenSupplier.evenlyDistributedTokens(nodesPerDc, newNodesPerDc, dcCount, 
1);
+            instanceConfigUpdater = config -> 
configuration.features.forEach(config::with);
+        }
+        clusterBuilder.withTokenSupplier(tokenSupplier)
+                      .withConfig(instanceConfigUpdater);
 
         if (dcCount > 1)
         {
diff --git 
a/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/testing/ClusterBuilderConfiguration.java
 
b/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/testing/ClusterBuilderConfiguration.java
index 91ff516..8759e3c 100644
--- 
a/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/testing/ClusterBuilderConfiguration.java
+++ 
b/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/testing/ClusterBuilderConfiguration.java
@@ -38,6 +38,7 @@ public class ClusterBuilderConfiguration
     public boolean dynamicPortAllocation = true;
     public final EnumSet<Feature> features = EnumSet.of(Feature.GOSSIP, 
Feature.JMX, Feature.NATIVE_PROTOCOL);
     public BiConsumer<ClassLoader, Integer> instanceInitializer = null;
+    public String partitioner;
 
     /**
      * Adds a features to the list of default features.
@@ -136,4 +137,16 @@ public class ClusterBuilderConfiguration
         this.dynamicPortAllocation = dynamicPortAllocation;
         return this;
     }
+
+    /**
+     * Sets the {@code partitioner} and returns a reference to this Builder 
enabling method chaining.
+     *
+     * @param partitioner the {@code partitioner} to set
+     * @return a reference to this Builder
+     */
+    public ClusterBuilderConfiguration partitioner(String partitioner)
+    {
+        this.partitioner = partitioner;
+        return this;
+    }
 }
diff --git 
a/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/testing/TestTokenSupplier.java
 
b/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/testing/TestTokenSupplier.java
index 28e8e4f..4268904 100644
--- 
a/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/testing/TestTokenSupplier.java
+++ 
b/cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/testing/TestTokenSupplier.java
@@ -20,9 +20,11 @@ package org.apache.cassandra.testing;
 
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.cassandra.distributed.api.TokenSupplier;
+import org.apache.cassandra.sidecar.adapters.base.Partitioner;
 
 /**
  * Static factory holder that provides a token supplier
@@ -38,7 +40,8 @@ public class TestTokenSupplier
     /**
      * Tokens are allocation used in tests to simulate token allocation nodes 
for an approx even distribution
      * in a multiDC environment with neighboring nodes different DCs allocated 
adjacent tokens.
-     * Allocations for new nodes are interleaved among existing tokens.
+     * Allocations for new nodes are interleaved among existing tokens. Usings 
the Murmur3 Partitioner to allocate
+     * tokens.
      *
      * @param numNodesPerDC    number of nodes from a single DC
      * @param newNodesPerDC    number of additional nodes for a DC
@@ -47,14 +50,38 @@ public class TestTokenSupplier
      * @return The token supplier that vends the tokens
      */
     public static TokenSupplier evenlyDistributedTokens(int numNodesPerDC, int 
newNodesPerDC, int numDcs, int numTokensPerNode)
+    {
+        return evenlyDistributedTokens(Partitioner.Murmur3, numNodesPerDC, 
newNodesPerDC, numDcs, numTokensPerNode);
+    }
+
+    /**
+     * Tokens are allocation used in tests to simulate token allocation nodes 
for an approx even distribution
+     * in a multiDC environment with neighboring nodes different DCs allocated 
adjacent tokens.
+     * Allocations for new nodes are interleaved among existing tokens.
+     *
+     * @param partitioner      the partitioner to use for token allocation
+     * @param numNodesPerDC    number of nodes from a single DC
+     * @param newNodesPerDC    number of additional nodes for a DC
+     * @param numDcs           no. of datacenters
+     * @param numTokensPerNode no. tokens allocated to each node (this is 
always 1 if there are no vnodes)
+     * @return The token supplier that vends the tokens
+     */
+    public static TokenSupplier evenlyDistributedTokens(Partitioner 
partitioner,
+                                                        int numNodesPerDC,
+                                                        int newNodesPerDC,
+                                                        int numDcs,
+                                                        int numTokensPerNode)
     {
         // Use token count using initial node count to first assign tokens to 
nodes
         long totalTokens = (long) (numNodesPerDC) * numDcs * numTokensPerNode;
         // Similar to Cassandra TokenSupplier, the increment is doubled to 
account for all tokens from MIN - MAX.
         // For multi-DC, since neighboring nodes from different DCs have 
consecutive tokens, the increment is
         // broadened by a factor of numDcs.
-        BigInteger increment = BigInteger.valueOf(((Long.MAX_VALUE / 
(totalTokens + 2)) * 2 * numDcs));
-        List<String>[] tokens = allocateExistingNodeTokens(numNodesPerDC,
+        BigInteger increment = 
partitioner.maxToken.subtract(partitioner.minToken.add(BigInteger.ONE))
+                                                   
.multiply(BigInteger.valueOf(numDcs))
+                                                   
.divide(BigInteger.valueOf(totalTokens + 2));
+        List<String>[] tokens = allocateExistingNodeTokens(partitioner,
+                                                           numNodesPerDC,
                                                            newNodesPerDC,
                                                            numDcs,
                                                            numTokensPerNode,
@@ -62,7 +89,7 @@ public class TestTokenSupplier
 
 
         // Initial value of the first new node
-        BigInteger value  = new BigInteger(tokens[(numDcs - 1)].get(0));
+        BigInteger value = new BigInteger(tokens[(numDcs - 1)].get(0));
         BigInteger subIncrement = increment.divide(BigInteger.valueOf(2));
 
         int nodeId = (int) totalTokens + 1;
@@ -84,19 +111,17 @@ public class TestTokenSupplier
         return (nodeIdx) -> tokens[nodeIdx - 1];
     }
 
-    private static List<String>[] allocateExistingNodeTokens(int numNodesPerDC,
+    private static List<String>[] allocateExistingNodeTokens(Partitioner 
partitioner,
+                                                             int numNodesPerDC,
                                                              int newNodesPerDC,
                                                              int numDcs,
                                                              int 
numTokensPerNode,
                                                              BigInteger 
increment)
     {
         List<String>[] tokens = new List[(numNodesPerDC + newNodesPerDC) * 
numDcs];
-        for (int i = 0; i < ((numNodesPerDC + newNodesPerDC) * numDcs); ++i)
-        {
-            tokens[i] = new ArrayList(numTokensPerNode);
-        }
+        Arrays.setAll(tokens, ignored -> new ArrayList<>(numTokensPerNode));
 
-        BigInteger value = BigInteger.valueOf(Long.MIN_VALUE + 1);
+        BigInteger value = partitioner.minToken.add(BigInteger.ONE);
 
         int nodeId = 1;
         for (int i = 0; i < numTokensPerNode; ++i)
diff --git 
a/cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/SparkBulkWriterSimpleTest.java
 
b/cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/CassandraAnalyticsSimpleTest.java
similarity index 96%
rename from 
cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/SparkBulkWriterSimpleTest.java
rename to 
cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/CassandraAnalyticsSimpleTest.java
index 3c7f156..fa94401 100644
--- 
a/cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/SparkBulkWriterSimpleTest.java
+++ 
b/cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/CassandraAnalyticsSimpleTest.java
@@ -40,7 +40,10 @@ import static org.apache.cassandra.testing.TestUtils.DC1_RF3;
 import static org.apache.cassandra.testing.TestUtils.ROW_COUNT;
 import static org.apache.cassandra.testing.TestUtils.TEST_KEYSPACE;
 
-class SparkBulkWriterSimpleTest extends SharedClusterSparkIntegrationTestBase
+/**
+ * A simple test that runs a sample read/write Cassandra Analytics job.
+ */
+class CassandraAnalyticsSimpleTest extends 
SharedClusterSparkIntegrationTestBase
 {
     static final QualifiedName QUALIFIED_NAME = new 
QualifiedName(TEST_KEYSPACE, "test");
 
diff --git 
a/cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/RandomPartitionerTest.java
 
b/cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/RandomPartitionerTest.java
new file mode 100644
index 0000000..6f7dfa0
--- /dev/null
+++ 
b/cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/RandomPartitionerTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.analytics;
+
+import org.apache.cassandra.testing.ClusterBuilderConfiguration;
+
+/**
+ * Runs test from {@link CassandraAnalyticsSimpleTest} with the {@code 
RandomPartitioner}.
+ */
+class RandomPartitionerTest extends CassandraAnalyticsSimpleTest
+{
+    /**
+     * Inherit the configuration for the cluster from {@link 
CassandraAnalyticsSimpleTest} and set the
+     * partitioner to be the RandomPartitioner.
+     *
+     * @return the updated configuration for the cluster
+     */
+    @Override
+    protected ClusterBuilderConfiguration testClusterConfiguration()
+    {
+        return 
super.testClusterConfiguration().partitioner("org.apache.cassandra.dht.RandomPartitioner");
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to