ccgus / fmdb

A Cocoa / Objective-C wrapper around SQLite
Other
13.84k stars 2.76k forks source link

FMDB locks database after sqlite3_step #123

Open nicoodeimos opened 11 years ago

nicoodeimos commented 11 years ago

Hello,

I'm having a deadlock with FMDB in a multithreaded environment. My app is composed of 2 thread that can read/write (updates and selects).

All the functions that deal with the database are protected by a shared mutex that ensures data integrity. I have two connections (one per thread), and the connections aren't shared (which is a requirement to avoid an EXC_BAD_ACCESS error).

Everything was fine until last week when I figured that sometimes the app blocks because of some FMDB calls to update/select data while the other thread is working on the database.

The locks happens on the C function sqlite3_step that returns SQLITE_BUSY, on the main thread (even when the second thread has finished its work).

My app uses the main thread to perform UI updates, while the second thread only updates the database from network data (nothing special, just an webservice).

I've used mutexes to ensure that the main thread gets data in a good final shape (i.e let the update thread do its work entirely, and then let the main thread get fully updated data).

All my lock/unlock mutex calls are balanced (the deadlock dosen't appear because of it). I'm using FMDB on iOS.

Do you have any idea why this would occur ? I've been struggling with that issue for a week now.. Thank you for your awesome work.

ccgus commented 11 years ago

I can't tell you why it would be happening- sorry. If you have a reproducible sample code, I'd love to see it.

You might consider switching to FMDatabaseQueue, which was designed to solve these headaches.

cfsi commented 10 years ago

I've just encountered a similar if not identical deadlock; two threads, each with their own FMDatabase, concurrently doing reads and writes, eventually deadlocking on write.

I've tracked this down to the fact that my result sets are not always being closed (and I never explicitly call close). If you walk your result set to the end with [rs next], FMDB will close it for you.

However, if you're just looking for a single return value, call [rs next], and return the parsed value to the caller, your result set will not be closed until it is freed - which may not happen until some undetermined time in the future.

The open result set holds open state in sqlite which needs to be cleared - but doesn't generally cause a problem if you are single threaded. (I actually did have a problem related to this with single threaded code as well, when I attempted to detach a database while a previous result set was still open.)

By going through my code and explicitly calling [rs close] in places where I do not otherwise exhaust the result set, I seem to have eliminated the deadlock. I was able to reproduce the deadlock reliably by commenting out the closes I added, and could not reproduce it reintroducing the closes.

I'm sure it's too late to help the original commenter, but hopefully it will help others who come across this issue. But the moral of the story is, make sure your result sets get closed in a timely manner.

Oh, and I'd also like to say, FMDB has been excellent.

patsch commented 10 years ago

cfsi - thanks a bunch!! I had exactly this issue and was pulling my hair out as to why the device completely froze; by ensuring that the result sets are closed before something happens on another thread the problem went away.