couchbase / couchbase-lite-C

C language bindings for the Couchbase Lite embedded NoSQL database engine
Apache License 2.0
116 stars 37 forks source link

CBLQuery_AddChangeListener deadlocks when called in transaction after CBLDatabase_BeginTransaction #497

Open jeffdgr8 opened 1 year ago

jeffdgr8 commented 1 year ago

I’ve run into a bug with an extension on my Kotlin Multiplatform Couchbase Lite library where I add a query change listener within a transaction. This code works on Android and JVM using the Java SDK and iOS and macOS using the Objective-C SDK, but not on Linux and Windows using the native C SDK. The C SDK deadlocks and hangs when calling CBLQuery_AddChangeListener after calling CBLDatabase_BeginTransaction. This is with Couchbase Lite version 3.0.12.

Original forum post.

blaugold commented 1 year ago

It might be related to CBL-4548 (#476).

jianminzhao commented 1 year ago

In general, we should avoid configuring the database inside an open transaction. In this case, to add a change listener, we will wire into the database to receive changes. While doing the wiring, we may require a new transaction and trapped in deadlock. Is there a specific reason you want to add the listener while inside your transaction?

jeffdgr8 commented 1 year ago

@blaugold yes, this looks like a similar limitation. As Blake notes, there are a lot of things that aren't allowed to be done within an open transaction. A helpful error message would be a better UX rather than hanging the application in deadlock though, which is harder to debug.

@jianminzhao I describe my use case a bit more in my forum post. Essentially my ideal goal would to get the initial live query results from within the transaction that also performed the count query to calculate the offset for the live query. This way there's a guarantee that the database query results haven't been updated since the count query was executed, and if they have, the live query observer would then call the observer again with the updated result set. Since the live query observer is asynchronous, this complicates this goal.