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

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git


The following commit(s) were added to refs/heads/main by this push:
     new f5c77295a9 refactor(pyamber): share receiver-batch construction in 
partitioners (#5989)
f5c77295a9 is described below

commit f5c77295a9db77420ecb2dd62eec1f7a05b82e46
Author: Matthew B. <[email protected]>
AuthorDate: Tue Jul 7 16:23:22 2026 -0700

    refactor(pyamber): share receiver-batch construction in partitioners (#5989)
    
    ### What changes were proposed in this PR?
    - Added `Partitioner.build_receiver_batches(channels)` to the base
    class, the single home for the ordered `(receiver, batch)` list built
    via `dict.fromkeys` (which preserves channel order where a set literal
    would not).
    - Replaced the three identical inline copies of that construction in
    `RoundRobinPartitioner`, `HashBasedShufflePartitioner`, and
    `RangeBasedShufflePartitioner` with a call to the shared helper,
    dropping the drifted copy-pasted comments.
    - No behavior change: each partitioner still builds the same ordered,
    deduplicated receiver list.
    ### Any related issues, documentation, discussions?
    Closes: #5988
    ### How was this PR tested?
    - Run `cd amber && PYTHONPATH=src/main/python python -m pytest
    src/test/python/core/architecture/sendsemantics/test_partitioners.py
    -q`, expect all 35 tests to pass.
    - The order/dedup behavior owned by the new helper is covered by the
    existing `TestRoundRobinPartitioner::test_init_preserves_channel_order`
    and `test_init_dedupes_duplicate_channels_preserving_first_seen_order`;
    confirm they still pass against the refactored construction.
    ### Was this PR authored or co-authored using generative AI tooling?
    Co-authored with Claude Opus 4.8 in compliance with ASF
    
    Co-authored-by: Xinyuan Lin <[email protected]>
---
 .../sendsemantics/hash_based_shuffle_partitioner.py       | 14 ++------------
 .../python/core/architecture/sendsemantics/partitioner.py | 12 ++++++++++++
 .../sendsemantics/range_based_shuffle_partitioner.py      | 14 ++------------
 .../architecture/sendsemantics/round_robin_partitioner.py | 15 ++-------------
 4 files changed, 18 insertions(+), 37 deletions(-)

diff --git 
a/amber/src/main/python/core/architecture/sendsemantics/hash_based_shuffle_partitioner.py
 
b/amber/src/main/python/core/architecture/sendsemantics/hash_based_shuffle_partitioner.py
index de018e5a3c..ceee764c1b 100644
--- 
a/amber/src/main/python/core/architecture/sendsemantics/hash_based_shuffle_partitioner.py
+++ 
b/amber/src/main/python/core/architecture/sendsemantics/hash_based_shuffle_partitioner.py
@@ -37,18 +37,8 @@ class HashBasedShufflePartitioner(Partitioner):
         super().__init__(set_one_of(Partitioning, partitioning))
         logger.debug(f"got {partitioning}")
         self.batch_size = partitioning.batch_size
-        # Partitioning contains an ordered list of downstream worker ids.
-        # Currently we are using the index of such an order to choose
-        # a downstream worker to send tuples to.
-        # Must use dict.fromkeys to ensure the order of receiver workers
-        # from partitioning is preserved (using `{}` to create a set
-        # does not preserve order and will not work correctly.)
-        self.receivers = [
-            (rid, [])
-            for rid in dict.fromkeys(
-                channel.to_worker_id for channel in partitioning.channels
-            )
-        ]
+        # Indexed by hash_code to choose the downstream worker to send to.
+        self.receivers = self.build_receiver_batches(partitioning.channels)
         self.hash_attribute_names = partitioning.hash_attribute_names
 
     @overrides
diff --git 
a/amber/src/main/python/core/architecture/sendsemantics/partitioner.py 
b/amber/src/main/python/core/architecture/sendsemantics/partitioner.py
index c4aac57cbe..ed2332d5cb 100644
--- a/amber/src/main/python/core/architecture/sendsemantics/partitioner.py
+++ b/amber/src/main/python/core/architecture/sendsemantics/partitioner.py
@@ -32,6 +32,18 @@ class Partitioner(ABC):
     def __init__(self, partitioning: Message):
         self.partitioning: Partitioning = get_one_of(partitioning)
 
+    @staticmethod
+    def build_receiver_batches(
+        channels,
+    ) -> typing.List[typing.Tuple[ActorVirtualIdentity, typing.List[Tuple]]]:
+        # An ordered (receiver, batch) pair per distinct downstream worker.
+        # dict.fromkeys preserves the channel order; a set literal would not,
+        # which breaks input-port materialization reader threads.
+        return [
+            (rid, [])
+            for rid in dict.fromkeys(channel.to_worker_id for channel in 
channels)
+        ]
+
     def add_tuple_to_batch(
         self, tuple_: Tuple
     ) -> Iterator[typing.Tuple[ActorVirtualIdentity, typing.List[Tuple]]]:
diff --git 
a/amber/src/main/python/core/architecture/sendsemantics/range_based_shuffle_partitioner.py
 
b/amber/src/main/python/core/architecture/sendsemantics/range_based_shuffle_partitioner.py
index 28aff35935..3f8f83c504 100644
--- 
a/amber/src/main/python/core/architecture/sendsemantics/range_based_shuffle_partitioner.py
+++ 
b/amber/src/main/python/core/architecture/sendsemantics/range_based_shuffle_partitioner.py
@@ -37,18 +37,8 @@ class RangeBasedShufflePartitioner(Partitioner):
         super().__init__(set_one_of(Partitioning, partitioning))
         logger.info(f"got {partitioning}")
         self.batch_size = partitioning.batch_size
-        # Partitioning contains an ordered list of downstream worker ids.
-        # Currently we are using the index of such an order to choose
-        # a downstream worker to send tuples to.
-        # Must use dict.fromkeys to ensure the order of receiver workers
-        # from partitioning is preserved (using `{}` to create a set
-        # does not preserve order and will not work correctly.)
-        self.receivers = [
-            (rid, [])
-            for rid in dict.fromkeys(
-                channel.to_worker_id for channel in partitioning.channels
-            )
-        ]
+        # Indexed by get_receiver_index to choose the downstream worker to 
send to.
+        self.receivers = self.build_receiver_batches(partitioning.channels)
         self.range_attribute_names = partitioning.range_attribute_names
         self.range_min = partitioning.range_min
         self.range_max = partitioning.range_max
diff --git 
a/amber/src/main/python/core/architecture/sendsemantics/round_robin_partitioner.py
 
b/amber/src/main/python/core/architecture/sendsemantics/round_robin_partitioner.py
index 87c3fee87d..21c1a3ca0f 100644
--- 
a/amber/src/main/python/core/architecture/sendsemantics/round_robin_partitioner.py
+++ 
b/amber/src/main/python/core/architecture/sendsemantics/round_robin_partitioner.py
@@ -35,19 +35,8 @@ class RoundRobinPartitioner(Partitioner):
     def __init__(self, partitioning: RoundRobinPartitioning):
         super().__init__(set_one_of(Partitioning, partitioning))
         self.batch_size = partitioning.batch_size
-        # Partitioning contains an ordered list of downstream worker ids.
-        # Currently we are using the index of such an order to choose
-        # a downstream worker to send tuples to.
-        # Must use dict.fromkeys to ensure the order of receiver workers
-        # from partitioning is preserved (using `{}` to create a set
-        # does not preserve order and will not work with input-port
-        # materialization reader threads.)
-        self.receivers = [
-            (rid, [])
-            for rid in dict.fromkeys(
-                channel.to_worker_id for channel in partitioning.channels
-            )
-        ]
+        # Indexed by round_robin_index to choose the downstream worker to send 
to.
+        self.receivers = self.build_receiver_batches(partitioning.channels)
         self.round_robin_index = 0
 
     @overrides

Reply via email to