Hi Dan

The plugin I'm referring to is a 'Share' plugin that one can embed inside of
a mac app, which then shows up in the "Sharing" menu in Safari. When you
click on it, it launches in its own process, allowing you to share the
currently viewed website with your main app. Thus, the main app and this
plugin are two separate processes accessing the same WAL database at the
same time (both could be 'writing').

I'll explain a bit more because disk I/O errors and disk corruption is
really killing me right now. These are the flags I've finally settled on:

#define SQLITE_ENABLE_FTS3 1
#define SQLITE_OMIT_DEPRECATED 1
#define SQLITE_OMIT_SHARED_CACHE 1
#define SQLITE_OMIT_AUTOMATIC_INDEX 1
#define SQLITE_OMIT_DECLTYPE 1

#define SQLITE_DEFAULT_MMAP_SIZE 0
#define SQLITE_DEFAULT_MEMSTATUS 0
#define SQLITE_DEFAULT_SYNCHRONOUS 1

#define SQLITE_THREADSAFE 2

#define SQLITE_MAX_MMAP_SIZE 0
#define SQLITE_TEMP_STORE 3


I've set it to be thread-safe. Although the app may have two processes
running at any given time (the main app,  and the plugin), any single
process itself has a single writer and multiple readers. Since WAL doesn't
support the read-only flag, I changed the readers to open like so (just as I
do my writer):

BOOL dbOpened = (sqlite3_open_v2(path.UTF8String, &readOnlyDB,
SQLITE_OPEN_READWRITE, NULL) == SQLITE_OK);

and then I set these to be query_only:

if (sqlite3_exec(readOnlyDB, "PRAGMA query_only=1;", NULL, NULL, NULL) !=
SQLITE_OK) {
  // ...       
}

The single writer is being accessed and used by the process using a
@synchronized() block (Objective-C), ensuring any prepared statement is used
and immediately reset and finalized before leaving the block.

To ensure thread-safety and a bit of 'database pooling' (so I don't have to
open and close connections on the same thread over and over again,
especially if I have nested calls in my code), I'm open a read-only
connection and then store it in the thread-local dictionary (i.e. [[NSThread
currentThread] threadDictionary]).

This gives me the concurrency I need, along with thread-safety to ensure the
same database connection is not used in a different thread. Prepared
statements tied to a read-only connection are also being stored this way -
in the thread local dictionary). 

I recently switched on the Thread Sanitizer in Xcode only to find that it
was complaining of race conditions inside of the sqlite3.c code, that the
various readers and writers were trying to read / write to the same
wal-index. This may be desirable (as I read elsewhere that this is okay) I
felt this may be causing issues. I've thus far wrapped each and every call
to the databse using the same @synchronized(lockObj) call. Doing so
essentially has made my otherwise multi-threaded app, a serialized app since
readers wait on each other, as well as on the main writer before accessing
the database. I tested this with a user seeing disk corruption often (and
mostly when he's using both the plugin and the main app) and he's reported a
90% improvement. This time he didn't see malformed disk errors but instead
saw 'disk I/O' errors after a few hours, but a relaunch of the app fixed it.

Right now I've tried every single flag in SQLite. Ive read, and re-read the
how to corrupt your database as well as anything and everything. I'm
struggling to figure this out. The *exact same code* works in iOS just fine
- not a single complaint for years. It's only the mac (any mac, it seems).

Maybe I could just switch to TRUNCATE journal mode now that I've effectiely
serialized all database access and I'm not getting any of the benefits of
multi-threading? Would that help? I should add that I switched to WAL
earlier this year and ever since have had issues reported, at least once a
week. Nowadays it's almost once a day. With journal_mode DELETE I never had
an issue, but then the app was pretty serial then.

Thanks
Fahad



--
Sent from: http://sqlite.1065341.n5.nabble.com/
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to