srielau commented on code in PR #58549:
URL: https://github.com/apache/spark/pull/58549#discussion_r4051436464


##########
sql/core/src/main/scala/org/apache/spark/sql/execution/python/ColumnarArrowEvalPythonEvaluatorFactory.scala:
##########
@@ -190,10 +216,22 @@ private[python] class 
ColumnarArrowEvalPythonEvaluatorFactory(
 
       val passThruQueue =
         new ArrayDeque[(Array[ColumnVector], Int)]()

Review Comment:
   Fixed in 14093addc31. The pass-through queue is now a ConcurrentLinkedQueue, 
which safely publishes entries between the pipelined writer thread and task 
thread. The Arrow-backed legacy-output test now explicitly enables pipelined 
execution.



##########
sql/core/src/main/scala/org/apache/spark/sql/execution/python/ColumnarArrowEvalPythonEvaluatorFactory.scala:
##########
@@ -190,10 +216,22 @@ private[python] class 
ColumnarArrowEvalPythonEvaluatorFactory(
 
       val passThruQueue =
         new ArrayDeque[(Array[ColumnVector], Int)]()
+      context.addTaskCompletionListener[Unit] { _ =>
+        while (!passThruQueue.isEmpty) {
+          passThruQueue.poll()._1.foreach(_.close())
+        }
+      }
 
       val bufferedIter = inputIter.map { batch =>
-        val passThruCols = childOutput.indices.map(
-          i => batch.column(i)).toArray
+        // The input reader owns and may close its vectors as soon as the 
Python runner consumes
+        // the input iterator. Create independent vector views whose buffers 
remain valid until
+        // the corresponding output batch is closed.
+        val passThruCols = childOutput.indices.map { i =>
+          val vector = 
batch.column(i).asInstanceOf[ArrowColumnVector].getValueVector

Review Comment:
   Fixed in 14093addc31. The optimized path now requires every 
child/pass-through column in the batch to be an ArrowColumnVector; mixed 
batches fall back to the row-queue path.



##########
sql/core/src/main/scala/org/apache/spark/sql/execution/python/ColumnarArrowEvalPythonEvaluatorFactory.scala:
##########
@@ -190,10 +216,22 @@ private[python] class 
ColumnarArrowEvalPythonEvaluatorFactory(
 
       val passThruQueue =
         new ArrayDeque[(Array[ColumnVector], Int)]()
+      context.addTaskCompletionListener[Unit] { _ =>
+        while (!passThruQueue.isEmpty) {
+          passThruQueue.poll()._1.foreach(_.close())
+        }
+      }
 
       val bufferedIter = inputIter.map { batch =>
-        val passThruCols = childOutput.indices.map(
-          i => batch.column(i)).toArray
+        // The input reader owns and may close its vectors as soon as the 
Python runner consumes

Review Comment:
   Fixed in 14093addc31. Both the class-level path description and 
evalArrowColumnar Scaladoc now explain that pass-through vectors are 
transferred to independent views because the source may close the originals 
before Python output is consumed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to