[ 
https://issues.apache.org/jira/browse/SPARK-39847?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Dongjoon Hyun resolved SPARK-39847.
-----------------------------------
    Fix Version/s: 3.3.1
                   3.2.3
                   3.4.0
       Resolution: Fixed

Issue resolved by pull request 37260
[https://github.com/apache/spark/pull/37260]

> Race condition related to interruption of task threads while they are in 
> RocksDBLoader.loadLibrary()
> ----------------------------------------------------------------------------------------------------
>
>                 Key: SPARK-39847
>                 URL: https://issues.apache.org/jira/browse/SPARK-39847
>             Project: Spark
>          Issue Type: Bug
>          Components: Structured Streaming
>    Affects Versions: 3.2.0
>            Reporter: Josh Rosen
>            Assignee: Josh Rosen
>            Priority: Major
>             Fix For: 3.3.1, 3.2.3, 3.4.0
>
>
> One of our workloads experienced a rare failure in `RocksDBLoader`
> {code:java}
> Caused by: java.lang.IllegalThreadStateException
>       at java.lang.Thread.start(Thread.java:708)
>       at 
> org.apache.spark.sql.execution.streaming.state.RocksDBLoader$.loadLibrary(RocksDBLoader.scala:51)
>  {code}
> After investigation, we determined that was due to task cancellation: if the 
> task which starts the RocksDB library loading is interrupted, another thread 
> may begin a load and crash with the thread state exception.
> Skimming through the code in 
> [RocksDBLoader|https://github.com/apache/spark/blob/master/sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDBLoader.scala],
>  I spot a potential race condition:
>  * Although the native JNI call is uninterruptible, the thread which calls 
> loadLibrary is still interruptible. Let’s call that thread the “task thread”.
>  * Say we have two tasks, A and B, which both want to load the JNI library.
>  * Say that Task A wins the race to perform the load and enters the 
> synchronized block in loadLibrary(), spawns a child thread to perform the 
> actual loading, then blocks in the loadLibraryThread.join() call.
>  * If Task A is interrupted, an InterruptedException will be thrown and it 
> will exit the loadLibrary synchronized block.
>  * At this point, Task B enters the synchronized block and sees that 
> exception == null because the loading thread is still running, so it calls 
> loadLibraryThread.start() and hits the thread state error.
> One way to fix this is to add
> {code:java}
>  if (loadLibraryThread.getState == Thread.State.NEW) {
>         loadLibraryThread.start()
>       }{code}
> to ensure that only one thread starts the loadLibraryThread. If the original 
> starter thread is interrupted then a new thread will encounter this block, 
> skip the start(), proceed to the join() and block on the original load thread.
> I will submit a PR with this fix.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscr...@spark.apache.org
For additional commands, e-mail: issues-h...@spark.apache.org

Reply via email to