Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deadlock when using both writeBlocking and Flows #1606

Closed
cmelchior opened this issue Dec 13, 2023 · 1 comment
Closed

Deadlock when using both writeBlocking and Flows #1606

cmelchior opened this issue Dec 13, 2023 · 1 comment

Comments

@cmelchior
Copy link
Contributor

cmelchior commented Dec 13, 2023

I ran into this behavior when I was trying to write up a sample that showed how to interop between Java and Kotlin. It looks like somehow we end up deadlocking our internals when using writeBlocking and Flow. Not 100% sure how it is happening though.

This JVM unit test demonstrates the behavior:

    @Test
    fun writeBlockingAndFlows() {
        val tmpDir = PlatformUtils.createTempDir()
        val configuration = RealmConfiguration.Builder(setOf(Parent::class, Child::class))
            .directory(tmpDir)
            .build()
        val realmScope = CoroutineScope(CoroutineName("RealmScope") + Dispatchers.Default)
        val realm = Realm.open(configuration)

        // Do initial write
        realm.writeBlocking {
            copyToRealm(Parent())
        }
        assertEquals(1, realm.query<Parent>().count().find())
        println("Wrote 1st data")

        // Start notifications
        val updateLatch = CountDownLatch(1)
        val job = realmScope.launch {
            realm.query<Parent>().asFlow().collect {
                println(it)
                if (it is UpdatedResults) {
                    updateLatch.countDown()
                }
            }
        }
        println("Started observer")

        // Do a 2nd write
        realm.writeBlocking {
            copyToRealm(Parent())
        }
        println("Wrote 2nd data")

        // Wait for the Update notification. This will currently fail, and all Coroutines are in
        // the WAITING state.
        // Note: If we move the notification block to run as the first thing, the writes do
        // not block it.
        if (!updateLatch.await(10, TimeUnit.SECONDS)) {
            fail("Did not receive update notification in time")
        }
        job.cancel()
        realm.close()
    }

The thread dump look like this:

image

@cmelchior
Copy link
Contributor Author

I made a mistake in reasoning about the flow of events. The 2nd write could happen before the listener fired the first event, which meant that no update was ever coming.

Closing

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 18, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant