Interprocess SQLite Thread Safety (on iOS)

I’m trying to determine if my sqlite access to a database is thread-safe on iOS. I’m writing a non App Store app (or possibly a launch daemon), so Apple’s approval isn’t an issue. The database in question is the built-in sms.db, so for sure the OS is also accessing this database for reading and writing. I only want to be able to safely read it.

I’ve read this about reading from multiple processes with sqlite:

  • Thread safe instantiation of a singleton
  • Cordova shows an warning as “ THREAD WARNING: took ms. ” in iOS
  • How can I make every message an object receives thread-safe?
  • Core Data & Threads
  • Thread safe lazy initialization on iOS
  • Why should we separate alloc and init calls to avoid deadlocks in Objective-C?
  • Multiple processes can have the same database open at the same time.
    Multiple processes can be doing a SELECT at the same time. But only
    one process can be making changes to the database at any moment in
    time, however.

    I understand that thread-safety can be compiled out of sqlite, and that sqlite3_threadsafe() can be used to test for this. Running this on iOS 5.0.1

    int safe = sqlite3_threadsafe();
    

    yields a result of 2. According to this, that means mutex locking is available. But, that doesn’t necessarily mean it’s in use.

    I’m not entirely clear on whether thread-safety is dynamically enabled on a per connection, per database, or global basis.

    I have also read this. It looks like sqlite3_config() can be used to enable safe multi-threading, but of course, I have no control, or visibility into how the OS itself may have used this call (do I?). If I were to make that call again in my app, would it make it safe to read the database, or would it only deconflict concurrent access for multiple threads in my app that used the same sqlite3 database handle?

    Anyway, my question is …

    can I safely read this database that’s also accessed by iOS, and if so, how?

    2 Solutions Collect From Internet About “Interprocess SQLite Thread Safety (on iOS)”

    I’ve never used SQLite, but I’ve spent a decent amount of time reading its docs because I plan on using it in the future (and the docs are interesting). I’d say that thread safety is independent of whether multiple processes can access the same database file at once. SQLite, regardless of what threading mode it is in, will lock the database file, so that multiple processes can read from the database at once but only one can write.

    Thread safety only affects how your process can use SQLite. Without any thread safety, you can only call SQLite functions from one thread. But it should still, say, take an EXCLUSIVE lock before writing, so that other processes can’t corrupt the database file. Thread safety just protects data in your process’s memory from getting corrupted if you use multiple threads. So I don’t think you ever need to worry about what another process (in this case iOS) is doing with an SQLite database.

    Edit: To clarify, any time you write to the database, including a plain INSERT/UPDATE/DELETE, it will automatically take an EXCLUSIVE lock, write to the database, then release the lock. (And it actually takes a SHARED lock, then a RESERVED lock, then a PENDING lock, then an EXCLUSIVE lock before writing.) By default, if the database is already locked (say from another process), then SQLite will return SQLITE_BUSY without waiting. You can call sqlite3_busy_timeout() to tell it to wait longer.

    I don’t think any of this is news to you, but a few thoughts:

    In terms of enabling multi-threading (either serialized or multi-threaded), the general counsel is that one can invoke sqlite3_config() (but you may have to do a shutdown first as suggested in the docs or as discussed on SO here) to enable the sort of multi-threading you want. That may be of diminished usefulness here, though, where you have no control over what sort of access iOS is requesting of sqlite and/or this database.

    Thus, I would have thought that, from an academic perspective, it would not be safe to read this system database (because as you say, you have no assurance of what the OS is doing). But I wouldn’t be surprised if iOS is opening the database using whatever the default mode is, so from a more pragmatic perspective, you might be fine.

    Clearly, for most users concerned about multi-threaded access within a single app, the best counsel would be to bypass the sqlite3_config() silliness and just simply ensure coordinated access through your own GCD serial queue (i.e., have a dedicated queue through which all database interactions go through, gracefully eliminating the multi-thread issue altogether). Sadly, that’s not an option here because you’re trying to coordinate database interaction with iOS itself.