diff --git a/db/sqlite3/src/Makefile.in b/db/sqlite3/src/Makefile.in index c745170bfb68..4c713f41c2e5 100644 --- a/db/sqlite3/src/Makefile.in +++ b/db/sqlite3/src/Makefile.in @@ -98,7 +98,7 @@ CSRCS = \ # REFEF_IO allows us to override IO functions, which is used in the AsyncIO # -DSQLITE_SECURE_DELETE=1 will cause SQLITE to 0-fill delete data so we # don't have to vacuum to make sure the data is not visible in the file. -DEFINES = -DSQLITE_ENABLE_REDEF_IO -DSQLITE_SECURE_DELETE=1 +DEFINES = -DSQLITE_ENABLE_REDEF_IO -DSQLITE_SECURE_DELETE=1 -DTHREADSAFE=1 ifdef ENABLE_TESTS ##LIBS = $(DIST)/lib/$(LIB_PREFIX)sqlite3_s.$(LIB_SUFFIX) diff --git a/storage/public/mozIStorageService.idl b/storage/public/mozIStorageService.idl index 01cfcfa7ace2..f220fbbe33b8 100644 --- a/storage/public/mozIStorageService.idl +++ b/storage/public/mozIStorageService.idl @@ -46,6 +46,11 @@ interface nsIFile; * a service that can create storage connections (mozIStorageConnection) * to either a well-known profile database or to a specific database file. * + * The implementation of this service using sqlite with the async IO module + * must be created the first time on the main thread. If you want to use it + * from another thread, you should be sure you call getService from the main + * thread before accessing it from another thread. + * * This is the only way to open a database connection. */ [scriptable, uuid(a4a0cad9-e0da-4379-bee4-2feef3dddc7e)] @@ -54,7 +59,11 @@ interface mozIStorageService : nsISupports { * Get a connection to a named special database storage. * * @param aStorageKey a string key identifying the type of storage - * requested. Valid values include: "profile", "memory" + * requested. Valid values include: "profile", "memory". + * + * @see openDatabase for restrictions on how database connections may be + * used. For the profile database, you should only access it from the main + * thread since other callers may also have connections. * * @returns a new mozIStorageConnection for the requested * storage database. @@ -76,14 +85,11 @@ interface mozIStorageService : nsISupports { * a connection to "Foo.sqlite" and "foo.sqlite" will CORRUPT YOUR DATABASE. * * Opening connections from more than one thread to the same database will - * also CORRUPT YOUR DATABASE. Accessing a connection object from any thread - * other than the thread that created it is not supported by sqlite. Some - * old Linux systems might corrupt the database due to locking issues in this - * case. + * also CORRUPT YOUR DATABASE. All connections share the same sqlite cache, + * and the cache is not threadsafe. * - * Opening a connection from any thread but the main thread has not been - * tested and should be assumed to not work. Even if you find that it works, - * there may be subtle locking problems, so don't do it. + * The connection object returned by this function is not threadsafe. You must + * use it only from the thread you created it from. * * @param aDatabaseFile a nsIFile of the database to open. * diff --git a/storage/src/mozStorageService.cpp b/storage/src/mozStorageService.cpp index add5a3d9fde8..408bc47bd3e8 100644 --- a/storage/src/mozStorageService.cpp +++ b/storage/src/mozStorageService.cpp @@ -41,6 +41,7 @@ #include "mozStorageService.h" #include "mozStorageConnection.h" #include "nsCRT.h" +#include "nsIThread.h" #include "plstr.h" #include "sqlite3.h" @@ -66,6 +67,14 @@ mozStorageService::~mozStorageService() nsresult mozStorageService::Init() { + // The service must be initialized on the main thread. The + // InitStorageAsyncIO function creates a thread which is joined with the + // main thread during shutdown. If the thread is created from a random + // thread, we'll join to the wrong parent. + NS_ENSURE_STATE(nsIThread::IsMainThread()); + + // this makes multiple connections to the same database share the same pager + // cache. sqlite3_enable_shared_cache(1); nsresult rv;