зеркало из https://github.com/mozilla/gecko-dev.git
Bug 702559 - First implementation of mozIStorageAsyncConnection;r=mak
This commit is contained in:
Родитель
11769462ee
Коммит
198d5dbf1f
|
@ -242,7 +242,7 @@ CloseDatabaseListener::CloseDatabaseListener(nsPermissionManager* aManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CloseDatabaseListener::Complete()
|
CloseDatabaseListener::Complete(nsresult, nsISupports*)
|
||||||
{
|
{
|
||||||
// Help breaking cycles
|
// Help breaking cycles
|
||||||
nsRefPtr<nsPermissionManager> manager = mManager.forget();
|
nsRefPtr<nsPermissionManager> manager = mManager.forget();
|
||||||
|
|
|
@ -559,7 +559,7 @@ public:
|
||||||
nsRefPtr<DBState> mDBState;
|
nsRefPtr<DBState> mDBState;
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
NS_IMETHOD Complete()
|
NS_IMETHOD Complete(nsresult, nsISupports*)
|
||||||
{
|
{
|
||||||
gCookieService->HandleDBClosed(mDBState);
|
gCookieService->HandleDBClosed(mDBState);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
XPIDL_SOURCES += [
|
XPIDL_SOURCES += [
|
||||||
'mozIStorageAggregateFunction.idl',
|
'mozIStorageAggregateFunction.idl',
|
||||||
|
'mozIStorageAsyncConnection.idl',
|
||||||
'mozIStorageAsyncStatement.idl',
|
'mozIStorageAsyncStatement.idl',
|
||||||
'mozIStorageBaseStatement.idl',
|
'mozIStorageBaseStatement.idl',
|
||||||
'mozIStorageBindingParams.idl',
|
'mozIStorageBindingParams.idl',
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
/* -*- Mode: idl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
|
interface mozIStorageAggregateFunction;
|
||||||
|
interface mozIStorageCompletionCallback;
|
||||||
|
interface mozIStorageFunction;
|
||||||
|
interface mozIStorageProgressHandler;
|
||||||
|
interface mozIStorageBaseStatement;
|
||||||
|
interface mozIStorageStatement;
|
||||||
|
interface mozIStorageAsyncStatement;
|
||||||
|
interface mozIStorageStatementCallback;
|
||||||
|
interface mozIStoragePendingStatement;
|
||||||
|
interface nsIFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mozIStorageAsyncConnection represents an asynchronous database
|
||||||
|
* connection attached to a specific file or to an in-memory data
|
||||||
|
* storage. It is the primary interface for interacting with a
|
||||||
|
* database from the main thread, including creating prepared
|
||||||
|
* statements, executing SQL, and examining database errors.
|
||||||
|
*/
|
||||||
|
[scriptable, uuid(0e661a1d-27ff-4e6b-ac5a-126314cef61a)]
|
||||||
|
interface mozIStorageAsyncConnection : nsISupports {
|
||||||
|
/**
|
||||||
|
* Close this database connection, allowing all pending statements
|
||||||
|
* to complete first.
|
||||||
|
*
|
||||||
|
* @param aCallback [optional]
|
||||||
|
* A callback that will be notified when the close is completed,
|
||||||
|
* with the following arguments:
|
||||||
|
* - status: the status of the call
|
||||||
|
* - value: |null|
|
||||||
|
*
|
||||||
|
* @throws NS_ERROR_NOT_SAME_THREAD
|
||||||
|
* If is called on a thread other than the one that opened it.
|
||||||
|
*/
|
||||||
|
void asyncClose([optional] in mozIStorageCompletionCallback aCallback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone a database and make the clone read only if needed.
|
||||||
|
*
|
||||||
|
* @param aReadOnly
|
||||||
|
* If true, the returned database should be put into read-only mode.
|
||||||
|
*
|
||||||
|
* @param aCallback
|
||||||
|
* A callback that will be notified when the operation is complete,
|
||||||
|
* with the following arguments:
|
||||||
|
* - status: the status of the operation
|
||||||
|
* - value: in case of success, an intance of
|
||||||
|
* mozIStorageAsyncConnection cloned from this one.
|
||||||
|
*
|
||||||
|
* @throws NS_ERROR_NOT_SAME_THREAD
|
||||||
|
* If is called on a thread other than the one that opened it.
|
||||||
|
* @throws NS_ERROR_UNEXPECTED
|
||||||
|
* If this connection is a memory database.
|
||||||
|
*
|
||||||
|
* @note If your connection is already read-only, you will get a read-only
|
||||||
|
* clone.
|
||||||
|
* @note Due to a bug in SQLite, if you use the shared cache
|
||||||
|
* (see mozIStorageService), you end up with the same privileges as the
|
||||||
|
* first connection opened regardless of what is specified in aReadOnly.
|
||||||
|
* @note The following pragmas are copied over to a read-only clone:
|
||||||
|
* - cache_size
|
||||||
|
* - temp_store
|
||||||
|
* The following pragmas are copied over to a writeable clone:
|
||||||
|
* - cache_size
|
||||||
|
* - temp_store
|
||||||
|
* - foreign_keys
|
||||||
|
* - journal_size_limit
|
||||||
|
* - synchronous
|
||||||
|
* - wal_autocheckpoint
|
||||||
|
*/
|
||||||
|
void asyncClone(in boolean aReadOnly,
|
||||||
|
in mozIStorageCompletionCallback aCallback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current database nsIFile. Null if the database
|
||||||
|
* connection refers to an in-memory database.
|
||||||
|
*/
|
||||||
|
readonly attribute nsIFile databaseFile;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//// Statement creation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an asynchronous statement for the given SQL. An
|
||||||
|
* asynchronous statement can only be used to dispatch asynchronous
|
||||||
|
* requests to the asynchronous execution thread and cannot be used
|
||||||
|
* to take any synchronous actions on the database.
|
||||||
|
*
|
||||||
|
* The expression may use ? to indicate sequential numbered arguments,
|
||||||
|
* ?1, ?2 etc. to indicate specific numbered arguments or :name and
|
||||||
|
* $var to indicate named arguments.
|
||||||
|
*
|
||||||
|
* @param aSQLStatement
|
||||||
|
* The SQL statement to execute.
|
||||||
|
* @return a new mozIStorageAsyncStatement
|
||||||
|
* @note The statement is created lazily on first execution.
|
||||||
|
*/
|
||||||
|
mozIStorageAsyncStatement createAsyncStatement(in AUTF8String aSQLStatement);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute an array of statements created with this connection using
|
||||||
|
* any currently bound parameters. When the array contains multiple
|
||||||
|
* statements, the execution is wrapped in a single
|
||||||
|
* transaction. These statements can be reused immediately, and
|
||||||
|
* reset does not need to be called.
|
||||||
|
*
|
||||||
|
* @param aStatements
|
||||||
|
* The array of statements to execute asynchronously, in the order they
|
||||||
|
* are given in the array.
|
||||||
|
* @param aNumStatements
|
||||||
|
* The number of statements in aStatements.
|
||||||
|
* @param aCallback [optional]
|
||||||
|
* The callback object that will be notified of progress, errors, and
|
||||||
|
* completion.
|
||||||
|
* @return an object that can be used to cancel the statements execution.
|
||||||
|
*
|
||||||
|
* @note If you have any custom defined functions, they must be
|
||||||
|
* re-entrant since they can be called on multiple threads.
|
||||||
|
*/
|
||||||
|
mozIStoragePendingStatement executeAsync(
|
||||||
|
[array, size_is(aNumStatements)] in mozIStorageBaseStatement aStatements,
|
||||||
|
in unsigned long aNumStatements,
|
||||||
|
[optional] in mozIStorageStatementCallback aCallback
|
||||||
|
);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//// Functions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 -1 for
|
||||||
|
* variable-argument functions.
|
||||||
|
* @param aFunction
|
||||||
|
* The instance of mozIStorageFunction, which implements the function
|
||||||
|
* in question.
|
||||||
|
*/
|
||||||
|
void createFunction(in AUTF8String aFunctionName,
|
||||||
|
in long aNumArguments,
|
||||||
|
in mozIStorageFunction aFunction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @param aNumArguments
|
||||||
|
* The number of arguments the function takes. Pass -1 for
|
||||||
|
* variable-argument functions.
|
||||||
|
* @param aFunction
|
||||||
|
* The instance of mozIStorageAggreagteFunction, which implements the
|
||||||
|
* function in question.
|
||||||
|
*/
|
||||||
|
void createAggregateFunction(in AUTF8String aFunctionName,
|
||||||
|
in long aNumArguments,
|
||||||
|
in mozIStorageAggregateFunction aFunction);
|
||||||
|
/**
|
||||||
|
* Delete custom SQL function (simple or aggregate one).
|
||||||
|
*
|
||||||
|
* @param aFunctionName
|
||||||
|
* The name of function to remove.
|
||||||
|
*/
|
||||||
|
void removeFunction(in AUTF8String aFunctionName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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. 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.
|
||||||
|
* @param aHandler
|
||||||
|
* The instance of mozIStorageProgressHandler.
|
||||||
|
* @return previous registered handler.
|
||||||
|
*/
|
||||||
|
mozIStorageProgressHandler setProgressHandler(in int32_t aGranularity,
|
||||||
|
in mozIStorageProgressHandler aHandler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a progress handler.
|
||||||
|
*
|
||||||
|
* @return previous registered handler.
|
||||||
|
*/
|
||||||
|
mozIStorageProgressHandler removeProgressHandler();
|
||||||
|
};
|
|
@ -6,10 +6,19 @@
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
[scriptable,function, uuid(0bfee0c4-2c24-400e-b18e-b5bb41a032c8)]
|
[scriptable, function, uuid(8cbf2dc2-91e0-44bc-984f-553638412071)]
|
||||||
interface mozIStorageCompletionCallback : nsISupports {
|
interface mozIStorageCompletionCallback : nsISupports {
|
||||||
/**
|
/**
|
||||||
* Indicates that the event this callback was passed in for has completed.
|
* Indicates that the event this callback was passed in for has completed.
|
||||||
|
*
|
||||||
|
* @param status
|
||||||
|
* The status of the call. Generally NS_OK if the operation
|
||||||
|
* completed successfully.
|
||||||
|
* @param value
|
||||||
|
* If the operation produces a result, the result. Otherwise,
|
||||||
|
* |null|.
|
||||||
|
*
|
||||||
|
* @see The calling method for expected values.
|
||||||
*/
|
*/
|
||||||
void complete();
|
void complete(in nsresult status, [optional] in nsISupports value);
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
#include "mozIStorageAsyncConnection.idl"
|
||||||
|
|
||||||
interface mozIStorageAggregateFunction;
|
interface mozIStorageAggregateFunction;
|
||||||
interface mozIStorageCompletionCallback;
|
interface mozIStorageCompletionCallback;
|
||||||
|
@ -23,10 +24,12 @@ interface nsIFile;
|
||||||
* creating prepared statements, executing SQL, and examining database
|
* creating prepared statements, executing SQL, and examining database
|
||||||
* errors.
|
* errors.
|
||||||
*
|
*
|
||||||
|
* @note From the main thread, you should rather use mozIStorageAsyncConnection.
|
||||||
|
*
|
||||||
* @threadsafe
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(c8646e4b-3e2d-4df3-98a9-e2bbf74f279c)]
|
[scriptable, uuid(4aa2ac47-8d24-4004-9b31-ec0bd85f0cc3)]
|
||||||
interface mozIStorageConnection : nsISupports {
|
interface mozIStorageConnection : mozIStorageAsyncConnection {
|
||||||
/**
|
/**
|
||||||
* Closes a database connection. Callers must finalize all statements created
|
* Closes a database connection. Callers must finalize all statements created
|
||||||
* for this connection prior to calling this method. It is illegal to use
|
* for this connection prior to calling this method. It is illegal to use
|
||||||
|
@ -41,20 +44,15 @@ interface mozIStorageConnection : nsISupports {
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously closes a database connection, allowing all pending
|
* Clones a database connection and makes the clone read only if needed.
|
||||||
* asynchronous statements to complete first.
|
|
||||||
*
|
*
|
||||||
* @param aCallback [optional]
|
* @param aReadOnly
|
||||||
* A callback that will be notified when the close is completed.
|
* If true, the returned database should be put into read-only mode.
|
||||||
|
* Defaults to false.
|
||||||
|
* @return the cloned database connection.
|
||||||
*
|
*
|
||||||
* @throws NS_ERROR_UNEXPECTED
|
* @throws NS_ERROR_UNEXPECTED
|
||||||
* If is called on a thread other than the one that opened it.
|
* If this connection is a memory database.
|
||||||
*/
|
|
||||||
void asyncClose([optional] in mozIStorageCompletionCallback aCallback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clones a database and makes the clone read only if needed.
|
|
||||||
*
|
|
||||||
* @note If your connection is already read-only, you will get a read-only
|
* @note If your connection is already read-only, you will get a read-only
|
||||||
* clone.
|
* clone.
|
||||||
* @note Due to a bug in SQLite, if you use the shared cache (openDatabase),
|
* @note Due to a bug in SQLite, if you use the shared cache (openDatabase),
|
||||||
|
@ -71,13 +69,6 @@ interface mozIStorageConnection : nsISupports {
|
||||||
* - synchronous
|
* - synchronous
|
||||||
* - wal_autocheckpoint
|
* - wal_autocheckpoint
|
||||||
*
|
*
|
||||||
* @throws NS_ERROR_UNEXPECTED
|
|
||||||
* If this connection is a memory database.
|
|
||||||
*
|
|
||||||
* @param aReadOnly
|
|
||||||
* If true, the returned database should be put into read-only mode.
|
|
||||||
* Defaults to false.
|
|
||||||
* @return the cloned database connection.
|
|
||||||
*/
|
*/
|
||||||
mozIStorageConnection clone([optional] in boolean aReadOnly);
|
mozIStorageConnection clone([optional] in boolean aReadOnly);
|
||||||
|
|
||||||
|
@ -93,12 +84,6 @@ interface mozIStorageConnection : nsISupports {
|
||||||
*/
|
*/
|
||||||
readonly attribute boolean connectionReady;
|
readonly attribute boolean connectionReady;
|
||||||
|
|
||||||
/**
|
|
||||||
* The current database nsIFile. Null if the database
|
|
||||||
* connection refers to an in-memory database.
|
|
||||||
*/
|
|
||||||
readonly attribute nsIFile databaseFile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lastInsertRowID returns the row ID from the last INSERT
|
* lastInsertRowID returns the row ID from the last INSERT
|
||||||
* operation.
|
* operation.
|
||||||
|
@ -143,22 +128,6 @@ interface mozIStorageConnection : nsISupports {
|
||||||
*/
|
*/
|
||||||
mozIStorageStatement createStatement(in AUTF8String aSQLStatement);
|
mozIStorageStatement createStatement(in AUTF8String aSQLStatement);
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an asynchronous statement (mozIStorageAsyncStatement) for the given
|
|
||||||
* SQL expression. An asynchronous statement can only be used to dispatch
|
|
||||||
* asynchronous requests to the asynchronous execution thread and cannot be
|
|
||||||
* used to take any synchronous actions on the database.
|
|
||||||
*
|
|
||||||
* The expression may use ? to indicate sequential numbered arguments,
|
|
||||||
* ?1, ?2 etc. to indicate specific numbered arguments or :name and
|
|
||||||
* $var to indicate named arguments.
|
|
||||||
*
|
|
||||||
* @param aSQLStatement
|
|
||||||
* The SQL statement to execute.
|
|
||||||
* @return a new mozIStorageAsyncStatement
|
|
||||||
*/
|
|
||||||
mozIStorageAsyncStatement createAsyncStatement(in AUTF8String aSQLStatement);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a SQL expression, expecting no arguments.
|
* Execute a SQL expression, expecting no arguments.
|
||||||
*
|
*
|
||||||
|
@ -166,31 +135,6 @@ interface mozIStorageConnection : nsISupports {
|
||||||
*/
|
*/
|
||||||
void executeSimpleSQL(in AUTF8String aSQLStatement);
|
void executeSimpleSQL(in AUTF8String aSQLStatement);
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an array of queries created with this connection asynchronously
|
|
||||||
* using any currently bound parameters. The statements are ran wrapped in a
|
|
||||||
* transaction. These statements can be reused immediately, and reset does
|
|
||||||
* not need to be called.
|
|
||||||
*
|
|
||||||
* Note: If you have any custom defined functions, they must be re-entrant
|
|
||||||
* since they can be called on multiple threads.
|
|
||||||
*
|
|
||||||
* @param aStatements
|
|
||||||
* The array of statements to execute asynchronously, in the order they
|
|
||||||
* are given in the array.
|
|
||||||
* @param aNumStatements
|
|
||||||
* The number of statements in aStatements.
|
|
||||||
* @param aCallback [optional]
|
|
||||||
* The callback object that will be notified of progress, errors, and
|
|
||||||
* completion.
|
|
||||||
* @return an object that can be used to cancel the statements execution.
|
|
||||||
*/
|
|
||||||
mozIStoragePendingStatement executeAsync(
|
|
||||||
[array, size_is(aNumStatements)] in mozIStorageBaseStatement aStatements,
|
|
||||||
in unsigned long aNumStatements,
|
|
||||||
[optional] in mozIStorageStatementCallback aCallback
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the given table exists.
|
* Check if the given table exists.
|
||||||
*
|
*
|
||||||
|
@ -268,75 +212,6 @@ interface mozIStorageConnection : nsISupports {
|
||||||
void createTable(in string aTableName,
|
void createTable(in string aTableName,
|
||||||
in string aTableSchema);
|
in string aTableSchema);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//// Functions
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 -1 for
|
|
||||||
* variable-argument functions.
|
|
||||||
* @param aFunction
|
|
||||||
* The instance of mozIStorageFunction, which implements the function
|
|
||||||
* in question.
|
|
||||||
*/
|
|
||||||
void createFunction(in AUTF8String aFunctionName,
|
|
||||||
in long aNumArguments,
|
|
||||||
in mozIStorageFunction aFunction);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
* @param aNumArguments
|
|
||||||
* The number of arguments the function takes. Pass -1 for
|
|
||||||
* variable-argument functions.
|
|
||||||
* @param aFunction
|
|
||||||
* The instance of mozIStorageAggreagteFunction, which implements the
|
|
||||||
* function in question.
|
|
||||||
*/
|
|
||||||
void createAggregateFunction(in AUTF8String aFunctionName,
|
|
||||||
in long aNumArguments,
|
|
||||||
in mozIStorageAggregateFunction aFunction);
|
|
||||||
/**
|
|
||||||
* Delete custom SQL function (simple or aggregate one).
|
|
||||||
*
|
|
||||||
* @param aFunctionName
|
|
||||||
* The name of function to remove.
|
|
||||||
*/
|
|
||||||
void removeFunction(in AUTF8String aFunctionName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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. 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.
|
|
||||||
* @param aHandler
|
|
||||||
* The instance of mozIStorageProgressHandler.
|
|
||||||
* @return previous registered handler.
|
|
||||||
*/
|
|
||||||
mozIStorageProgressHandler setProgressHandler(in int32_t aGranularity,
|
|
||||||
in mozIStorageProgressHandler aHandler);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a progress handler.
|
|
||||||
*
|
|
||||||
* @return previous registered handler.
|
|
||||||
*/
|
|
||||||
mozIStorageProgressHandler removeProgressHandler();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls SQLITE_FCNTL_CHUNK_SIZE setting in sqlite. This helps avoid fragmentation
|
* Controls SQLITE_FCNTL_CHUNK_SIZE setting in sqlite. This helps avoid fragmentation
|
||||||
* by growing/shrinking the database file in SQLITE_FCNTL_CHUNK_SIZE increments. To
|
* by growing/shrinking the database file in SQLITE_FCNTL_CHUNK_SIZE increments. To
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
interface mozIStorageConnection;
|
interface mozIStorageConnection;
|
||||||
interface nsIFile;
|
interface nsIFile;
|
||||||
interface nsIFileURL;
|
interface nsIFileURL;
|
||||||
|
interface nsIPropertyBag2;
|
||||||
|
interface nsIVariant;
|
||||||
|
interface mozIStorageCompletionCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The mozIStorageService interface is intended to be implemented by
|
* The mozIStorageService interface is intended to be implemented by
|
||||||
|
@ -19,8 +22,56 @@ interface nsIFileURL;
|
||||||
* @note The first reference to mozIStorageService must be made on the main
|
* @note The first reference to mozIStorageService must be made on the main
|
||||||
* thread.
|
* thread.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(12bfad34-cca3-40fb-8736-d8bf9db61a27)]
|
[scriptable, uuid(07b6b2f5-6d97-47b4-9584-e65bc467fe9e)]
|
||||||
interface mozIStorageService : nsISupports {
|
interface mozIStorageService : nsISupports {
|
||||||
|
/**
|
||||||
|
* Open an asynchronous connection to a database.
|
||||||
|
*
|
||||||
|
* This method MUST be called from the main thread. The connection object
|
||||||
|
* returned by this function is not threadsafe. You MUST use it only from
|
||||||
|
* the main thread.
|
||||||
|
*
|
||||||
|
* If you have more than one connection to a file, you MUST use the EXACT
|
||||||
|
* SAME NAME for the file each time, including case. The sqlite code uses
|
||||||
|
* a simple string compare to see if there is already a connection. Opening
|
||||||
|
* a connection to "Foo.sqlite" and "foo.sqlite" will CORRUPT YOUR DATABASE.
|
||||||
|
*
|
||||||
|
* @param aDatabaseStore Either a nsIFile representing the file that contains
|
||||||
|
* the database or a special string to open a special database. The special
|
||||||
|
* string may be:
|
||||||
|
* - "memory" to open an in-memory database.
|
||||||
|
*
|
||||||
|
* @param aOptions A set of options (may be null). Options may contain:
|
||||||
|
* - bool shared (defaults to |false|).
|
||||||
|
* -- If |true|, opens the database with a shared-cache. The
|
||||||
|
* shared-cache mode is more memory-efficient when many
|
||||||
|
* connections to the same database are expected, though, the
|
||||||
|
* connections will contend the cache resource. In any cases
|
||||||
|
* where performance matter, working without a shared-cache will
|
||||||
|
* improve concurrency. @see openUnsharedDatabase
|
||||||
|
*
|
||||||
|
* - int growthIncrement (defaults to none).
|
||||||
|
* -- Set the growth increment for the main database. This hints SQLite to
|
||||||
|
* grow the database file by a given chunk size and may reduce
|
||||||
|
* filesystem fragmentation on large databases.
|
||||||
|
* @see mozIStorageConnection::setGrowthIncrement
|
||||||
|
*
|
||||||
|
* @param aCallback A callback that will receive the result of the operation.
|
||||||
|
* In case of error, it may receive as status:
|
||||||
|
* - NS_ERROR_OUT_OF_MEMORY if allocating a new storage object fails.
|
||||||
|
* - NS_ERROR_FILE_CORRUPTED if the database file is corrupted.
|
||||||
|
* In case of success, it receives as argument the new database
|
||||||
|
* connection, as an instance of |mozIStorageAsyncConnection|.
|
||||||
|
*
|
||||||
|
* @throws NS_ERROR_INVALID_ARG if |aDatabaseStore| is neither a file nor
|
||||||
|
* one of the special strings understood by this method, or if one of
|
||||||
|
* the options passed through |aOptions| does not have the right type.
|
||||||
|
* @throws NS_ERROR_NOT_SAME_THREAD if called from a thread other than the
|
||||||
|
* main thread.
|
||||||
|
*/
|
||||||
|
void openAsyncDatabase(in nsIVariant aDatabaseStore,
|
||||||
|
[optional] in nsIPropertyBag2 aOptions,
|
||||||
|
in mozIStorageCompletionCallback aCallback);
|
||||||
/**
|
/**
|
||||||
* Get a connection to a named special database storage.
|
* Get a connection to a named special database storage.
|
||||||
*
|
*
|
||||||
|
@ -58,12 +109,6 @@ interface mozIStorageService : nsISupports {
|
||||||
* The connection object returned by this function is not threadsafe. You must
|
* The connection object returned by this function is not threadsafe. You must
|
||||||
* use it only from the thread you created it from.
|
* use it only from the thread you created it from.
|
||||||
*
|
*
|
||||||
* If your database contains virtual tables (f.e. for full-text indexes), you
|
|
||||||
* must open it with openUnsharedDatabase, as those tables are incompatible
|
|
||||||
* with a shared cache. If you attempt to use this method to open a database
|
|
||||||
* containing virtual tables, it will think the database is corrupted and
|
|
||||||
* throw NS_ERROR_FILE_CORRUPTED.
|
|
||||||
*
|
|
||||||
* @param aDatabaseFile
|
* @param aDatabaseFile
|
||||||
* A nsIFile that represents the database that is to be opened..
|
* A nsIFile that represents the database that is to be opened..
|
||||||
*
|
*
|
||||||
|
@ -79,12 +124,11 @@ interface mozIStorageService : nsISupports {
|
||||||
/**
|
/**
|
||||||
* Open a connection to the specified file that doesn't share a sqlite cache.
|
* Open a connection to the specified file that doesn't share a sqlite cache.
|
||||||
*
|
*
|
||||||
* Each connection uses its own sqlite cache, which is inefficient, so you
|
* Without a shared-cache, each connection uses its own pages cache, which
|
||||||
* should use openDatabase instead of this method unless you need a feature
|
* may be memory inefficient with a large number of connections, in such a
|
||||||
* of SQLite that is incompatible with a shared cache, like virtual table
|
* case so you should use openDatabase instead. On the other side, if cache
|
||||||
* and full text indexing support. If cache contention is expected, for
|
* contention may be an issue, for instance when concurrency is important to
|
||||||
* instance when operating on a database from multiple threads, using
|
* ensure responsiveness, using unshared connections may be a performance win.
|
||||||
* unshared connections may be a performance win.
|
|
||||||
*
|
*
|
||||||
* ==========
|
* ==========
|
||||||
* DANGER
|
* DANGER
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "mozIStorageVacuumParticipant.h"
|
#include "mozIStorageVacuumParticipant.h"
|
||||||
#include "mozIStorageCompletionCallback.h"
|
#include "mozIStorageCompletionCallback.h"
|
||||||
#include "mozIStorageAsyncStatement.h"
|
#include "mozIStorageAsyncStatement.h"
|
||||||
|
#include "mozIStorageAsyncConnection.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Native Language Helpers
|
//// Native Language Helpers
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
#include "prlog.h"
|
#include "prlog.h"
|
||||||
#include "prprf.h"
|
#include "prprf.h"
|
||||||
|
#include "nsProxyRelease.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#define MIN_AVAILABLE_BYTES_PER_CHUNKED_GROWTH 524288000 // 500 MiB
|
#define MIN_AVAILABLE_BYTES_PER_CHUNKED_GROWTH 524288000 // 500 MiB
|
||||||
|
@ -364,6 +365,7 @@ public:
|
||||||
(void)mConnection->internalClose();
|
(void)mConnection->internalClose();
|
||||||
if (mCallbackEvent)
|
if (mCallbackEvent)
|
||||||
(void)mCallingThread->Dispatch(mCallbackEvent, NS_DISPATCH_NORMAL);
|
(void)mCallingThread->Dispatch(mCallbackEvent, NS_DISPATCH_NORMAL);
|
||||||
|
|
||||||
(void)mAsyncExecutionThread->Shutdown();
|
(void)mAsyncExecutionThread->Shutdown();
|
||||||
|
|
||||||
// Because we have no guarantee that the invocation of this method on the
|
// Because we have no guarantee that the invocation of this method on the
|
||||||
|
@ -387,13 +389,91 @@ private:
|
||||||
nsCOMPtr<nsIThread> mAsyncExecutionThread;
|
nsCOMPtr<nsIThread> mAsyncExecutionThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event used to initialize the clone of a connection.
|
||||||
|
*
|
||||||
|
* Must be executed on the clone's async execution thread.
|
||||||
|
*/
|
||||||
|
class AsyncInitializeClone MOZ_FINAL: public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @param aConnection The connection being cloned.
|
||||||
|
* @param aClone The clone.
|
||||||
|
* @param aReadOnly If |true|, the clone is read only.
|
||||||
|
* @param aCallback A callback to trigger once initialization
|
||||||
|
* is complete. This event will be called on
|
||||||
|
* aClone->threadOpenedOn.
|
||||||
|
*/
|
||||||
|
AsyncInitializeClone(Connection* aConnection,
|
||||||
|
Connection* aClone,
|
||||||
|
const bool aReadOnly,
|
||||||
|
mozIStorageCompletionCallback* aCallback)
|
||||||
|
: mConnection(aConnection)
|
||||||
|
, mClone(aClone)
|
||||||
|
, mReadOnly(aReadOnly)
|
||||||
|
, mCallback(aCallback)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD Run() {
|
||||||
|
MOZ_ASSERT (NS_GetCurrentThread() == mClone->getAsyncExecutionTarget());
|
||||||
|
|
||||||
|
nsresult rv = mConnection->initializeClone(mClone, mReadOnly);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return Dispatch(rv, nullptr);
|
||||||
|
}
|
||||||
|
return Dispatch(NS_OK,
|
||||||
|
NS_ISUPPORTS_CAST(mozIStorageAsyncConnection*, mClone));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsresult Dispatch(nsresult aResult, nsISupports* aValue) {
|
||||||
|
nsRefPtr<CallbackComplete> event = new CallbackComplete(aResult,
|
||||||
|
aValue,
|
||||||
|
mCallback.forget());
|
||||||
|
return mClone->threadOpenedOn->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncInitializeClone() {
|
||||||
|
nsCOMPtr<nsIThread> thread;
|
||||||
|
DebugOnly<nsresult> rv = NS_GetMainThread(getter_AddRefs(thread));
|
||||||
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||||
|
|
||||||
|
// Handle ambiguous nsISupports inheritance.
|
||||||
|
Connection *rawConnection = nullptr;
|
||||||
|
mConnection.swap(rawConnection);
|
||||||
|
(void)NS_ProxyRelease(thread, NS_ISUPPORTS_CAST(mozIStorageConnection *,
|
||||||
|
rawConnection));
|
||||||
|
|
||||||
|
Connection *rawClone = nullptr;
|
||||||
|
mClone.swap(rawClone);
|
||||||
|
(void)NS_ProxyRelease(thread, NS_ISUPPORTS_CAST(mozIStorageConnection *,
|
||||||
|
rawClone));
|
||||||
|
|
||||||
|
// Generally, the callback will be released by CallbackComplete.
|
||||||
|
// However, if for some reason Run() is not executed, we still
|
||||||
|
// need to ensure that it is released here.
|
||||||
|
mozIStorageCompletionCallback *rawCallback = nullptr;
|
||||||
|
mCallback.swap(rawCallback);
|
||||||
|
(void)NS_ProxyRelease(thread, rawCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<Connection> mConnection;
|
||||||
|
nsRefPtr<Connection> mClone;
|
||||||
|
const bool mReadOnly;
|
||||||
|
nsCOMPtr<mozIStorageCompletionCallback> mCallback;
|
||||||
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Connection
|
//// Connection
|
||||||
|
|
||||||
Connection::Connection(Service *aService,
|
Connection::Connection(Service *aService,
|
||||||
int aFlags)
|
int aFlags,
|
||||||
|
bool aAsyncOnly)
|
||||||
: sharedAsyncExecutionMutex("Connection::sharedAsyncExecutionMutex")
|
: sharedAsyncExecutionMutex("Connection::sharedAsyncExecutionMutex")
|
||||||
, sharedDBMutex("Connection::sharedDBMutex")
|
, sharedDBMutex("Connection::sharedDBMutex")
|
||||||
, threadOpenedOn(do_GetCurrentThread())
|
, threadOpenedOn(do_GetCurrentThread())
|
||||||
|
@ -403,6 +483,7 @@ Connection::Connection(Service *aService,
|
||||||
, mProgressHandler(nullptr)
|
, mProgressHandler(nullptr)
|
||||||
, mFlags(aFlags)
|
, mFlags(aFlags)
|
||||||
, mStorageService(aService)
|
, mStorageService(aService)
|
||||||
|
, mAsyncOnly(aAsyncOnly)
|
||||||
{
|
{
|
||||||
mFunctions.Init();
|
mFunctions.Init();
|
||||||
mStorageService->registerConnection(this);
|
mStorageService->registerConnection(this);
|
||||||
|
@ -412,15 +493,18 @@ Connection::~Connection()
|
||||||
{
|
{
|
||||||
(void)Close();
|
(void)Close();
|
||||||
|
|
||||||
MOZ_ASSERT(!mAsyncExecutionThread);
|
MOZ_ASSERT(!mAsyncExecutionThread,
|
||||||
|
"AsyncClose has not been invoked on this connection!");
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_THREADSAFE_ADDREF(Connection)
|
NS_IMPL_THREADSAFE_ADDREF(Connection)
|
||||||
NS_IMPL_THREADSAFE_QUERY_INTERFACE2(
|
|
||||||
Connection,
|
NS_INTERFACE_MAP_BEGIN(Connection)
|
||||||
mozIStorageConnection,
|
NS_INTERFACE_MAP_ENTRY(mozIStorageAsyncConnection)
|
||||||
nsIInterfaceRequestor
|
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||||
)
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(mozIStorageConnection, !mAsyncOnly)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozIStorageConnection)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
// This is identical to what NS_IMPL_THREADSAFE_RELEASE provides, but with the
|
// This is identical to what NS_IMPL_THREADSAFE_RELEASE provides, but with the
|
||||||
// extra |1 == count| case.
|
// extra |1 == count| case.
|
||||||
|
@ -436,8 +520,9 @@ NS_IMETHODIMP_(nsrefcnt) Connection::Release(void)
|
||||||
mStorageService->unregisterConnection(this);
|
mStorageService->unregisterConnection(this);
|
||||||
} else if (0 == count) {
|
} else if (0 == count) {
|
||||||
mRefCnt = 1; /* stabilize */
|
mRefCnt = 1; /* stabilize */
|
||||||
/* enable this to find non-threadsafe destructors: */
|
#if 0 /* enable this to find non-threadsafe destructors: */
|
||||||
/* NS_ASSERT_OWNINGTHREAD(Connection); */
|
NS_ASSERT_OWNINGTHREAD(Connection);
|
||||||
|
#endif
|
||||||
delete (this);
|
delete (this);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -952,6 +1037,9 @@ Connection::Close()
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
Connection::AsyncClose(mozIStorageCompletionCallback *aCallback)
|
Connection::AsyncClose(mozIStorageCompletionCallback *aCallback)
|
||||||
{
|
{
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
return NS_ERROR_NOT_SAME_THREAD;
|
||||||
|
}
|
||||||
if (!mDBConn)
|
if (!mDBConn)
|
||||||
return NS_ERROR_NOT_INITIALIZED;
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
|
||||||
|
@ -984,10 +1072,13 @@ Connection::AsyncClose(mozIStorageCompletionCallback *aCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
Connection::Clone(bool aReadOnly,
|
Connection::AsyncClone(bool aReadOnly,
|
||||||
mozIStorageConnection **_connection)
|
mozIStorageCompletionCallback *aCallback)
|
||||||
{
|
{
|
||||||
PROFILER_LABEL("storage", "Connection::Clone");
|
PROFILER_LABEL("storage", "Connection::Clone");
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
return NS_ERROR_NOT_SAME_THREAD;
|
||||||
|
}
|
||||||
if (!mDBConn)
|
if (!mDBConn)
|
||||||
return NS_ERROR_NOT_INITIALIZED;
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
if (!mDatabaseFile)
|
if (!mDatabaseFile)
|
||||||
|
@ -1000,12 +1091,27 @@ Connection::Clone(bool aReadOnly,
|
||||||
// Turn off SQLITE_OPEN_CREATE.
|
// Turn off SQLITE_OPEN_CREATE.
|
||||||
flags = (~SQLITE_OPEN_CREATE & flags);
|
flags = (~SQLITE_OPEN_CREATE & flags);
|
||||||
}
|
}
|
||||||
nsRefPtr<Connection> clone = new Connection(mStorageService, flags);
|
|
||||||
NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY);
|
|
||||||
|
|
||||||
nsresult rv = mFileURL ? clone->initialize(mFileURL)
|
nsRefPtr<Connection> clone = new Connection(mStorageService, flags,
|
||||||
: clone->initialize(mDatabaseFile);
|
mAsyncOnly);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
nsRefPtr<AsyncInitializeClone> initEvent =
|
||||||
|
new AsyncInitializeClone(this, clone, aReadOnly, aCallback);
|
||||||
|
nsCOMPtr<nsIEventTarget> target = clone->getAsyncExecutionTarget();
|
||||||
|
if (!target) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
return target->Dispatch(initEvent, NS_DISPATCH_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
Connection::initializeClone(Connection* aClone, bool aReadOnly)
|
||||||
|
{
|
||||||
|
nsresult rv = mFileURL ? aClone->initialize(mFileURL)
|
||||||
|
: aClone->initialize(mDatabaseFile);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
// Copy over pragmas from the original connection.
|
// Copy over pragmas from the original connection.
|
||||||
static const char * pragmas[] = {
|
static const char * pragmas[] = {
|
||||||
|
@ -1032,16 +1138,47 @@ Connection::Clone(bool aReadOnly,
|
||||||
if (stmt && NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
|
if (stmt && NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
|
||||||
pragmaQuery.AppendLiteral(" = ");
|
pragmaQuery.AppendLiteral(" = ");
|
||||||
pragmaQuery.AppendInt(stmt->AsInt32(0));
|
pragmaQuery.AppendInt(stmt->AsInt32(0));
|
||||||
rv = clone->ExecuteSimpleSQL(pragmaQuery);
|
rv = aClone->ExecuteSimpleSQL(pragmaQuery);
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy any functions that have been added to this connection.
|
// Copy any functions that have been added to this connection.
|
||||||
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
||||||
(void)mFunctions.EnumerateRead(copyFunctionEnumerator, clone);
|
(void)mFunctions.EnumerateRead(copyFunctionEnumerator, aClone);
|
||||||
|
|
||||||
NS_ADDREF(*_connection = clone);
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
Connection::Clone(bool aReadOnly,
|
||||||
|
mozIStorageConnection **_connection)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(threadOpenedOn == NS_GetCurrentThread());
|
||||||
|
|
||||||
|
PROFILER_LABEL("storage", "Connection::Clone");
|
||||||
|
if (!mDBConn)
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
if (!mDatabaseFile)
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
|
||||||
|
int flags = mFlags;
|
||||||
|
if (aReadOnly) {
|
||||||
|
// Turn off SQLITE_OPEN_READWRITE, and set SQLITE_OPEN_READONLY.
|
||||||
|
flags = (~SQLITE_OPEN_READWRITE & flags) | SQLITE_OPEN_READONLY;
|
||||||
|
// Turn off SQLITE_OPEN_CREATE.
|
||||||
|
flags = (~SQLITE_OPEN_CREATE & flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<Connection> clone = new Connection(mStorageService, flags,
|
||||||
|
mAsyncOnly);
|
||||||
|
|
||||||
|
nsresult rv = initializeClone(clone, aReadOnly);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IF_ADDREF(*_connection = clone);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "mozilla/Mutex.h"
|
#include "mozilla/Mutex.h"
|
||||||
|
#include "nsProxyRelease.h"
|
||||||
|
#include "nsThreadUtils.h"
|
||||||
#include "nsIInterfaceRequestor.h"
|
#include "nsIInterfaceRequestor.h"
|
||||||
|
|
||||||
#include "nsDataHashtable.h"
|
#include "nsDataHashtable.h"
|
||||||
|
@ -17,6 +19,8 @@
|
||||||
#include "SQLiteMutex.h"
|
#include "SQLiteMutex.h"
|
||||||
#include "mozIStorageConnection.h"
|
#include "mozIStorageConnection.h"
|
||||||
#include "mozStorageService.h"
|
#include "mozStorageService.h"
|
||||||
|
#include "mozIStorageAsyncConnection.h"
|
||||||
|
#include "mozIStorageCompletionCallback.h"
|
||||||
|
|
||||||
#include "nsIMutableArray.h"
|
#include "nsIMutableArray.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
|
@ -37,6 +41,7 @@ class Connection MOZ_FINAL : public mozIStorageConnection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_MOZISTORAGEASYNCCONNECTION
|
||||||
NS_DECL_MOZISTORAGECONNECTION
|
NS_DECL_MOZISTORAGECONNECTION
|
||||||
NS_DECL_NSIINTERFACEREQUESTOR
|
NS_DECL_NSIINTERFACEREQUESTOR
|
||||||
|
|
||||||
|
@ -60,8 +65,13 @@ public:
|
||||||
* connection.
|
* connection.
|
||||||
* @param aFlags
|
* @param aFlags
|
||||||
* The flags to pass to sqlite3_open_v2.
|
* The flags to pass to sqlite3_open_v2.
|
||||||
|
* @param aAsyncOnly
|
||||||
|
* If |true|, the Connection only implements asynchronous interface:
|
||||||
|
* - |mozIStorageAsyncConnection|;
|
||||||
|
* If |false|, the result also implements synchronous interface:
|
||||||
|
* - |mozIStorageConnection|.
|
||||||
*/
|
*/
|
||||||
Connection(Service *aService, int aFlags);
|
Connection(Service *aService, int aFlags, bool aAsyncOnly);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the connection to an in-memory database.
|
* Creates the connection to an in-memory database.
|
||||||
|
@ -162,9 +172,11 @@ public:
|
||||||
*/
|
*/
|
||||||
bool isAsyncClosing();
|
bool isAsyncClosing();
|
||||||
|
|
||||||
|
|
||||||
|
nsresult initializeClone(Connection *aClone, bool aReadOnly);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~Connection();
|
~Connection();
|
||||||
|
|
||||||
nsresult initializeInternal(nsIFile *aDatabaseFile);
|
nsresult initializeInternal(nsIFile *aDatabaseFile);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -262,6 +274,54 @@ private:
|
||||||
// connections do not outlive the service. 2) Our custom collating functions
|
// connections do not outlive the service. 2) Our custom collating functions
|
||||||
// call its localeCompareStrings() method.
|
// call its localeCompareStrings() method.
|
||||||
nsRefPtr<Service> mStorageService;
|
nsRefPtr<Service> mStorageService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If |false|, this instance supports synchronous operations
|
||||||
|
* and it can be cast to |mozIStorageConnection|.
|
||||||
|
*/
|
||||||
|
const bool mAsyncOnly;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Runnable designed to call a mozIStorageCompletionCallback on
|
||||||
|
* the appropriate thread.
|
||||||
|
*/
|
||||||
|
class CallbackComplete MOZ_FINAL : public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @param aValue The result to pass to the callback. It must
|
||||||
|
* already be owned by the main thread.
|
||||||
|
* @param aCallback The callback. It must already be owned by the
|
||||||
|
* main thread.
|
||||||
|
*/
|
||||||
|
CallbackComplete(nsresult aStatus,
|
||||||
|
nsISupports* aValue,
|
||||||
|
already_AddRefed<mozIStorageCompletionCallback> aCallback)
|
||||||
|
: mStatus(aStatus)
|
||||||
|
, mValue(aValue)
|
||||||
|
, mCallback(aCallback)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD Run() {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
nsresult rv = mCallback->Complete(mStatus, mValue);
|
||||||
|
|
||||||
|
// Ensure that we release on the main thread
|
||||||
|
mValue = nullptr;
|
||||||
|
mCallback = nullptr;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsresult mStatus;
|
||||||
|
nsCOMPtr<nsISupports> mValue;
|
||||||
|
// This is a nsRefPtr<T> and not a nsCOMPtr<T> because
|
||||||
|
// nsCOMP<T> would cause an off-main thread QI, which
|
||||||
|
// is not a good idea (and crashes XPConnect).
|
||||||
|
nsRefPtr<mozIStorageCompletionCallback> mCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace storage
|
} // namespace storage
|
||||||
|
|
|
@ -161,7 +161,7 @@ public:
|
||||||
|
|
||||||
NS_IMETHOD Run()
|
NS_IMETHOD Run()
|
||||||
{
|
{
|
||||||
(void)mCallback->Complete();
|
(void)mCallback->Complete(NS_OK, nullptr);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -20,9 +20,11 @@
|
||||||
#include "nsILocaleService.h"
|
#include "nsILocaleService.h"
|
||||||
#include "nsIXPConnect.h"
|
#include "nsIXPConnect.h"
|
||||||
#include "nsIObserverService.h"
|
#include "nsIObserverService.h"
|
||||||
|
#include "nsIPropertyBag2.h"
|
||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/mozPoisonWrite.h"
|
#include "mozilla/mozPoisonWrite.h"
|
||||||
|
#include "mozIStorageCompletionCallback.h"
|
||||||
|
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
|
|
||||||
|
@ -644,7 +646,7 @@ Service::OpenSpecialDatabase(const char *aStorageKey,
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<Connection> msc = new Connection(this, SQLITE_OPEN_READWRITE);
|
nsRefPtr<Connection> msc = new Connection(this, SQLITE_OPEN_READWRITE, false);
|
||||||
|
|
||||||
rv = storageFile ? msc->initialize(storageFile) : msc->initialize();
|
rv = storageFile ? msc->initialize(storageFile) : msc->initialize();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -654,6 +656,151 @@ Service::OpenSpecialDatabase(const char *aStorageKey,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class AsyncInitDatabase MOZ_FINAL : public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AsyncInitDatabase(Connection* aConnection,
|
||||||
|
nsIFile* aStorageFile,
|
||||||
|
int32_t aGrowthIncrement,
|
||||||
|
mozIStorageCompletionCallback* aCallback)
|
||||||
|
: mConnection(aConnection)
|
||||||
|
, mStorageFile(aStorageFile)
|
||||||
|
, mGrowthIncrement(aGrowthIncrement)
|
||||||
|
, mCallback(aCallback)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD Run()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
nsresult rv = mStorageFile ? mConnection->initialize(mStorageFile)
|
||||||
|
: mConnection->initialize();
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return DispatchResult(rv, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mGrowthIncrement >= 0) {
|
||||||
|
// Ignore errors. In the future, we might wish to log them.
|
||||||
|
(void)mConnection->SetGrowthIncrement(mGrowthIncrement, EmptyCString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return DispatchResult(NS_OK, NS_ISUPPORTS_CAST(mozIStorageAsyncConnection*,
|
||||||
|
mConnection));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsresult DispatchResult(nsresult aStatus, nsISupports* aValue) {
|
||||||
|
nsRefPtr<CallbackComplete> event =
|
||||||
|
new CallbackComplete(aStatus,
|
||||||
|
aValue,
|
||||||
|
mCallback.forget());
|
||||||
|
return NS_DispatchToMainThread(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncInitDatabase()
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIThread> thread;
|
||||||
|
DebugOnly<nsresult> rv = NS_GetMainThread(getter_AddRefs(thread));
|
||||||
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||||
|
(void)NS_ProxyRelease(thread, mStorageFile);
|
||||||
|
|
||||||
|
// Handle ambiguous nsISupports inheritance.
|
||||||
|
Connection *rawConnection = nullptr;
|
||||||
|
mConnection.swap(rawConnection);
|
||||||
|
(void)NS_ProxyRelease(thread, NS_ISUPPORTS_CAST(mozIStorageConnection *,
|
||||||
|
rawConnection));
|
||||||
|
|
||||||
|
// Generally, the callback will be released by CallbackComplete.
|
||||||
|
// However, if for some reason Run() is not executed, we still
|
||||||
|
// need to ensure that it is released here.
|
||||||
|
mozIStorageCompletionCallback *rawCallback = nullptr;
|
||||||
|
mCallback.swap(rawCallback);
|
||||||
|
(void)NS_ProxyRelease(thread, rawCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<Connection> mConnection;
|
||||||
|
nsCOMPtr<nsIFile> mStorageFile;
|
||||||
|
int32_t mGrowthIncrement;
|
||||||
|
nsRefPtr<mozIStorageCompletionCallback> mCallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
Service::OpenAsyncDatabase(nsIVariant *aDatabaseStore,
|
||||||
|
nsIPropertyBag2 *aOptions,
|
||||||
|
mozIStorageCompletionCallback *aCallback)
|
||||||
|
{
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
return NS_ERROR_NOT_SAME_THREAD;
|
||||||
|
}
|
||||||
|
NS_ENSURE_ARG(aDatabaseStore);
|
||||||
|
NS_ENSURE_ARG(aCallback);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIFile> storageFile;
|
||||||
|
int flags = SQLITE_OPEN_READWRITE;
|
||||||
|
|
||||||
|
nsCOMPtr<nsISupports> dbStore;
|
||||||
|
nsresult rv = aDatabaseStore->GetAsISupports(getter_AddRefs(dbStore));
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
// Generally, aDatabaseStore holds the database nsIFile.
|
||||||
|
storageFile = do_QueryInterface(dbStore, &rv);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = storageFile->Clone(getter_AddRefs(storageFile));
|
||||||
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||||
|
|
||||||
|
// Ensure that SQLITE_OPEN_CREATE is passed in for compatibility reasons.
|
||||||
|
flags |= SQLITE_OPEN_CREATE;
|
||||||
|
|
||||||
|
// Extract and apply the shared-cache option.
|
||||||
|
bool shared = false;
|
||||||
|
if (aOptions) {
|
||||||
|
rv = aOptions->GetPropertyAsBool(NS_LITERAL_STRING("shared"), &shared);
|
||||||
|
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flags |= shared ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE;
|
||||||
|
} else {
|
||||||
|
// Sometimes, however, it's a special database name.
|
||||||
|
nsAutoCString keyString;
|
||||||
|
rv = aDatabaseStore->GetAsACString(keyString);
|
||||||
|
if (NS_FAILED(rv) || !keyString.EqualsLiteral("memory")) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just fall through with NULL storageFile, this will cause the storage
|
||||||
|
// connection to use a memory DB.
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t growthIncrement = -1;
|
||||||
|
if (aOptions && storageFile) {
|
||||||
|
rv = aOptions->GetPropertyAsInt32(NS_LITERAL_STRING("growthIncrement"),
|
||||||
|
&growthIncrement);
|
||||||
|
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create connection on this thread, but initialize it on its helper thread.
|
||||||
|
nsRefPtr<Connection> msc = new Connection(this, flags, true);
|
||||||
|
nsCOMPtr<nsIEventTarget> target = msc->getAsyncExecutionTarget();
|
||||||
|
MOZ_ASSERT(target, "Cannot initialize a connection that has been closed already");
|
||||||
|
|
||||||
|
nsRefPtr<AsyncInitDatabase> asyncInit =
|
||||||
|
new AsyncInitDatabase(msc,
|
||||||
|
storageFile,
|
||||||
|
growthIncrement,
|
||||||
|
aCallback);
|
||||||
|
return target->Dispatch(asyncInit, nsIEventTarget::DISPATCH_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
Service::OpenDatabase(nsIFile *aDatabaseFile,
|
Service::OpenDatabase(nsIFile *aDatabaseFile,
|
||||||
mozIStorageConnection **_connection)
|
mozIStorageConnection **_connection)
|
||||||
|
@ -664,7 +811,7 @@ Service::OpenDatabase(nsIFile *aDatabaseFile,
|
||||||
// reasons.
|
// reasons.
|
||||||
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE |
|
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE |
|
||||||
SQLITE_OPEN_CREATE;
|
SQLITE_OPEN_CREATE;
|
||||||
nsRefPtr<Connection> msc = new Connection(this, flags);
|
nsRefPtr<Connection> msc = new Connection(this, flags, false);
|
||||||
|
|
||||||
nsresult rv = msc->initialize(aDatabaseFile);
|
nsresult rv = msc->initialize(aDatabaseFile);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -683,7 +830,7 @@ Service::OpenUnsharedDatabase(nsIFile *aDatabaseFile,
|
||||||
// reasons.
|
// reasons.
|
||||||
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_PRIVATECACHE |
|
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_PRIVATECACHE |
|
||||||
SQLITE_OPEN_CREATE;
|
SQLITE_OPEN_CREATE;
|
||||||
nsRefPtr<Connection> msc = new Connection(this, flags);
|
nsRefPtr<Connection> msc = new Connection(this, flags, false);
|
||||||
|
|
||||||
nsresult rv = msc->initialize(aDatabaseFile);
|
nsresult rv = msc->initialize(aDatabaseFile);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -702,7 +849,7 @@ Service::OpenDatabaseWithFileURL(nsIFileURL *aFileURL,
|
||||||
// reasons.
|
// reasons.
|
||||||
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE |
|
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE |
|
||||||
SQLITE_OPEN_CREATE | SQLITE_OPEN_URI;
|
SQLITE_OPEN_CREATE | SQLITE_OPEN_URI;
|
||||||
nsRefPtr<Connection> msc = new Connection(this, flags);
|
nsRefPtr<Connection> msc = new Connection(this, flags, false);
|
||||||
|
|
||||||
nsresult rv = msc->initialize(aFileURL);
|
nsresult rv = msc->initialize(aFileURL);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
|
@ -176,7 +176,7 @@ AsyncStatementSpinner::HandleCompletion(uint16_t aReason)
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
AsyncStatementSpinner::Complete()
|
AsyncStatementSpinner::Complete(nsresult, nsISupports*)
|
||||||
{
|
{
|
||||||
mCompleted = true;
|
mCompleted = true;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
@ -222,7 +222,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
BlockingConnectionCloseCallback::Complete()
|
BlockingConnectionCloseCallback::Complete(nsresult, nsISupports*)
|
||||||
{
|
{
|
||||||
mDone = true;
|
mDone = true;
|
||||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче