зеркало из https://github.com/mozilla/pjs.git
Make mozIStorageConnection threadsafe - bug 448476 r=robarnold
This commit is contained in:
Родитель
134dad3910
Коммит
bbe06d499c
|
@ -53,6 +53,8 @@ interface nsIFile;
|
|||
* primary interface for interacting with a database, including
|
||||
* creating prepared statements, executing SQL, and examining database
|
||||
* errors.
|
||||
*
|
||||
* @threadsafe
|
||||
*/
|
||||
[scriptable, uuid(623f9ddb-434b-4d39-bc2d-1c617da241d0)]
|
||||
interface mozIStorageConnection : nsISupports {
|
||||
|
@ -206,7 +208,9 @@ interface mozIStorageConnection : nsISupports {
|
|||
*/
|
||||
|
||||
/**
|
||||
* Create a new SQLite function
|
||||
* Create a new SQL function. If you use your connection on multiple threads,
|
||||
* your function needs to be threadsafe, or it should only be called on one
|
||||
* thread.
|
||||
*
|
||||
* @param aFunctionName The name of function to create, as seen in SQL.
|
||||
* @param aNumArguments The number of arguments the function takes. Pass
|
||||
|
@ -219,7 +223,9 @@ interface mozIStorageConnection : nsISupports {
|
|||
in mozIStorageFunction aFunction);
|
||||
|
||||
/**
|
||||
* Create a new SQLite aggregate function
|
||||
* Create a new SQL aggregate function. If you use your connection on
|
||||
* multiple threads, your function needs to be threadsafe, or it should only
|
||||
* be called on one thread.
|
||||
*
|
||||
* @param aFunctionName The name of aggregate function to create, as seen
|
||||
* in SQL.
|
||||
|
@ -232,7 +238,7 @@ interface mozIStorageConnection : nsISupports {
|
|||
in long aNumArguments,
|
||||
in mozIStorageAggregateFunction aFunction);
|
||||
/**
|
||||
* Delete custom SQLite function (simple or aggregate one)
|
||||
* Delete custom SQL function (simple or aggregate one).
|
||||
*
|
||||
* @param aFunctionName The name of function to remove.
|
||||
*/
|
||||
|
@ -240,7 +246,9 @@ interface mozIStorageConnection : nsISupports {
|
|||
|
||||
/**
|
||||
* Sets a progress handler. Only one handler can be registered at a time.
|
||||
* If you need more than one, you need to chain them yourself.
|
||||
* If you need more than one, you need to chain them yourself. This progress
|
||||
* handler should be threadsafe if you use this connection object on more than
|
||||
* one thread.
|
||||
*
|
||||
* @param aGranularity The number of SQL virtual machine steps between
|
||||
* progress handler callbacks.
|
||||
|
|
|
@ -70,12 +70,16 @@ PRLogModuleInfo* gStorageLog = nsnull;
|
|||
|
||||
#define PREF_TS_SYNCHRONOUS "toolkit.storage.synchronous"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(mozStorageConnection, mozIStorageConnection)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(mozStorageConnection, mozIStorageConnection)
|
||||
|
||||
mozStorageConnection::mozStorageConnection(mozIStorageService* aService)
|
||||
: mDBConn(nsnull), mTransactionInProgress(PR_FALSE),
|
||||
mProgressHandler(nsnull),
|
||||
mStorageService(aService)
|
||||
mozStorageConnection::mozStorageConnection(mozIStorageService* aService) :
|
||||
mDBConn(nsnull)
|
||||
, mTransactionMutex(nsAutoLock::NewLock("TransactionMutex"))
|
||||
, mTransactionInProgress(PR_FALSE)
|
||||
, mFunctionsMutex(nsAutoLock::NewLock("FunctionsMutex"))
|
||||
, mProgressHandlerMutex(nsAutoLock::NewLock("ProgressHandlerMutex"))
|
||||
, mProgressHandler(nsnull)
|
||||
, mStorageService(aService)
|
||||
{
|
||||
mFunctions.Init();
|
||||
}
|
||||
|
@ -83,6 +87,9 @@ mozStorageConnection::mozStorageConnection(mozIStorageService* aService)
|
|||
mozStorageConnection::~mozStorageConnection()
|
||||
{
|
||||
(void)Close();
|
||||
nsAutoLock::DestroyLock(mTransactionMutex);
|
||||
nsAutoLock::DestroyLock(mFunctionsMutex);
|
||||
nsAutoLock::DestroyLock(mProgressHandlerMutex);
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -101,6 +108,9 @@ NS_IMETHODIMP
|
|||
mozStorageConnection::Initialize(nsIFile *aDatabaseFile)
|
||||
{
|
||||
NS_ASSERTION (!mDBConn, "Initialize called on already opened database!");
|
||||
NS_ENSURE_TRUE(mTransactionMutex, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ENSURE_TRUE(mFunctionsMutex, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ENSURE_TRUE(mProgressHandlerMutex, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
int srv;
|
||||
nsresult rv;
|
||||
|
@ -215,8 +225,12 @@ mozStorageConnection::Close()
|
|||
leafName.get()));
|
||||
#endif
|
||||
|
||||
if (mProgressHandler)
|
||||
sqlite3_progress_handler(mDBConn, 0, NULL, NULL);
|
||||
{
|
||||
nsAutoLock mutex(mProgressHandlerMutex);
|
||||
if (mProgressHandler)
|
||||
sqlite3_progress_handler(mDBConn, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
int srv = sqlite3_close(mDBConn);
|
||||
if (srv != SQLITE_OK)
|
||||
NS_WARNING("sqlite3_close failed. There are probably outstanding statements!");
|
||||
|
@ -417,6 +431,7 @@ mozStorageConnection::IndexExists(const nsACString& aIndexName, PRBool* _retval)
|
|||
NS_IMETHODIMP
|
||||
mozStorageConnection::GetTransactionInProgress(PRBool *_retval)
|
||||
{
|
||||
nsAutoLock mutex(mTransactionMutex);
|
||||
*_retval = mTransactionInProgress;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -425,17 +440,13 @@ mozStorageConnection::GetTransactionInProgress(PRBool *_retval)
|
|||
NS_IMETHODIMP
|
||||
mozStorageConnection::BeginTransaction()
|
||||
{
|
||||
if (mTransactionInProgress)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = ExecuteSimpleSQL (NS_LITERAL_CSTRING("BEGIN TRANSACTION"));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mTransactionInProgress = PR_TRUE;
|
||||
return rv;
|
||||
return BeginTransactionAs(mozIStorageConnection::TRANSACTION_DEFERRED);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozStorageConnection::BeginTransactionAs(PRInt32 aTransactionType)
|
||||
{
|
||||
nsAutoLock mutex(mTransactionMutex);
|
||||
if (mTransactionInProgress)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv;
|
||||
|
@ -460,6 +471,7 @@ mozStorageConnection::BeginTransactionAs(PRInt32 aTransactionType)
|
|||
NS_IMETHODIMP
|
||||
mozStorageConnection::CommitTransaction()
|
||||
{
|
||||
nsAutoLock mutex(mTransactionMutex);
|
||||
if (!mTransactionInProgress)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = ExecuteSimpleSQL (NS_LITERAL_CSTRING("COMMIT TRANSACTION"));
|
||||
|
@ -471,6 +483,7 @@ mozStorageConnection::CommitTransaction()
|
|||
NS_IMETHODIMP
|
||||
mozStorageConnection::RollbackTransaction()
|
||||
{
|
||||
nsAutoLock mutex(mTransactionMutex);
|
||||
if (!mTransactionInProgress)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = ExecuteSimpleSQL (NS_LITERAL_CSTRING("ROLLBACK TRANSACTION"));
|
||||
|
@ -523,6 +536,7 @@ mozStorageConnection::s_FindFuncEnum(const nsACString &aKey,
|
|||
PRBool
|
||||
mozStorageConnection::FindFunctionByInstance(nsISupports *aInstance)
|
||||
{
|
||||
// The lock should already be held by calling functions
|
||||
FindFuncEnumArgs args = { aInstance, PR_FALSE };
|
||||
mFunctions.EnumerateRead(s_FindFuncEnum, &args);
|
||||
return args.mFound;
|
||||
|
@ -663,6 +677,7 @@ mozStorageConnection::CreateFunction(const nsACString &aFunctionName,
|
|||
// do we already have this function defined?
|
||||
// Check for name only because simple function can
|
||||
// be defined multiple times with different names (aliases).
|
||||
nsAutoLock mutex(mFunctionsMutex);
|
||||
NS_ENSURE_FALSE(mFunctions.Get (aFunctionName, NULL), NS_ERROR_FAILURE);
|
||||
|
||||
int srv = sqlite3_create_function (mDBConn,
|
||||
|
@ -738,6 +753,7 @@ mozStorageConnection::CreateAggregateFunction(const nsACString &aFunctionName,
|
|||
|
||||
// do we already have this function defined?
|
||||
// Check for name.
|
||||
nsAutoLock mutex(mFunctionsMutex);
|
||||
NS_ENSURE_FALSE(mFunctions.Get (aFunctionName, NULL), NS_ERROR_FAILURE);
|
||||
|
||||
// Aggregate functions are stateful, so we cannot have
|
||||
|
@ -770,6 +786,7 @@ mozStorageConnection::RemoveFunction(const nsACString &aFunctionName)
|
|||
{
|
||||
if (!mDBConn) return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
nsAutoLock mutex(mFunctionsMutex);
|
||||
NS_ENSURE_TRUE(mFunctions.Get (aFunctionName, NULL), NS_ERROR_FAILURE);
|
||||
|
||||
int srv = sqlite3_create_function (mDBConn,
|
||||
|
@ -805,6 +822,7 @@ mozStorageConnection::SetProgressHandler(PRInt32 aGranularity,
|
|||
if (!mDBConn) return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
// Return previous one
|
||||
nsAutoLock mutex(mProgressHandlerMutex);
|
||||
NS_IF_ADDREF(*aOldHandler = mProgressHandler);
|
||||
|
||||
if (!aHandler || aGranularity <= 0) {
|
||||
|
@ -823,6 +841,7 @@ mozStorageConnection::RemoveProgressHandler(mozIStorageProgressHandler **aOldHan
|
|||
if (!mDBConn) return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
// Return previous one
|
||||
nsAutoLock mutex(mProgressHandlerMutex);
|
||||
NS_IF_ADDREF(*aOldHandler = mProgressHandler);
|
||||
|
||||
mProgressHandler = nsnull;
|
||||
|
@ -834,6 +853,7 @@ mozStorageConnection::RemoveProgressHandler(mozIStorageProgressHandler **aOldHan
|
|||
int
|
||||
mozStorageConnection::ProgressHandler()
|
||||
{
|
||||
nsAutoLock mutex(mProgressHandlerMutex);
|
||||
if (mProgressHandler) {
|
||||
PRBool res;
|
||||
nsresult rv = mProgressHandler->OnProgress(this, &res);
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#define _MOZSTORAGECONNECTION_H_
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoLock.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
|
@ -91,10 +92,14 @@ protected:
|
|||
|
||||
sqlite3 *mDBConn;
|
||||
nsCOMPtr<nsIFile> mDatabaseFile;
|
||||
|
||||
PRLock *mTransactionMutex;
|
||||
PRBool mTransactionInProgress;
|
||||
|
||||
PRLock *mFunctionsMutex;
|
||||
nsInterfaceHashtable<nsCStringHashKey, nsISupports> mFunctions;
|
||||
|
||||
PRLock *mProgressHandlerMutex;
|
||||
nsCOMPtr<mozIStorageProgressHandler> mProgressHandler;
|
||||
|
||||
// This isn't accessed but is used to make sure that the connections do
|
||||
|
|
Загрузка…
Ссылка в новой задаче