Bug 584319 - 'IndexedDB: Out of Memory error and crash when calling moz_indexedDB.open a lot'. r=sicking

This commit is contained in:
Ben Turner 2010-10-19 10:58:42 -07:00
Родитель e8315ce8b9
Коммит 88b443f419
13 изменённых файлов: 156 добавлений и 152 удалений

Просмотреть файл

@ -172,12 +172,6 @@ AsyncConnectionHelper::Run()
NS_ASSERTION(connection, "This should never be null!"); NS_ASSERTION(connection, "This should never be null!");
} }
} }
else if (mDatabase) {
rv = mDatabase->GetOrCreateConnection(getter_AddRefs(connection));
if (NS_SUCCEEDED(rv)) {
NS_ASSERTION(connection, "This should never be null!");
}
}
if (connection) { if (connection) {
rv = connection->SetProgressHandler(kProgressHandlerGranularity, this, rv = connection->SetProgressHandler(kProgressHandlerGranularity, this,

Просмотреть файл

@ -147,14 +147,14 @@ CheckPermissionsHelper::Run()
nsRefPtr<AsyncConnectionHelper> helper; nsRefPtr<AsyncConnectionHelper> helper;
helper.swap(mHelper); helper.swap(mHelper);
nsCOMPtr<nsIThread> thread;
thread.swap(mThread);
nsCOMPtr<nsIDOMWindow> window; nsCOMPtr<nsIDOMWindow> window;
window.swap(mWindow); window.swap(mWindow);
if (permission == nsIPermissionManager::ALLOW_ACTION) { if (permission == nsIPermissionManager::ALLOW_ACTION) {
return helper->Dispatch(thread); IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
return helper->Dispatch(mgr->IOThread());
} }
NS_ASSERTION(permission == nsIPermissionManager::UNKNOWN_ACTION || NS_ASSERTION(permission == nsIPermissionManager::UNKNOWN_ACTION ||

Просмотреть файл

@ -63,25 +63,21 @@ public:
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
CheckPermissionsHelper(AsyncConnectionHelper* aHelper, CheckPermissionsHelper(AsyncConnectionHelper* aHelper,
nsIThread* aThread,
nsIDOMWindow* aWindow, nsIDOMWindow* aWindow,
const nsACString& aASCIIOrigin) const nsACString& aASCIIOrigin)
: mHelper(aHelper), : mHelper(aHelper),
mThread(aThread),
mWindow(aWindow), mWindow(aWindow),
mASCIIOrigin(aASCIIOrigin), mASCIIOrigin(aASCIIOrigin),
mHasPrompted(PR_FALSE), mHasPrompted(PR_FALSE),
mPromptResult(0) mPromptResult(0)
{ {
NS_ASSERTION(aHelper, "Null pointer!"); NS_ASSERTION(aHelper, "Null pointer!");
NS_ASSERTION(aThread, "Null pointer!");
NS_ASSERTION(aWindow, "Null pointer!"); NS_ASSERTION(aWindow, "Null pointer!");
NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty host!"); NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty host!");
} }
private: private:
nsRefPtr<AsyncConnectionHelper> mHelper; nsRefPtr<AsyncConnectionHelper> mHelper;
nsCOMPtr<nsIThread> mThread;
nsCOMPtr<nsIDOMWindow> mWindow; nsCOMPtr<nsIDOMWindow> mWindow;
nsCString mASCIIOrigin; nsCString mASCIIOrigin;
PRBool mHasPrompted; PRBool mHasPrompted;

Просмотреть файл

@ -81,6 +81,54 @@ EnumerateObjectStoreNames(const nsAString& aKey,
} }
#ifdef NS_BUILD_REFCNT_LOGGING
DatabaseInfo::DatabaseInfo()
: id(0)
{
MOZ_COUNT_CTOR(DatabaseInfo);
}
DatabaseInfo::~DatabaseInfo()
{
MOZ_COUNT_DTOR(DatabaseInfo);
}
IndexInfo::IndexInfo()
: id(LL_MININT),
unique(false),
autoIncrement(false)
{
MOZ_COUNT_CTOR(IndexInfo);
}
IndexInfo::~IndexInfo()
{
MOZ_COUNT_DTOR(IndexInfo);
}
ObjectStoreInfo::ObjectStoreInfo()
: id(0),
autoIncrement(false),
databaseId(0)
{
MOZ_COUNT_CTOR(ObjectStoreInfo);
}
ObjectStoreInfo::~ObjectStoreInfo()
{
MOZ_COUNT_DTOR(ObjectStoreInfo);
}
IndexUpdateInfo::IndexUpdateInfo()
{
MOZ_COUNT_CTOR(IndexUpdateInfo);
}
IndexUpdateInfo::~IndexUpdateInfo()
{
MOZ_COUNT_DTOR(IndexUpdateInfo);
}
#endif /* NS_BUILD_REFCNT_LOGGING */
// static // static
bool bool
DatabaseInfo::Get(PRUint32 aId, DatabaseInfo::Get(PRUint32 aId,

Просмотреть файл

@ -57,8 +57,13 @@ struct DatabaseInfo
nsAutoRefCnt referenceCount; nsAutoRefCnt referenceCount;
#ifdef NS_BUILD_REFCNT_LOGGING
DatabaseInfo();
~DatabaseInfo();
#else
DatabaseInfo() DatabaseInfo()
: id(0) { } : id(0) { }
#endif
static bool Get(PRUint32 aId, static bool Get(PRUint32 aId,
DatabaseInfo** aInfo); DatabaseInfo** aInfo);
@ -73,8 +78,13 @@ struct DatabaseInfo
struct IndexInfo struct IndexInfo
{ {
#ifdef NS_BUILD_REFCNT_LOGGING
IndexInfo();
~IndexInfo();
#else
IndexInfo() IndexInfo()
: id(LL_MININT), unique(false), autoIncrement(false) { } : id(LL_MININT), unique(false), autoIncrement(false) { }
#endif
PRInt64 id; PRInt64 id;
nsString name; nsString name;
@ -92,8 +102,13 @@ struct ObjectStoreInfo
PRUint32 databaseId; PRUint32 databaseId;
nsTArray<IndexInfo> indexes; nsTArray<IndexInfo> indexes;
#ifdef NS_BUILD_REFCNT_LOGGING
ObjectStoreInfo();
~ObjectStoreInfo();
#else
ObjectStoreInfo() ObjectStoreInfo()
: id(0), autoIncrement(false), databaseId(0) { } : id(0), autoIncrement(false), databaseId(0) { }
#endif
static bool Get(PRUint32 aDatabaseId, static bool Get(PRUint32 aDatabaseId,
const nsAString& aName, const nsAString& aName,
@ -107,6 +122,11 @@ struct ObjectStoreInfo
struct IndexUpdateInfo struct IndexUpdateInfo
{ {
#ifdef NS_BUILD_REFCNT_LOGGING
IndexUpdateInfo();
~IndexUpdateInfo();
#endif
IndexInfo info; IndexInfo info;
Key value; Key value;
}; };

Просмотреть файл

@ -224,14 +224,10 @@ already_AddRefed<IDBDatabase>
IDBDatabase::Create(nsIScriptContext* aScriptContext, IDBDatabase::Create(nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwner, nsPIDOMWindow* aOwner,
DatabaseInfo* aDatabaseInfo, DatabaseInfo* aDatabaseInfo,
LazyIdleThread* aThread,
nsCOMPtr<mozIStorageConnection>& aConnection,
const nsACString& aASCIIOrigin) const nsACString& aASCIIOrigin)
{ {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aDatabaseInfo, "Null pointer!"); NS_ASSERTION(aDatabaseInfo, "Null pointer!");
NS_ASSERTION(aThread, "Null pointer!");
NS_ASSERTION(aConnection, "Null pointer!");
NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!"); NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
nsRefPtr<IDBDatabase> db(new IDBDatabase()); nsRefPtr<IDBDatabase> db(new IDBDatabase());
@ -245,16 +241,11 @@ IDBDatabase::Create(nsIScriptContext* aScriptContext,
db->mFilePath = aDatabaseInfo->filePath; db->mFilePath = aDatabaseInfo->filePath;
db->mASCIIOrigin = aASCIIOrigin; db->mASCIIOrigin = aASCIIOrigin;
aThread->SetWeakIdleObserver(db);
db->mConnectionThread = aThread;
db->mConnection.swap(aConnection);
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!"); NS_ASSERTION(mgr, "This should never be null!");
if (!mgr->RegisterDatabase(db)) { if (!mgr->RegisterDatabase(db)) {
NS_WARNING("Out of memory?"); // Either out of memory or shutting down.
return nsnull; return nsnull;
} }
@ -263,7 +254,8 @@ IDBDatabase::Create(nsIScriptContext* aScriptContext,
IDBDatabase::IDBDatabase() IDBDatabase::IDBDatabase()
: mDatabaseId(0), : mDatabaseId(0),
mInvalidated(0) mInvalidated(0),
mRegistered(false)
{ {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -276,17 +268,14 @@ IDBDatabase::IDBDatabase()
IDBDatabase::~IDBDatabase() IDBDatabase::~IDBDatabase()
{ {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
if (mgr) {
mgr->UnregisterDatabase(this);
}
if (mConnectionThread) { if (mRegistered) {
mConnectionThread->SetWeakIdleObserver(nsnull); IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
if (mgr) {
mgr->UnregisterDatabase(this);
}
} }
CloseConnection();
if (mDatabaseId && !mInvalidated) { if (mDatabaseId && !mInvalidated) {
DatabaseInfo* info; DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabaseId, &info)) { if (!DatabaseInfo::Get(mDatabaseId, &info)) {
@ -314,40 +303,6 @@ IDBDatabase::~IDBDatabase()
} }
} }
nsresult
IDBDatabase::GetOrCreateConnection(mozIStorageConnection** aResult)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mInvalidated) {
return NS_ERROR_NOT_AVAILABLE;
}
if (!mConnection) {
mConnection = IDBFactory::GetConnection(mFilePath);
NS_ENSURE_TRUE(mConnection, NS_ERROR_FAILURE);
}
nsCOMPtr<mozIStorageConnection> result(mConnection);
result.forget(aResult);
return NS_OK;
}
void
IDBDatabase::CloseConnection()
{
if (mConnection) {
if (mConnectionThread) {
NS_ProxyRelease(mConnectionThread, mConnection, PR_TRUE);
}
else {
NS_ERROR("Leaking connection!");
mozIStorageConnection* leak;
mConnection.forget(&leak);
}
}
}
bool bool
IDBDatabase::IsQuotaDisabled() IDBDatabase::IsQuotaDisabled()
{ {
@ -415,7 +370,6 @@ IDBDatabase::Invalidate()
} }
PR_AtomicSet(&mInvalidated, 1); PR_AtomicSet(&mInvalidated, 1);
CloseConnection();
DatabaseInfo* info; DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabaseId, &info)) { if (!DatabaseInfo::Get(mDatabaseId, &info)) {
@ -448,7 +402,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBDatabase) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBDatabase)
NS_INTERFACE_MAP_ENTRY(nsIIDBDatabase) NS_INTERFACE_MAP_ENTRY(nsIIDBDatabase)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBDatabase) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBDatabase)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper) NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
@ -653,6 +606,10 @@ IDBDatabase::Transaction(nsIVariant* aStoreNames,
{ {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (IndexedDatabaseManager::IsShuttingDown()) {
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
}
if (aOptionalArgCount) { if (aOptionalArgCount) {
if (aMode != nsIIDBTransaction::READ_WRITE && if (aMode != nsIIDBTransaction::READ_WRITE &&
aMode != nsIIDBTransaction::READ_ONLY && aMode != nsIIDBTransaction::READ_ONLY &&
@ -831,19 +788,6 @@ IDBDatabase::ObjectStore(const nsAString& aName,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
IDBDatabase::Observe(nsISupports* aSubject,
const char* aTopic,
const PRUnichar* aData)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_FALSE(strcmp(aTopic, IDLE_THREAD_TOPIC), NS_ERROR_UNEXPECTED);
CloseConnection();
return NS_OK;
}
PRUint16 PRUint16
SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection) SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{ {

Просмотреть файл

@ -41,16 +41,13 @@
#define mozilla_dom_indexeddb_idbdatabase_h__ #define mozilla_dom_indexeddb_idbdatabase_h__
#include "mozilla/dom/indexedDB/IndexedDatabase.h" #include "mozilla/dom/indexedDB/IndexedDatabase.h"
#include "mozilla/dom/indexedDB/LazyIdleThread.h"
#include "nsIIDBDatabase.h" #include "nsIIDBDatabase.h"
#include "nsIObserver.h"
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
#include "nsDOMEventTargetHelper.h" #include "nsDOMEventTargetHelper.h"
#include "nsDOMLists.h" #include "nsDOMLists.h"
class mozIStorageConnection;
class nsIScriptContext; class nsIScriptContext;
class nsPIDOMWindow; class nsPIDOMWindow;
@ -59,17 +56,17 @@ BEGIN_INDEXEDDB_NAMESPACE
class AsyncConnectionHelper; class AsyncConnectionHelper;
struct DatabaseInfo; struct DatabaseInfo;
class IDBTransaction; class IDBTransaction;
class IndexedDatabaseManager;
class IDBDatabase : public nsDOMEventTargetHelper, class IDBDatabase : public nsDOMEventTargetHelper,
public nsIIDBDatabase, public nsIIDBDatabase
public nsIObserver
{ {
friend class AsyncConnectionHelper; friend class AsyncConnectionHelper;
friend class IndexedDatabaseManager;
public: public:
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIIDBDATABASE NS_DECL_NSIIDBDATABASE
NS_DECL_NSIOBSERVER
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBDatabase, NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBDatabase,
nsDOMEventTargetHelper) nsDOMEventTargetHelper)
@ -78,17 +75,8 @@ public:
Create(nsIScriptContext* aScriptContext, Create(nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwner, nsPIDOMWindow* aOwner,
DatabaseInfo* aDatabaseInfo, DatabaseInfo* aDatabaseInfo,
LazyIdleThread* aThread,
nsCOMPtr<mozIStorageConnection>& aConnection,
const nsACString& aASCIIOrigin); const nsACString& aASCIIOrigin);
nsIThread* ConnectionThread()
{
return mConnectionThread;
}
void CloseConnection();
PRUint32 Id() PRUint32 Id()
{ {
return mDatabaseId; return mDatabaseId;
@ -111,8 +99,7 @@ public:
return mOwner; return mOwner;
} }
bool bool IsQuotaDisabled();
IsQuotaDisabled();
nsCString& Origin() nsCString& Origin()
{ {
@ -126,21 +113,13 @@ private:
IDBDatabase(); IDBDatabase();
~IDBDatabase(); ~IDBDatabase();
// Only meant to be called on mStorageThread!
nsresult GetOrCreateConnection(mozIStorageConnection** aConnection);
PRUint32 mDatabaseId; PRUint32 mDatabaseId;
nsString mName; nsString mName;
nsString mDescription; nsString mDescription;
nsString mFilePath; nsString mFilePath;
nsCString mASCIIOrigin; nsCString mASCIIOrigin;
PRInt32 mInvalidated; PRInt32 mInvalidated;
bool mRegistered;
nsRefPtr<LazyIdleThread> mConnectionThread;
// Only touched on mStorageThread! These must be destroyed in the
// FireCloseConnectionRunnable method.
nsCOMPtr<mozIStorageConnection> mConnection;
// Only touched on the main thread. // Only touched on the main thread.
nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener; nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;

Просмотреть файл

@ -128,30 +128,24 @@ public:
OpenDatabaseHelper(IDBRequest* aRequest, OpenDatabaseHelper(IDBRequest* aRequest,
const nsAString& aName, const nsAString& aName,
const nsAString& aDescription, const nsAString& aDescription,
const nsACString& aASCIIOrigin, const nsACString& aASCIIOrigin)
LazyIdleThread* aThread)
: AsyncConnectionHelper(static_cast<IDBDatabase*>(nsnull), aRequest), : AsyncConnectionHelper(static_cast<IDBDatabase*>(nsnull), aRequest),
mName(aName), mDescription(aDescription), mASCIIOrigin(aASCIIOrigin), mName(aName), mDescription(aDescription), mASCIIOrigin(aASCIIOrigin),
mThread(aThread), mDatabaseId(0) mDatabaseId(0)
{ } { }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection); PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
PRUint16 GetSuccessResult(nsIWritableVariant* aResult); PRUint16 GetSuccessResult(nsIWritableVariant* aResult);
private: private:
PRUint16 DoDatabaseWorkInternal(mozIStorageConnection* aConnection);
// In-params. // In-params.
nsString mName; nsString mName;
nsString mDescription; nsString mDescription;
nsCString mASCIIOrigin; nsCString mASCIIOrigin;
nsRefPtr<LazyIdleThread> mThread;
// Out-params. // Out-params.
nsTArray<nsAutoPtr<ObjectStoreInfo> > mObjectStores; nsTArray<nsAutoPtr<ObjectStoreInfo> > mObjectStores;
nsString mVersion; nsString mVersion;
nsCOMPtr<mozIStorageConnection> mConnection;
nsString mDatabaseFilePath; nsString mDatabaseFilePath;
PRUint32 mDatabaseId; PRUint32 mDatabaseId;
}; };
@ -718,14 +712,11 @@ IDBFactory::Open(const nsAString& aName,
nsRefPtr<IDBRequest> request = IDBRequest::Create(this, context, innerWindow); nsRefPtr<IDBRequest> request = IDBRequest::Create(this, context, innerWindow);
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<LazyIdleThread> thread(new LazyIdleThread(kDefaultThreadTimeoutMS,
nsnull));
nsRefPtr<OpenDatabaseHelper> openHelper = nsRefPtr<OpenDatabaseHelper> openHelper =
new OpenDatabaseHelper(request, aName, aDescription, origin, thread); new OpenDatabaseHelper(request, aName, aDescription, origin);
nsRefPtr<CheckPermissionsHelper> permissionHelper = nsRefPtr<CheckPermissionsHelper> permissionHelper =
new CheckPermissionsHelper(openHelper, thread, innerWindow, origin); new CheckPermissionsHelper(openHelper, innerWindow, origin);
nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate(); nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate();
NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE); NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE);
@ -839,30 +830,26 @@ IDBFactory::MakeBoundKeyRange(nsIVariant* aLeft,
PRUint16 PRUint16
OpenDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection) OpenDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
PRUint16 result = DoDatabaseWorkInternal(aConnection);
if (result != OK) {
mConnection = nsnull;
}
return result;
}
PRUint16
OpenDatabaseHelper::DoDatabaseWorkInternal(mozIStorageConnection* aConnection)
{ {
#ifdef DEBUG #ifdef DEBUG
{ {
PRBool correctThread; PRBool correctThread;
NS_ASSERTION(NS_SUCCEEDED(mThread->IsOnCurrentThread(&correctThread)) && NS_ASSERTION(NS_SUCCEEDED(IndexedDatabaseManager::Get()->IOThread()->
IsOnCurrentThread(&correctThread)) &&
correctThread, correctThread,
"Running on the wrong thread!"); "Running on the wrong thread!");
} }
#endif #endif
NS_ASSERTION(!aConnection, "Huh?!"); NS_ASSERTION(!aConnection, "Huh?!");
if (IndexedDatabaseManager::IsShuttingDown()) {
return nsIIDBDatabaseException::UNKNOWN_ERR;
}
nsCOMPtr<mozIStorageConnection> connection;
nsresult rv = CreateDatabaseConnection(mASCIIOrigin, mName, mDescription, nsresult rv = CreateDatabaseConnection(mASCIIOrigin, mName, mDescription,
mDatabaseFilePath, mDatabaseFilePath,
getter_AddRefs(mConnection)); getter_AddRefs(connection));
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR); NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
mDatabaseId = HashString(mDatabaseFilePath); mDatabaseId = HashString(mDatabaseFilePath);
@ -872,7 +859,7 @@ OpenDatabaseHelper::DoDatabaseWorkInternal(mozIStorageConnection* aConnection)
{ // Load object store names and ids. { // Load object store names and ids.
nsCOMPtr<mozIStorageStatement> stmt; nsCOMPtr<mozIStorageStatement> stmt;
rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( rv = connection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT name, id, key_path, auto_increment " "SELECT name, id, key_path, auto_increment "
"FROM object_store" "FROM object_store"
), getter_AddRefs(stmt)); ), getter_AddRefs(stmt));
@ -910,7 +897,7 @@ OpenDatabaseHelper::DoDatabaseWorkInternal(mozIStorageConnection* aConnection)
{ // Load index information { // Load index information
nsCOMPtr<mozIStorageStatement> stmt; nsCOMPtr<mozIStorageStatement> stmt;
rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( rv = connection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT object_store_id, id, name, key_path, unique_index, " "SELECT object_store_id, id, name, key_path, unique_index, "
"object_store_autoincrement " "object_store_autoincrement "
"FROM object_store_index" "FROM object_store_index"
@ -951,7 +938,7 @@ OpenDatabaseHelper::DoDatabaseWorkInternal(mozIStorageConnection* aConnection)
{ // Load version information. { // Load version information.
nsCOMPtr<mozIStorageStatement> stmt; nsCOMPtr<mozIStorageStatement> stmt;
rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( rv = connection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT version " "SELECT version "
"FROM database" "FROM database"
), getter_AddRefs(stmt)); ), getter_AddRefs(stmt));
@ -975,8 +962,6 @@ OpenDatabaseHelper::DoDatabaseWorkInternal(mozIStorageConnection* aConnection)
PRUint16 PRUint16
OpenDatabaseHelper::GetSuccessResult(nsIWritableVariant* aResult) OpenDatabaseHelper::GetSuccessResult(nsIWritableVariant* aResult)
{ {
NS_ASSERTION(mConnection, "Should have a connection!");
DatabaseInfo* dbInfo; DatabaseInfo* dbInfo;
if (DatabaseInfo::Get(mDatabaseId, &dbInfo)) { if (DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
NS_ASSERTION(dbInfo->referenceCount, "Bad reference count!"); NS_ASSERTION(dbInfo->referenceCount, "Bad reference count!");
@ -1064,10 +1049,10 @@ OpenDatabaseHelper::GetSuccessResult(nsIWritableVariant* aResult)
nsRefPtr<IDBDatabase> db = nsRefPtr<IDBDatabase> db =
IDBDatabase::Create(mRequest->ScriptContext(), mRequest->Owner(), dbInfo, IDBDatabase::Create(mRequest->ScriptContext(), mRequest->Owner(), dbInfo,
mThread, mConnection, mASCIIOrigin); mASCIIOrigin);
NS_ASSERTION(db, "This can't fail!"); if (!db) {
return nsIIDBDatabaseException::UNKNOWN_ERR;
NS_ASSERTION(!mConnection, "Should have swapped out!"); }
aResult->SetAsISupports(static_cast<nsPIDOMEventTarget*>(db)); aResult->SetAsISupports(static_cast<nsPIDOMEventTarget*>(db));
return OK; return OK;

Просмотреть файл

@ -53,6 +53,7 @@
#include "nsHashKeys.h" #include "nsHashKeys.h"
#include "nsInterfaceHashtable.h" #include "nsInterfaceHashtable.h"
class mozIStorageConnection;
class mozIStorageStatement; class mozIStorageStatement;
class nsIThread; class nsIThread;

Просмотреть файл

@ -68,7 +68,7 @@ using namespace mozilla::services;
namespace { namespace {
bool gShutdown = false; PRInt32 gShutdown = 0;
// Does not hold a reference. // Does not hold a reference.
IndexedDatabaseManager* gInstance = nsnull; IndexedDatabaseManager* gInstance = nsnull;
@ -116,7 +116,7 @@ IndexedDatabaseManager::GetOrCreate()
{ {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (gShutdown) { if (IsShuttingDown()) {
NS_ERROR("Calling GetOrCreateInstance() after shutdown!"); NS_ERROR("Calling GetOrCreateInstance() after shutdown!");
return nsnull; return nsnull;
} }
@ -153,7 +153,8 @@ IndexedDatabaseManager::GetOrCreate()
// Make a lazy thread for any IO we need (like clearing or enumerating the // Make a lazy thread for any IO we need (like clearing or enumerating the
// contents of indexedDB database directories). // contents of indexedDB database directories).
instance->mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS); instance->mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
LazyIdleThread::ManualShutdown);
// The observer service will hold our last reference, don't AddRef here. // The observer service will hold our last reference, don't AddRef here.
gInstance = instance; gInstance = instance;
@ -187,7 +188,7 @@ IndexedDatabaseManager::RegisterDatabase(IDBDatabase* aDatabase)
NS_ASSERTION(aDatabase, "Null pointer!"); NS_ASSERTION(aDatabase, "Null pointer!");
// Don't allow any new databases to be created after shutdown. // Don't allow any new databases to be created after shutdown.
if (gShutdown) { if (IsShuttingDown()) {
return false; return false;
} }
@ -205,6 +206,8 @@ IndexedDatabaseManager::RegisterDatabase(IDBDatabase* aDatabase)
NS_WARNING("Out of memory?"); NS_WARNING("Out of memory?");
return false; return false;
} }
aDatabase->mRegistered = true;
return true; return true;
} }
@ -287,6 +290,13 @@ IndexedDatabaseManager::WaitForClearAndDispatch(const nsACString& aOrigin,
return NS_DispatchToCurrentThread(aRunnable); return NS_DispatchToCurrentThread(aRunnable);
} }
// static
bool
IndexedDatabaseManager::IsShuttingDown()
{
return !!gShutdown;
}
NS_IMPL_ISUPPORTS2(IndexedDatabaseManager, nsIIndexedDatabaseManager, NS_IMPL_ISUPPORTS2(IndexedDatabaseManager, nsIIndexedDatabaseManager,
nsIObserver) nsIObserver)
@ -445,9 +455,11 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject,
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID)) { if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID)) {
// Setting this flag prevents the servic from being recreated and prevents // Setting this flag prevents the service from being recreated and prevents
// further databases from being created. // further databases from being created.
gShutdown = true; if (PR_AtomicSet(&gShutdown, 1)) {
NS_ERROR("Shutdown more than once?!");
}
// Make sure to join with our IO thread. // Make sure to join with our IO thread.
if (NS_FAILED(mIOThread->Shutdown())) { if (NS_FAILED(mIOThread->Shutdown())) {

Просмотреть файл

@ -80,6 +80,14 @@ public:
nsresult WaitForClearAndDispatch(const nsACString& aOrigin, nsresult WaitForClearAndDispatch(const nsACString& aOrigin,
nsIRunnable* aRunnable); nsIRunnable* aRunnable);
nsIThread* IOThread()
{
NS_ASSERTION(mIOThread, "This should never be null!");
return mIOThread;
}
static bool IsShuttingDown();
private: private:
IndexedDatabaseManager(); IndexedDatabaseManager();
~IndexedDatabaseManager(); ~IndexedDatabaseManager();

Просмотреть файл

@ -64,6 +64,7 @@ USING_INDEXEDDB_NAMESPACE
using mozilla::MutexAutoLock; using mozilla::MutexAutoLock;
LazyIdleThread::LazyIdleThread(PRUint32 aIdleTimeoutMS, LazyIdleThread::LazyIdleThread(PRUint32 aIdleTimeoutMS,
ShutdownMethod aShutdownMethod,
nsIObserver* aIdleObserver) nsIObserver* aIdleObserver)
: mMutex("LazyIdleThread::mMutex"), : mMutex("LazyIdleThread::mMutex"),
mOwningThread(NS_GetCurrentThread()), mOwningThread(NS_GetCurrentThread()),
@ -71,6 +72,7 @@ LazyIdleThread::LazyIdleThread(PRUint32 aIdleTimeoutMS,
mIdleTimeoutMS(aIdleTimeoutMS), mIdleTimeoutMS(aIdleTimeoutMS),
mPendingEventCount(0), mPendingEventCount(0),
mIdleNotificationCount(0), mIdleNotificationCount(0),
mShutdownMethod(aShutdownMethod),
mShutdown(PR_FALSE), mShutdown(PR_FALSE),
mThreadIsShuttingDown(PR_FALSE), mThreadIsShuttingDown(PR_FALSE),
mIdleTimeoutEnabled(PR_TRUE) mIdleTimeoutEnabled(PR_TRUE)
@ -172,7 +174,7 @@ LazyIdleThread::EnsureThread()
nsresult rv; nsresult rv;
if (NS_IsMainThread()) { if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) {
nsCOMPtr<nsIObserverService> obs = nsCOMPtr<nsIObserverService> obs =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv); do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -257,7 +259,7 @@ LazyIdleThread::ShutdownThread()
nsresult rv; nsresult rv;
if (mThread) { if (mThread) {
if (NS_IsMainThread()) { if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) {
nsCOMPtr<nsIObserverService> obs = nsCOMPtr<nsIObserverService> obs =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID); do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
NS_WARN_IF_FALSE(obs, "Failed to get observer service!"); NS_WARN_IF_FALSE(obs, "Failed to get observer service!");
@ -504,8 +506,10 @@ LazyIdleThread::Observe(nsISupports* /* aSubject */,
const PRUnichar* /* aData */) const PRUnichar* /* aData */)
{ {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_FALSE(strcmp("xpcom-shutdown-threads", aTopic), NS_ASSERTION(mShutdownMethod == AutomaticShutdown,
NS_ERROR_UNEXPECTED); "Should not receive notifications if not AutomaticShutdown!");
NS_ASSERTION(!strcmp("xpcom-shutdown-threads", aTopic), "Bad topic!");
Shutdown(); Shutdown();
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -72,11 +72,17 @@ public:
NS_DECL_NSITHREADOBSERVER NS_DECL_NSITHREADOBSERVER
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
enum ShutdownMethod {
AutomaticShutdown = 0,
ManualShutdown
};
/** /**
* Create a new LazyIdleThread that will destroy its thread after the given * Create a new LazyIdleThread that will destroy its thread after the given
* number of milliseconds. * number of milliseconds.
*/ */
LazyIdleThread(PRUint32 aIdleTimeoutMS, LazyIdleThread(PRUint32 aIdleTimeoutMS,
ShutdownMethod aShutdownMethod = AutomaticShutdown,
nsIObserver* aIdleObserver = nsnull); nsIObserver* aIdleObserver = nsnull);
/** /**
@ -191,6 +197,13 @@ private:
*/ */
PRUint32 mIdleNotificationCount; PRUint32 mIdleNotificationCount;
/**
* Whether or not the thread should automatically shutdown. If the owner
* specified ManualShutdown at construction time then the owner should take
* care to call Shutdown() manually when appropriate.
*/
ShutdownMethod mShutdownMethod;
/** /**
* Only accessed on the owning thread. Set to true when Shutdown() has been * Only accessed on the owning thread. Set to true when Shutdown() has been
* called and prevents EnsureThread() from recreating mThread. * called and prevents EnsureThread() from recreating mThread.