viirya commented on code in PR #59565:
URL: https://github.com/apache/spark/pull/59565#discussion_r4301622123
##########
core/src/test/scala/org/apache/spark/api/python/BasePythonRunnerSuite.scala:
##########
@@ -211,4 +219,102 @@ class BasePythonRunnerSuite extends SparkFunSuite {
assert(BasePythonRunner.readWorkerMetrics(stream) == expectedMetrics)
checkEndMarkers(stream)
}
+
+ test("SPARK-60305: CloseShieldOutputStream forwards writes and does not
close the " +
+ "underlying stream") {
+ val bufferStream = new DirectByteBufferOutputStream()
+ val shielded = new CloseShieldOutputStream(bufferStream)
+ shielded.write(Array[Byte](1, 2, 3), 1, 2)
+ shielded.write(4)
+ shielded.close()
+ assert(bufferStream.size() === 3)
+ val bytes = new Array[Byte](3)
+ bufferStream.toByteBuffer.get(bytes)
+ assert(bytes.toSeq === Seq[Byte](2, 3, 4))
+ bufferStream.close()
+ }
+
+ test("SPARK-60305: interrupting the task thread inside a channel write keeps
the input " +
+ "buffer alive") {
+ sc = new SparkContext("local", "test")
+ val func = SimplePythonFunction(Seq.empty[Byte], new JHashMap[String,
String](),
+ new JArrayList[String](), "python3", "3", new JArrayList(), null)
+ val inWrite = new CountDownLatch(1)
+ val resume = new AtomicBoolean(false)
+ @volatile var writeError: Throwable = null
+
+ // Writes the way the Arrow inputs do: through
`Channels.newChannel(dataOut)`, whose writes
+ // the JVM closes, together with `dataOut`, when the writing thread is
interrupted. The
+ // write blocks until the test has interrupted the thread, then forwards
to `dataOut`.
+ class TestRunner extends BasePythonRunner[Int,
Int](Seq(ChainedPythonFunctions(Seq(func))),
Review Comment:
Done. The test now uses `PythonRunner` with `new runner.Writer(...)` and
`new runner.ReaderInputStream(...)`.
##########
core/src/main/scala/org/apache/spark/api/python/CloseShieldOutputStream.scala:
##########
@@ -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.spark.api.python
+
+import java.io.{FilterOutputStream, OutputStream}
+
+/**
+ * An output stream that forwards writes to `out` but does not close it on
[[close()]].
+ *
+ * Python runners serialize their input into a `DirectByteBufferOutputStream`,
whose `close()`
+ * frees its native buffer. Arrow writers write that stream through
`Channels.newChannel(...)`,
+ * an interruptible channel: when another thread interrupts the writing thread
inside a channel
+ * write (e.g. a task kill with `interruptThread = true`),
`Thread.interrupt()` closes the
+ * channel, and so the wrapped stream, on the interrupting thread while the
writing thread may
+ * still be copying into the buffer. Handing the writer this stream keeps the
buffer alive; the
+ * writing thread still stops with a `ClosedByInterruptException`, and the
buffer is freed only
+ * by its owner.
+ */
+private[python] class CloseShieldOutputStream(out: OutputStream) extends
FilterOutputStream(out) {
Review Comment:
Renamed the parameter to `underlying`.
--
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]