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

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 1611369de9 [flink] Do not shuffle to a negative channel when the 
partition hash is Integer.MIN_VALUE (#9408)
1611369de9 is described below

commit 1611369de95828d0f71bfa816dccf5ae638fe9b1
Author: ZIHAN DAI <[email protected]>
AuthorDate: Wed Aug 26 19:30:16 2026 +1000

    [flink] Do not shuffle to a negative channel when the partition hash is 
Integer.MIN_VALUE (#9408)
---
 .../StatisticsOrRecordChannelComputer.java         |  2 +-
 .../StatisticsOrRecordChannelComputerTest.java     | 23 ++++++++++++++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/partition/StatisticsOrRecordChannelComputer.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/partition/StatisticsOrRecordChannelComputer.java
index 8a19f95e0e..0cb5f7c950 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/partition/StatisticsOrRecordChannelComputer.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/partition/StatisticsOrRecordChannelComputer.java
@@ -186,7 +186,7 @@ public class StatisticsOrRecordChannelComputer implements 
ChannelComputer<Statis
             if (assignment == null) {
                 int defaultSubtaskCount =
                         Math.min(numChannels, 
DEFAULT_SUBTASK_COUNT_FOR_UNKNOWN_PARTITION);
-                int startChannel = Math.abs(partitionKey.hashCode()) % 
numChannels;
+                int startChannel = ChannelComputer.startChannel(partitionKey, 
numChannels);
                 List<Integer> subtasks = new ArrayList<>(defaultSubtaskCount);
                 List<Long> weights = new ArrayList<>(defaultSubtaskCount);
                 for (int i = 0; i < defaultSubtaskCount; i++) {
diff --git 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/partition/StatisticsOrRecordChannelComputerTest.java
 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/partition/StatisticsOrRecordChannelComputerTest.java
index deedae4c29..ef4f617b82 100644
--- 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/partition/StatisticsOrRecordChannelComputerTest.java
+++ 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/partition/StatisticsOrRecordChannelComputerTest.java
@@ -226,6 +226,29 @@ class StatisticsOrRecordChannelComputerTest {
         assertThat(assignment).containsKey(p2);
     }
 
+    @Test
+    void testUnknownPartitionWhoseKeyHashesToMinValue() {
+        // Math.abs leaves Integer.MIN_VALUE negative. Pin the fixture: if the 
row hash ever
+        // changes this stops testing anything, and this assertion says so 
instead of passing.
+        InternalRow row =
+                GenericRow.of(
+                        0, BinaryString.fromString("p3588823253"), 
BinaryString.fromString("d"));
+        
assertThat(getPartitionKey(row).hashCode()).isEqualTo(Integer.MIN_VALUE);
+
+        // Integer.MIN_VALUE % n is only zero when n divides 2^31, so a 
parallelism that is not a
+        // power of two is what turns the negative hash into a negative 
channel.
+        for (int downstreamParallelism = 1; downstreamParallelism <= 16; 
downstreamParallelism++) {
+            StatisticsOrRecordChannelComputer channelComputer =
+                    new StatisticsOrRecordChannelComputer(schema);
+            channelComputer.setup(downstreamParallelism);
+            for (int i = 0; i < 50; i++) {
+                
assertThat(channelComputer.channel(StatisticsOrRecord.fromRecord(row)))
+                        .as("parallelism %d", downstreamParallelism)
+                        .isBetween(0, downstreamParallelism - 1);
+            }
+        }
+    }
+
     private BinaryRow getPartitionKey(InternalRow row) {
         RowPartitionKeyExtractor extractor = new 
RowPartitionKeyExtractor(schema);
         return extractor.partition(row).copy();

Reply via email to