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/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new 4f63ada240 chore(spm): extract initialize all parititions helper 
(#23419)
4f63ada240 is described below

commit 4f63ada24056d9ec9b8decc04f128512bcdd735e
Author: Raz Luvaton <[email protected]>
AuthorDate: Thu Jul 9 19:21:28 2026 +0300

    chore(spm): extract initialize all parititions helper (#23419)
    
    ## Which issue does this PR close?
    
    N/A
    
    ## Rationale for this change
    
    Keeping the core loop tight and readable
    
    ## What changes are included in this PR?
    
    Just extracting a function
    
    ## Are these changes tested?
    
    existing tests
    
    ## Are there any user-facing changes?
    Nope
---
 datafusion/physical-plan/src/sorts/merge.rs | 107 +++++++++++++++++-----------
 1 file changed, 64 insertions(+), 43 deletions(-)

diff --git a/datafusion/physical-plan/src/sorts/merge.rs 
b/datafusion/physical-plan/src/sorts/merge.rs
index 4583d19e91..4117789777 100644
--- a/datafusion/physical-plan/src/sorts/merge.rs
+++ b/datafusion/physical-plan/src/sorts/merge.rs
@@ -236,53 +236,24 @@ impl<C: CursorValues> SortPreservingMergeStream<C> {
             }
             return Poll::Ready(None);
         }
+
         // Once all partitions have set their corresponding cursors for the 
loser tree,
         // we skip the following block. Until then, this function may be 
called multiple
         // times and can return Poll::Pending if any partition returns 
Poll::Pending.
-
         if self.loser_tree.is_empty() {
-            // Manual indexing since we're iterating over the vector and 
shrinking it in the loop
-            let mut idx = 0;
-            while idx < self.uninitiated_partitions.len() {
-                let partition_idx = self.uninitiated_partitions[idx];
-                match self.maybe_poll_stream(cx, partition_idx) {
-                    Poll::Ready(Err(e)) => {
-                        self.done = true;
-                        return Poll::Ready(Some(Err(e)));
-                    }
-                    Poll::Pending => {
-                        // The polled stream is pending which means we're 
already set up to
-                        // be woken when necessary
-                        // Try the next stream
-                        idx += 1;
-                    }
-                    _ => {
-                        // The polled stream is ready
-                        // Remove it from uninitiated_partitions
-                        // Don't bump idx here, since a new element will have 
taken its
-                        // place which we'll try in the next loop iteration
-                        // swap_remove will change the partition poll order, 
but that shouldn't
-                        // make a difference since we're waiting for all 
streams to be ready.
-                        self.uninitiated_partitions.swap_remove(idx);
-                    }
-                }
-            }
-
-            if self.uninitiated_partitions.is_empty() {
-                // If there are no more uninitiated partitions, set up the 
loser tree and continue
-                // to the next phase.
-
-                // Claim the memory for the uninitiated partitions
-                self.uninitiated_partitions.shrink_to_fit();
-                self.init_loser_tree();
-            } else {
-                // There are still uninitiated partitions so return pending.
-                // We only get here if we've polled all uninitiated streams 
and at least one of them
-                // returned pending itself. That means we will be woken as 
soon as one of the
-                // streams would like to be polled again.
-                // There is no need to reschedule ourselves eagerly.
-                return Poll::Pending;
-            }
+            ready!(self.initialize_all_partitions(cx))?;
+            assert_eq!(
+                self.uninitiated_partitions.len(),
+                0,
+                "all partitions should be initialized"
+            );
+
+            // If there are no more uninitiated partitions, set up the loser 
tree and continue
+            // to the next phase.
+
+            // Claim the memory for the uninitiated partitions
+            self.uninitiated_partitions.shrink_to_fit();
+            self.init_loser_tree();
         }
 
         // NB timer records time taken on drop, so there are no
@@ -327,6 +298,56 @@ impl<C: CursorValues> SortPreservingMergeStream<C> {
         }
     }
 
+    /// Initialize all partitions, return `Poll::Pending` if any partition 
returns `Poll::Pending`
+    ///
+    /// This DOES NOT return `Poll::Pending` as soon as the first uninitiated 
partition returns `Poll::Pending`
+    /// so we can continue to initialize the remaining partitions
+    fn initialize_all_partitions(&mut self, cx: &mut Context) -> 
Poll<Result<()>> {
+        assert_eq!(
+            self.loser_tree.len(),
+            0,
+            "loser tree must be empty when initializing"
+        );
+
+        // Manual indexing since we're iterating over the vector and shrinking 
it in the loop
+        let mut idx = 0;
+        while idx < self.uninitiated_partitions.len() {
+            let partition_idx = self.uninitiated_partitions[idx];
+            match self.maybe_poll_stream(cx, partition_idx) {
+                Poll::Ready(Err(e)) => {
+                    self.done = true;
+                    return Poll::Ready(Err(e));
+                }
+                Poll::Pending => {
+                    // The polled stream is pending which means we're already 
set up to
+                    // be woken when necessary
+                    // Try the next stream
+                    idx += 1;
+                }
+                _ => {
+                    // The polled stream is ready
+                    // Remove it from uninitiated_partitions
+                    // Don't bump idx here, since a new element will have 
taken its
+                    // place which we'll try in the next loop iteration
+                    // swap_remove will change the partition poll order, but 
that shouldn't
+                    // make a difference since we're waiting for all streams 
to be ready.
+                    self.uninitiated_partitions.swap_remove(idx);
+                }
+            }
+        }
+
+        if self.uninitiated_partitions.is_empty() {
+            Poll::Ready(Ok(()))
+        } else {
+            // There are still uninitiated partitions so return pending.
+            // We only get here if we've polled all uninitiated streams and at 
least one of them
+            // returned pending itself. That means we will be woken as soon as 
one of the
+            // streams would like to be polled again.
+            // There is no need to reschedule ourselves eagerly.
+            Poll::Pending
+        }
+    }
+
     /// For the given partition, updates the poll count. If the current value 
is the same
     /// of the previous value, it increases the count by 1; otherwise, it is 
reset as 0.
     fn update_poll_count_on_the_same_value(&mut self, partition_idx: usize) {


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

Reply via email to