mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Bug 1350637 - Part 2: Core changes for LocalStorage on PBackground; r=asuth
- stop inheriting StorageDBBridge in StorageDBThread and StorageDBChild - move StorageDBThread and StorageDBChild initialization out of LocalStorageCache - use IPC even for the intra-process communication in main process - rationalize a bit storage observer code - make StorageDBParent to always be created and destroyed on the background thread
This commit is contained in:
parent
ceff0f7d8f
commit
c186d54bb2
@ -24,10 +24,6 @@ namespace dom {
|
||||
|
||||
#define DOM_STORAGE_CACHE_KEEP_ALIVE_TIME_MS 20000
|
||||
|
||||
// static
|
||||
StorageDBBridge* LocalStorageCache::sDatabase = nullptr;
|
||||
bool LocalStorageCache::sDatabaseDown = false;
|
||||
|
||||
namespace {
|
||||
|
||||
const uint32_t kDefaultSet = 0;
|
||||
@ -243,13 +239,14 @@ LocalStorageCache::Preload()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!StartDatabase()) {
|
||||
StorageDBChild* storageChild = StorageDBChild::GetOrCreate();
|
||||
if (!storageChild) {
|
||||
mLoaded = true;
|
||||
mLoadResult = NS_ERROR_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
sDatabase->AsyncPreload(this);
|
||||
storageChild->AsyncPreload(this);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -309,7 +306,7 @@ LocalStorageCache::WaitForPreload(Telemetry::HistogramID aTelemetryID)
|
||||
// No need to check sDatabase for being non-null since preload is either
|
||||
// done before we've shut the DB down or when the DB could not start,
|
||||
// preload has not even be started.
|
||||
sDatabase->SyncPreload(this);
|
||||
StorageDBChild::Get()->SyncPreload(this);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -429,17 +426,18 @@ LocalStorageCache::SetItem(const LocalStorage* aStorage, const nsAString& aKey,
|
||||
data.mKeys.Put(aKey, aValue);
|
||||
|
||||
if (aSource == ContentMutation && Persist(aStorage)) {
|
||||
if (!sDatabase) {
|
||||
StorageDBChild* storageChild = StorageDBChild::Get();
|
||||
if (!storageChild) {
|
||||
NS_ERROR("Writing to localStorage after the database has been shut down"
|
||||
", data lose!");
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (DOMStringIsNull(aOld)) {
|
||||
return sDatabase->AsyncAddItem(this, aKey, aValue);
|
||||
return storageChild->AsyncAddItem(this, aKey, aValue);
|
||||
}
|
||||
|
||||
return sDatabase->AsyncUpdateItem(this, aKey, aValue);
|
||||
return storageChild->AsyncUpdateItem(this, aKey, aValue);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -470,13 +468,14 @@ LocalStorageCache::RemoveItem(const LocalStorage* aStorage,
|
||||
data.mKeys.Remove(aKey);
|
||||
|
||||
if (aSource == ContentMutation && Persist(aStorage)) {
|
||||
if (!sDatabase) {
|
||||
StorageDBChild* storageChild = StorageDBChild::Get();
|
||||
if (!storageChild) {
|
||||
NS_ERROR("Writing to localStorage after the database has been shut down"
|
||||
", data lose!");
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
return sDatabase->AsyncRemoveItem(this, aKey);
|
||||
return storageChild->AsyncRemoveItem(this, aKey);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -511,13 +510,14 @@ LocalStorageCache::Clear(const LocalStorage* aStorage,
|
||||
}
|
||||
|
||||
if (aSource == ContentMutation && Persist(aStorage) && (refresh || hadData)) {
|
||||
if (!sDatabase) {
|
||||
StorageDBChild* storageChild = StorageDBChild::Get();
|
||||
if (!storageChild) {
|
||||
NS_ERROR("Writing to localStorage after the database has been shut down"
|
||||
", data lose!");
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
return sDatabase->AsyncClear(this);
|
||||
return storageChild->AsyncClear(this);
|
||||
}
|
||||
|
||||
return hadData ? NS_OK : NS_SUCCESS_DOM_NO_OPERATION;
|
||||
@ -672,67 +672,5 @@ StorageUsage::CheckAndSetETLD1UsageDelta(uint32_t aDataSetIndex,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
StorageDBBridge*
|
||||
LocalStorageCache::StartDatabase()
|
||||
{
|
||||
if (sDatabase || sDatabaseDown) {
|
||||
// When sDatabaseDown is at true, sDatabase is null.
|
||||
// Checking sDatabaseDown flag here prevents reinitialization of
|
||||
// the database after shutdown.
|
||||
return sDatabase;
|
||||
}
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
// XXX Fix me!
|
||||
return nullptr;
|
||||
} else {
|
||||
// Use LocalStorageManager::Ensure in case we're called from
|
||||
// DOMSessionStorageManager's initializer and we haven't yet initialized the
|
||||
// local storage manager.
|
||||
RefPtr<StorageDBChild> db = new StorageDBChild(
|
||||
LocalStorageManager::Ensure());
|
||||
|
||||
nsresult rv = db->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
db.forget(&sDatabase);
|
||||
}
|
||||
|
||||
return sDatabase;
|
||||
}
|
||||
|
||||
// static
|
||||
StorageDBBridge*
|
||||
LocalStorageCache::GetDatabase()
|
||||
{
|
||||
return sDatabase;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
LocalStorageCache::StopDatabase()
|
||||
{
|
||||
if (!sDatabase) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
sDatabaseDown = true;
|
||||
|
||||
nsresult rv = sDatabase->Shutdown();
|
||||
if (XRE_IsParentProcess()) {
|
||||
delete sDatabase;
|
||||
} else {
|
||||
StorageDBChild* child = static_cast<StorageDBChild*>(sDatabase);
|
||||
NS_RELEASE(child);
|
||||
}
|
||||
|
||||
sDatabase = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -131,13 +131,6 @@ public:
|
||||
|
||||
void GetKeys(const LocalStorage* aStorage, nsTArray<nsString>& aKeys);
|
||||
|
||||
// Starts the database engine thread or the IPC bridge
|
||||
static StorageDBBridge* StartDatabase();
|
||||
static StorageDBBridge* GetDatabase();
|
||||
|
||||
// Stops the thread and flushes all uncommited data
|
||||
static nsresult StopDatabase();
|
||||
|
||||
// LocalStorageCacheBridge
|
||||
|
||||
virtual const nsCString Origin() const;
|
||||
@ -260,13 +253,6 @@ private:
|
||||
// Whether we have already captured state of the cache preload on our first
|
||||
// access.
|
||||
bool mPreloadTelemetryRecorded : 1;
|
||||
|
||||
// StorageDBThread on the parent or single process,
|
||||
// StorageDBChild on the child process.
|
||||
static StorageDBBridge* sDatabase;
|
||||
|
||||
// False until we shut the database down.
|
||||
static bool sDatabaseDown;
|
||||
};
|
||||
|
||||
// StorageUsage
|
||||
@ -274,7 +260,7 @@ private:
|
||||
class StorageUsageBridge
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageUsageBridge)
|
||||
NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING(StorageUsageBridge)
|
||||
|
||||
virtual const nsCString& OriginScope() = 0;
|
||||
virtual void LoadUsage(const int64_t aUsage) = 0;
|
||||
|
@ -76,7 +76,7 @@ LocalStorageManager::LocalStorageManager()
|
||||
// Do this only on the child process. The thread IPC bridge
|
||||
// is also used to communicate chrome observer notifications.
|
||||
// Note: must be called after we set sSelf
|
||||
LocalStorageCache::StartDatabase();
|
||||
StorageDBChild::GetOrCreate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,9 +168,9 @@ LocalStorageManager::GetOriginUsage(const nsACString& aOriginNoSuffix)
|
||||
|
||||
usage = new StorageUsage(aOriginNoSuffix);
|
||||
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
if (db) {
|
||||
db->AsyncGetUsage(usage);
|
||||
StorageDBChild* storageChild = StorageDBChild::GetOrCreate();
|
||||
if (storageChild) {
|
||||
storageChild->AsyncGetUsage(usage);
|
||||
}
|
||||
|
||||
mUsages.Put(aOriginNoSuffix, usage);
|
||||
@ -234,7 +234,7 @@ LocalStorageManager::GetStorageInternal(CreateMode aCreateMode,
|
||||
if (aCreateMode == CreateMode::CreateIfShouldPreload) {
|
||||
// This is a demand to just preload the cache, if the scope has
|
||||
// no data stored, bypass creation and preload of the cache.
|
||||
StorageDBBridge* db = LocalStorageCache::GetDatabase();
|
||||
StorageDBChild* db = StorageDBChild::Get();
|
||||
if (db) {
|
||||
if (!db->ShouldPreloadOrigin(LocalStorageManager::CreateOrigin(originAttrSuffix, originKey))) {
|
||||
return NS_OK;
|
||||
|
@ -131,6 +131,7 @@ private:
|
||||
nsDataHashtable<nsCStringHashKey, RefPtr<StorageUsage> > mUsages;
|
||||
|
||||
friend class LocalStorageCache;
|
||||
friend class StorageDBChild;
|
||||
// Releases cache since it is no longer referrered by any Storage object.
|
||||
virtual void DropCache(LocalStorageCache* aCache);
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "mozIStorageValueArray.h"
|
||||
#include "mozIStorageFunction.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsVariant.h"
|
||||
#include "mozilla/IOInterposer.h"
|
||||
@ -48,6 +49,11 @@ using namespace StorageUtils;
|
||||
|
||||
namespace { // anon
|
||||
|
||||
StorageDBThread* sStorageThread = nullptr;
|
||||
|
||||
// False until we shut the storage thread down.
|
||||
bool sStorageThreadDown = false;
|
||||
|
||||
// This is only a compatibility code for schema version 0. Returns the 'scope'
|
||||
// key in the schema version 0 format for the scope column.
|
||||
nsCString
|
||||
@ -106,11 +112,64 @@ Scheme0Scope(LocalStorageCacheBridge* aCache)
|
||||
|
||||
} // anon
|
||||
|
||||
|
||||
// XXX Fix me!
|
||||
#if 0
|
||||
StorageDBBridge::StorageDBBridge()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
class StorageDBThread::InitHelper final
|
||||
: public Runnable
|
||||
{
|
||||
nsCOMPtr<nsIEventTarget> mOwningThread;
|
||||
mozilla::Mutex mMutex;
|
||||
mozilla::CondVar mCondVar;
|
||||
nsString mProfilePath;
|
||||
nsresult mMainThreadResultCode;
|
||||
bool mWaiting;
|
||||
|
||||
public:
|
||||
InitHelper()
|
||||
: Runnable("dom::StorageDBThread::InitHelper")
|
||||
, mOwningThread(GetCurrentThreadEventTarget())
|
||||
, mMutex("InitHelper::mMutex")
|
||||
, mCondVar(mMutex, "InitHelper::mCondVar")
|
||||
, mMainThreadResultCode(NS_OK)
|
||||
, mWaiting(true)
|
||||
{ }
|
||||
|
||||
// Because of the `sync Preload` IPC, we need to be able to synchronously
|
||||
// initialize, which includes consulting and initializing
|
||||
// some main-thread-only APIs. Bug 1386441 discusses improving this situation.
|
||||
nsresult
|
||||
SyncDispatchAndReturnProfilePath(nsAString& aProfilePath);
|
||||
|
||||
private:
|
||||
~InitHelper() override = default;
|
||||
|
||||
nsresult
|
||||
RunOnMainThread();
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
class StorageDBThread::NoteBackgroundThreadRunnable final
|
||||
: public Runnable
|
||||
{
|
||||
nsCOMPtr<nsIEventTarget> mOwningThread;
|
||||
|
||||
public:
|
||||
NoteBackgroundThreadRunnable()
|
||||
: Runnable("dom::StorageDBThread::NoteBackgroundThreadRunnable")
|
||||
, mOwningThread(GetCurrentThreadEventTarget())
|
||||
{ }
|
||||
|
||||
private:
|
||||
~NoteBackgroundThreadRunnable() override = default;
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
StorageDBThread::StorageDBThread()
|
||||
: mThread(nullptr)
|
||||
@ -127,26 +186,66 @@ StorageDBThread::StorageDBThread()
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
StorageDBThread*
|
||||
StorageDBThread::Get()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
return sStorageThread;
|
||||
}
|
||||
|
||||
// static
|
||||
StorageDBThread*
|
||||
StorageDBThread::GetOrCreate()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (sStorageThread || sStorageThreadDown) {
|
||||
// When sStorageThreadDown is at true, sStorageThread is null.
|
||||
// Checking sStorageThreadDown flag here prevents reinitialization of
|
||||
// the storage thread after shutdown.
|
||||
return sStorageThread;
|
||||
}
|
||||
|
||||
nsAutoPtr<StorageDBThread> storageThread(new StorageDBThread());
|
||||
|
||||
nsresult rv = storageThread->Init();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sStorageThread = storageThread.forget();
|
||||
|
||||
return sStorageThread;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StorageDBThread::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// Need to determine location on the main thread, since
|
||||
// NS_GetSpecialDirectory access the atom table that can
|
||||
// be accessed only on the main thread.
|
||||
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(mDatabaseFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
RefPtr<InitHelper> helper = new InitHelper();
|
||||
|
||||
nsString profilePath;
|
||||
nsresult rv = helper->SyncDispatchAndReturnProfilePath(profilePath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mDatabaseFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mDatabaseFile->InitWithPath(profilePath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mDatabaseFile->Append(NS_LITERAL_STRING("webappsstore.sqlite"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Ensure mozIStorageService init on the main thread first.
|
||||
nsCOMPtr<mozIStorageService> service =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Need to keep the lock to avoid setting mThread later then
|
||||
// the thread body executes.
|
||||
MonitorAutoLock monitor(mThreadObserver->GetMonitor());
|
||||
@ -158,12 +257,20 @@ StorageDBThread::Init()
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
RefPtr<NoteBackgroundThreadRunnable> runnable =
|
||||
new NoteBackgroundThreadRunnable();
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StorageDBThread::Shutdown()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
sStorageThreadDown = true;
|
||||
|
||||
if (!mThread) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
@ -904,7 +1011,7 @@ StorageDBThread::DBOperation::Perform(StorageDBThread* aThread)
|
||||
}
|
||||
|
||||
StatementCache* statements;
|
||||
if (MOZ_UNLIKELY(NS_IsMainThread())) {
|
||||
if (MOZ_UNLIKELY(IsOnBackgroundThread())) {
|
||||
statements = &aThread->mReaderStatements;
|
||||
} else {
|
||||
statements = &aThread->mWorkerStatements;
|
||||
@ -1494,5 +1601,115 @@ StorageDBThread::PendingOperations::IsOriginUpdatePending(const nsACString& aOri
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StorageDBThread::
|
||||
InitHelper::SyncDispatchAndReturnProfilePath(nsAString& aProfilePath)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
|
||||
|
||||
mozilla::MutexAutoLock autolock(mMutex);
|
||||
while (mWaiting) {
|
||||
mCondVar.Wait();
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(mMainThreadResultCode))) {
|
||||
return mMainThreadResultCode;
|
||||
}
|
||||
|
||||
aProfilePath = mProfilePath;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StorageDBThread::
|
||||
InitHelper::RunOnMainThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Need to determine location on the main thread, since
|
||||
// NS_GetSpecialDirectory accesses the atom table that can
|
||||
// only be accessed on the main thread.
|
||||
nsCOMPtr<nsIFile> profileDir;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(profileDir));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = profileDir->GetPath(mProfilePath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// This service has to be started on the main thread currently.
|
||||
nsCOMPtr<mozIStorageService> ss =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StorageDBThread::
|
||||
InitHelper::Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsresult rv = RunOnMainThread();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mMainThreadResultCode = rv;
|
||||
}
|
||||
|
||||
mozilla::MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(mWaiting);
|
||||
|
||||
mWaiting = false;
|
||||
mCondVar.Notify();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StorageDBThread::
|
||||
NoteBackgroundThreadRunnable::Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
StorageObserver* observer = StorageObserver::Self();
|
||||
MOZ_ASSERT(observer);
|
||||
|
||||
observer->NoteBackgroundThread(mOwningThread);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StorageDBThread::
|
||||
ShutdownRunnable::Run()
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
mDone = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (sStorageThread) {
|
||||
sStorageThread->Shutdown();
|
||||
|
||||
delete sStorageThread;
|
||||
sStorageThread = nullptr;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -32,6 +32,15 @@ class StorageUsage;
|
||||
|
||||
typedef mozilla::storage::StatementCache<mozIStorageStatement> StatementCache;
|
||||
|
||||
// XXX Fix me!
|
||||
// 1. Move comments to StorageDBThread/StorageDBChild.
|
||||
// 2. Devirtualize relevant methods in StorageDBThread/StorageDBChild.
|
||||
// 3. Remove relevant methods in StorageDBThread/StorageDBChild that are
|
||||
// unused.
|
||||
// 4. Remove this class completely.
|
||||
//
|
||||
// See bug 1387636 for more details.
|
||||
#if 0
|
||||
// Interface used by the cache to post operations to the asynchronous
|
||||
// database thread or process.
|
||||
class StorageDBBridge
|
||||
@ -100,17 +109,15 @@ public:
|
||||
// Check whether the scope has any data stored on disk and is thus allowed to
|
||||
// preload
|
||||
virtual bool ShouldPreloadOrigin(const nsACString& aOriginNoSuffix) = 0;
|
||||
|
||||
// Get the complete list of scopes having data
|
||||
virtual void GetOriginsHavingData(InfallibleTArray<nsCString>* aOrigins) = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
// The implementation of the the database engine, this directly works
|
||||
// with the sqlite or any other db API we are based on
|
||||
// This class is resposible for collecting and processing asynchronous
|
||||
// DB operations over caches (LocalStorageCache) communicating though
|
||||
// LocalStorageCacheBridge interface class
|
||||
class StorageDBThread final : public StorageDBBridge
|
||||
class StorageDBThread final
|
||||
{
|
||||
public:
|
||||
class PendingOperations;
|
||||
@ -287,11 +294,43 @@ public:
|
||||
Monitor mMonitor;
|
||||
};
|
||||
|
||||
class InitHelper;
|
||||
|
||||
class NoteBackgroundThreadRunnable;
|
||||
|
||||
class ShutdownRunnable : public Runnable
|
||||
{
|
||||
// Only touched on the main thread.
|
||||
bool& mDone;
|
||||
|
||||
public:
|
||||
explicit ShutdownRunnable(bool& aDone)
|
||||
: Runnable("dom::StorageDBThread::ShutdownRunnable")
|
||||
, mDone(aDone)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
private:
|
||||
~ShutdownRunnable()
|
||||
{ }
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
public:
|
||||
StorageDBThread();
|
||||
virtual ~StorageDBThread() {}
|
||||
|
||||
static StorageDBThread*
|
||||
Get();
|
||||
|
||||
static StorageDBThread*
|
||||
GetOrCreate();
|
||||
|
||||
virtual nsresult Init();
|
||||
|
||||
// Flushes all uncommited data and stops the I/O thread.
|
||||
virtual nsresult Shutdown();
|
||||
|
||||
virtual void AsyncPreload(LocalStorageCacheBridge* aCache,
|
||||
@ -358,7 +397,9 @@ public:
|
||||
virtual void AsyncFlush();
|
||||
|
||||
virtual bool ShouldPreloadOrigin(const nsACString& aOrigin);
|
||||
virtual void GetOriginsHavingData(InfallibleTArray<nsCString>* aOrigins);
|
||||
|
||||
// Get the complete list of scopes having data.
|
||||
void GetOriginsHavingData(InfallibleTArray<nsCString>* aOrigins);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIFile> mDatabaseFile;
|
||||
|
@ -20,10 +20,38 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
StorageDBChild* sStorageChild = nullptr;
|
||||
|
||||
// False until we shut the storage child down.
|
||||
bool sStorageChildDown = false;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Child
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class StorageDBChild::ShutdownObserver final
|
||||
: public nsIObserver
|
||||
{
|
||||
public:
|
||||
ShutdownObserver()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
private:
|
||||
~ShutdownObserver()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ADDREF(StorageDBChild)
|
||||
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) StorageDBChild::Release(void)
|
||||
@ -70,6 +98,44 @@ StorageDBChild::~StorageDBChild()
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
StorageDBChild*
|
||||
StorageDBChild::Get()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
return sStorageChild;
|
||||
}
|
||||
|
||||
// static
|
||||
StorageDBChild*
|
||||
StorageDBChild::GetOrCreate()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sStorageChild || sStorageChildDown) {
|
||||
// When sStorageChildDown is at true, sStorageChild is null.
|
||||
// Checking sStorageChildDown flag here prevents reinitialization of
|
||||
// the storage child after shutdown.
|
||||
return sStorageChild;
|
||||
}
|
||||
|
||||
// Use LocalStorageManager::Ensure in case we're called from
|
||||
// DOMSessionStorageManager's initializer and we haven't yet initialized the
|
||||
// local storage manager.
|
||||
RefPtr<StorageDBChild> storageChild =
|
||||
new StorageDBChild(LocalStorageManager::Ensure());
|
||||
|
||||
nsresult rv = storageChild->Init();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
storageChild.forget(&sStorageChild);
|
||||
|
||||
return sStorageChild;
|
||||
}
|
||||
|
||||
nsTHashtable<nsCStringHashKey>&
|
||||
StorageDBChild::OriginsHavingData()
|
||||
{
|
||||
@ -83,6 +149,8 @@ StorageDBChild::OriginsHavingData()
|
||||
nsresult
|
||||
StorageDBChild::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
PBackgroundChild* actor = BackgroundChild::GetOrCreateForCurrentThread();
|
||||
if (NS_WARN_IF(!actor)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -92,6 +160,16 @@ StorageDBChild::Init()
|
||||
|
||||
actor->SendPBackgroundStorageConstructor(this);
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
||||
MOZ_ASSERT(observerService);
|
||||
|
||||
nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
observerService->AddObserver(observer,
|
||||
"xpcom-shutdown",
|
||||
false));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -295,6 +373,35 @@ StorageDBChild::RecvError(const nsresult& aRv)
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(StorageDBChild::ShutdownObserver, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
StorageDBChild::
|
||||
ShutdownObserver::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (NS_WARN_IF(!observerService)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
Unused << observerService->RemoveObserver(this, "xpcom-shutdown");
|
||||
|
||||
if (sStorageChild) {
|
||||
sStorageChildDown = true;
|
||||
|
||||
NS_RELEASE(sStorageChild);
|
||||
sStorageChild = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Parent
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -335,10 +442,10 @@ private:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
StorageDBBridge* db = LocalStorageCache::GetDatabase();
|
||||
if (db) {
|
||||
StorageDBThread* storageThread = StorageDBThread::Get();
|
||||
if (storageThread) {
|
||||
InfallibleTArray<nsCString> scopes;
|
||||
db->GetOriginsHavingData(&scopes);
|
||||
storageThread->GetOriginsHavingData(&scopes);
|
||||
mozilla::Unused << mParent->SendOriginsHavingData(scopes);
|
||||
}
|
||||
|
||||
@ -413,27 +520,31 @@ StorageDBParent::RecvAsyncPreload(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
const bool& aPriority)
|
||||
{
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
if (!db) {
|
||||
StorageDBThread* storageThread = StorageDBThread::GetOrCreate();
|
||||
if (!storageThread) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
db->AsyncPreload(NewCache(aOriginSuffix, aOriginNoSuffix), aPriority);
|
||||
storageThread->AsyncPreload(NewCache(aOriginSuffix, aOriginNoSuffix),
|
||||
aPriority);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
StorageDBParent::RecvAsyncGetUsage(const nsCString& aOriginNoSuffix)
|
||||
{
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
if (!db) {
|
||||
StorageDBThread* storageThread = StorageDBThread::GetOrCreate();
|
||||
if (!storageThread) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
// The object releases it self in LoadUsage method
|
||||
RefPtr<UsageParentBridge> usage =
|
||||
new UsageParentBridge(this, aOriginNoSuffix);
|
||||
db->AsyncGetUsage(usage);
|
||||
|
||||
storageThread->AsyncGetUsage(usage);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
@ -524,8 +635,8 @@ StorageDBParent::RecvPreload(const nsCString& aOriginSuffix,
|
||||
InfallibleTArray<nsString>* aValues,
|
||||
nsresult* aRv)
|
||||
{
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
if (!db) {
|
||||
StorageDBThread* storageThread = StorageDBThread::GetOrCreate();
|
||||
if (!storageThread) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
@ -533,7 +644,8 @@ StorageDBParent::RecvPreload(const nsCString& aOriginSuffix,
|
||||
new SyncLoadCacheHelper(aOriginSuffix, aOriginNoSuffix, aAlreadyLoadedCount,
|
||||
aKeys, aValues, aRv));
|
||||
|
||||
db->SyncPreload(cache, true);
|
||||
storageThread->SyncPreload(cache, true);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
@ -543,13 +655,15 @@ StorageDBParent::RecvAsyncAddItem(const nsCString& aOriginSuffix,
|
||||
const nsString& aKey,
|
||||
const nsString& aValue)
|
||||
{
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
if (!db) {
|
||||
StorageDBThread* storageThread = StorageDBThread::GetOrCreate();
|
||||
if (!storageThread) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
nsresult rv = db->AsyncAddItem(NewCache(aOriginSuffix, aOriginNoSuffix), aKey,
|
||||
aValue);
|
||||
nsresult rv =
|
||||
storageThread->AsyncAddItem(NewCache(aOriginSuffix, aOriginNoSuffix),
|
||||
aKey,
|
||||
aValue);
|
||||
if (NS_FAILED(rv) && mIPCOpen) {
|
||||
mozilla::Unused << SendError(rv);
|
||||
}
|
||||
@ -563,13 +677,15 @@ StorageDBParent::RecvAsyncUpdateItem(const nsCString& aOriginSuffix,
|
||||
const nsString& aKey,
|
||||
const nsString& aValue)
|
||||
{
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
if (!db) {
|
||||
StorageDBThread* storageThread = StorageDBThread::GetOrCreate();
|
||||
if (!storageThread) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
nsresult rv = db->AsyncUpdateItem(NewCache(aOriginSuffix, aOriginNoSuffix),
|
||||
aKey, aValue);
|
||||
nsresult rv =
|
||||
storageThread->AsyncUpdateItem(NewCache(aOriginSuffix, aOriginNoSuffix),
|
||||
aKey,
|
||||
aValue);
|
||||
if (NS_FAILED(rv) && mIPCOpen) {
|
||||
mozilla::Unused << SendError(rv);
|
||||
}
|
||||
@ -582,13 +698,14 @@ StorageDBParent::RecvAsyncRemoveItem(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
const nsString& aKey)
|
||||
{
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
if (!db) {
|
||||
StorageDBThread* storageThread = StorageDBThread::GetOrCreate();
|
||||
if (!storageThread) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
nsresult rv = db->AsyncRemoveItem(NewCache(aOriginSuffix, aOriginNoSuffix),
|
||||
aKey);
|
||||
nsresult rv =
|
||||
storageThread->AsyncRemoveItem(NewCache(aOriginSuffix, aOriginNoSuffix),
|
||||
aKey);
|
||||
if (NS_FAILED(rv) && mIPCOpen) {
|
||||
mozilla::Unused << SendError(rv);
|
||||
}
|
||||
@ -600,12 +717,13 @@ mozilla::ipc::IPCResult
|
||||
StorageDBParent::RecvAsyncClear(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix)
|
||||
{
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
if (!db) {
|
||||
StorageDBThread* storageThread = StorageDBThread::GetOrCreate();
|
||||
if (!storageThread) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
nsresult rv = db->AsyncClear(NewCache(aOriginSuffix, aOriginNoSuffix));
|
||||
nsresult rv =
|
||||
storageThread->AsyncClear(NewCache(aOriginSuffix, aOriginNoSuffix));
|
||||
if (NS_FAILED(rv) && mIPCOpen) {
|
||||
mozilla::Unused << SendError(rv);
|
||||
}
|
||||
@ -616,12 +734,13 @@ StorageDBParent::RecvAsyncClear(const nsCString& aOriginSuffix,
|
||||
mozilla::ipc::IPCResult
|
||||
StorageDBParent::RecvAsyncFlush()
|
||||
{
|
||||
StorageDBBridge* db = LocalStorageCache::GetDatabase();
|
||||
if (!db) {
|
||||
StorageDBThread* storageThread = StorageDBThread::Get();
|
||||
if (!storageThread) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
db->AsyncFlush();
|
||||
storageThread->AsyncFlush();
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
@ -704,6 +823,8 @@ private:
|
||||
break;
|
||||
}
|
||||
|
||||
mParent = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
@ -731,7 +852,10 @@ StorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey,
|
||||
RefPtr<LoadRunnable> r =
|
||||
new LoadRunnable(mParent, LoadRunnable::loadItem, mOriginSuffix,
|
||||
mOriginNoSuffix, aKey, aValue);
|
||||
NS_DispatchToMainThread(r);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -748,7 +872,9 @@ StorageDBParent::CacheParentBridge::LoadDone(nsresult aRv)
|
||||
RefPtr<LoadRunnable> r =
|
||||
new LoadRunnable(mParent, LoadRunnable::loadDone, mOriginSuffix,
|
||||
mOriginNoSuffix, aRv);
|
||||
NS_DispatchToMainThread(r);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
|
||||
}
|
||||
|
||||
void
|
||||
@ -758,6 +884,42 @@ StorageDBParent::CacheParentBridge::LoadWait()
|
||||
MOZ_ASSERT(false);
|
||||
}
|
||||
|
||||
// XXX Fix me!
|
||||
// This should be just:
|
||||
// NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::CacheParentBridge, Destroy)
|
||||
// But due to different strings used for refcount logging and different return
|
||||
// types, this is done manually for now.
|
||||
NS_IMETHODIMP_(void)
|
||||
StorageDBParent::CacheParentBridge::Release(void)
|
||||
{
|
||||
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
|
||||
nsrefcnt count = --mRefCnt;
|
||||
NS_LOG_RELEASE(this, count, "LocalStorageCacheBridge");
|
||||
if (0 == count) {
|
||||
mRefCnt = 1; /* stabilize */
|
||||
/* enable this to find non-threadsafe destructors: */
|
||||
/* NS_ASSERT_OWNINGTHREAD(_class); */
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StorageDBParent::CacheParentBridge::Destroy()
|
||||
{
|
||||
if (mOwningEventTarget->IsOnCurrentThread()) {
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Runnable> destroyRunnable =
|
||||
NewNonOwningRunnableMethod("CacheParentBridge::Destroy",
|
||||
this,
|
||||
&CacheParentBridge::Destroy);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(destroyRunnable,
|
||||
NS_DISPATCH_NORMAL));
|
||||
}
|
||||
|
||||
// StorageDBParent::UsageParentBridge
|
||||
|
||||
namespace {
|
||||
@ -782,6 +944,9 @@ private:
|
||||
}
|
||||
|
||||
mozilla::Unused << mParent->SendLoadUsage(mOriginScope, mUsage);
|
||||
|
||||
mParent = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -796,7 +961,43 @@ void
|
||||
StorageDBParent::UsageParentBridge::LoadUsage(const int64_t aUsage)
|
||||
{
|
||||
RefPtr<UsageRunnable> r = new UsageRunnable(mParent, mOriginScope, aUsage);
|
||||
NS_DispatchToMainThread(r);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
|
||||
}
|
||||
|
||||
// XXX Fix me!
|
||||
// This should be just:
|
||||
// NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::UsageParentBridge, Destroy)
|
||||
// But due to different strings used for refcount logging, this is done manually
|
||||
// for now.
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
StorageDBParent::UsageParentBridge::Release(void)
|
||||
{
|
||||
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
|
||||
nsrefcnt count = --mRefCnt;
|
||||
NS_LOG_RELEASE(this, count, "StorageUsageBridge");
|
||||
if (count == 0) {
|
||||
Destroy();
|
||||
return 0;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void
|
||||
StorageDBParent::UsageParentBridge::Destroy()
|
||||
{
|
||||
if (mOwningEventTarget->IsOnCurrentThread()) {
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Runnable> destroyRunnable =
|
||||
NewNonOwningRunnableMethod("UsageParentBridge::Destroy",
|
||||
this,
|
||||
&UsageParentBridge::Destroy);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(destroyRunnable,
|
||||
NS_DISPATCH_NORMAL));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -28,14 +28,22 @@ class PBackgroundStorageParent;
|
||||
// is responsible to send all requests to the parent process
|
||||
// and expects asynchronous answers. Those are then transparently
|
||||
// forwarded back to consumers on the child process.
|
||||
class StorageDBChild final : public StorageDBBridge
|
||||
, public PBackgroundStorageChild
|
||||
class StorageDBChild final
|
||||
: public PBackgroundStorageChild
|
||||
{
|
||||
class ShutdownObserver;
|
||||
|
||||
virtual ~StorageDBChild();
|
||||
|
||||
public:
|
||||
explicit StorageDBChild(LocalStorageManager* aManager);
|
||||
|
||||
static StorageDBChild*
|
||||
Get();
|
||||
|
||||
static StorageDBChild*
|
||||
GetOrCreate();
|
||||
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release(void);
|
||||
|
||||
@ -69,17 +77,21 @@ public:
|
||||
}
|
||||
|
||||
virtual void AsyncClearMatchingOrigin(const nsACString& aOriginNoSuffix)
|
||||
{ /* NO-OP on the child process */ }
|
||||
{
|
||||
MOZ_CRASH("Shouldn't be called!");
|
||||
}
|
||||
|
||||
virtual void AsyncClearMatchingOriginAttributes(const OriginAttributesPattern& aPattern)
|
||||
{ /* NO-OP on the child process */ }
|
||||
{
|
||||
MOZ_CRASH("Shouldn't be called!");
|
||||
}
|
||||
|
||||
virtual void AsyncFlush()
|
||||
{ SendAsyncFlush(); }
|
||||
{
|
||||
MOZ_CRASH("Shouldn't be called!");
|
||||
}
|
||||
|
||||
virtual bool ShouldPreloadOrigin(const nsACString& aOriginNoSuffix);
|
||||
virtual void GetOriginsHavingData(InfallibleTArray<nsCString>* aOrigins)
|
||||
{ NS_NOTREACHED("Not implemented for child process"); }
|
||||
|
||||
private:
|
||||
mozilla::ipc::IPCResult RecvObserve(const nsCString& aTopic,
|
||||
@ -148,7 +160,8 @@ public:
|
||||
CacheParentBridge(StorageDBParent* aParentDB,
|
||||
const nsACString& aOriginSuffix,
|
||||
const nsACString& aOriginNoSuffix)
|
||||
: mParent(aParentDB)
|
||||
: mOwningEventTarget(GetCurrentThreadSerialEventTarget())
|
||||
, mParent(aParentDB)
|
||||
, mOriginSuffix(aOriginSuffix), mOriginNoSuffix(aOriginNoSuffix)
|
||||
, mLoaded(false), mLoadedCount(0) {}
|
||||
virtual ~CacheParentBridge() {}
|
||||
@ -168,7 +181,14 @@ public:
|
||||
virtual void LoadDone(nsresult aRv);
|
||||
virtual void LoadWait();
|
||||
|
||||
NS_IMETHOD_(void)
|
||||
Release(void);
|
||||
|
||||
private:
|
||||
void
|
||||
Destroy();
|
||||
|
||||
nsCOMPtr<nsISerialEventTarget> mOwningEventTarget;
|
||||
RefPtr<StorageDBParent> mParent;
|
||||
nsCString mOriginSuffix, mOriginNoSuffix;
|
||||
bool mLoaded;
|
||||
@ -181,14 +201,23 @@ public:
|
||||
public:
|
||||
UsageParentBridge(StorageDBParent* aParentDB,
|
||||
const nsACString& aOriginScope)
|
||||
: mParent(aParentDB), mOriginScope(aOriginScope) {}
|
||||
: mOwningEventTarget(GetCurrentThreadSerialEventTarget())
|
||||
, mParent(aParentDB)
|
||||
, mOriginScope(aOriginScope) {}
|
||||
virtual ~UsageParentBridge() {}
|
||||
|
||||
// StorageUsageBridge
|
||||
virtual const nsCString& OriginScope() { return mOriginScope; }
|
||||
virtual void LoadUsage(const int64_t usage);
|
||||
|
||||
NS_IMETHOD_(MozExternalRefCountType)
|
||||
Release(void);
|
||||
|
||||
private:
|
||||
void
|
||||
Destroy();
|
||||
|
||||
nsCOMPtr<nsISerialEventTarget> mOwningEventTarget;
|
||||
RefPtr<StorageDBParent> mParent;
|
||||
nsCString mOriginScope;
|
||||
};
|
||||
|
@ -70,8 +70,9 @@ StorageObserver::Init()
|
||||
|
||||
// Shutdown
|
||||
obs->AddObserver(sSelf, "profile-after-change", true);
|
||||
obs->AddObserver(sSelf, "profile-before-change", true);
|
||||
obs->AddObserver(sSelf, "xpcom-shutdown", true);
|
||||
if (XRE_IsParentProcess()) {
|
||||
obs->AddObserver(sSelf, "profile-before-change", true);
|
||||
}
|
||||
|
||||
// Observe low device storage notifications.
|
||||
obs->AddObserver(sSelf, "disk-space-watcher", true);
|
||||
@ -145,6 +146,12 @@ StorageObserver::Notify(const char* aTopic,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StorageObserver::NoteBackgroundThread(nsIEventTarget* aBackgroundThread)
|
||||
{
|
||||
mBackgroundThread = aBackgroundThread;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StorageObserver::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
@ -177,8 +184,11 @@ StorageObserver::Observe(nsISupports* aSubject,
|
||||
if (timer == mDBThreadStartDelayTimer) {
|
||||
mDBThreadStartDelayTimer = nullptr;
|
||||
|
||||
// XXX Fix me!
|
||||
#if 0
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -190,10 +200,13 @@ StorageObserver::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXX Fix me!
|
||||
#if 0
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
|
||||
|
||||
db->AsyncClearAll();
|
||||
#endif
|
||||
|
||||
Notify("cookie-cleared");
|
||||
|
||||
@ -254,10 +267,13 @@ StorageObserver::Observe(nsISupports* aSubject,
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, "extension:purge-localStorage")) {
|
||||
// XXX Fix me!
|
||||
#if 0
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
|
||||
|
||||
db->AsyncClearAll();
|
||||
#endif
|
||||
|
||||
Notify("extension:purge-localStorage-caches");
|
||||
|
||||
@ -287,10 +303,13 @@ StorageObserver::Observe(nsISupports* aSubject,
|
||||
rv = CreateReversedDomain(aceDomain, originScope);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// XXX Fix me!
|
||||
#if 0
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
|
||||
|
||||
db->AsyncClearMatchingOrigin(originScope);
|
||||
#endif
|
||||
|
||||
Notify("domain-data-cleared", EmptyString(), originScope);
|
||||
|
||||
@ -312,10 +331,13 @@ StorageObserver::Observe(nsISupports* aSubject,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// XXX Fix me!
|
||||
#if 0
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
|
||||
|
||||
db->AsyncClearMatchingOriginAttributes(pattern);
|
||||
#endif
|
||||
|
||||
Notify("origin-attr-pattern-cleared", nsDependentString(aData));
|
||||
|
||||
@ -328,11 +350,20 @@ StorageObserver::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, "profile-before-change") ||
|
||||
!strcmp(aTopic, "xpcom-shutdown")) {
|
||||
rv = LocalStorageCache::StopDatabase();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Error while stopping Storage DB background thread");
|
||||
if (!strcmp(aTopic, "profile-before-change")) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
if (mBackgroundThread) {
|
||||
bool done = false;
|
||||
|
||||
RefPtr<StorageDBThread::ShutdownRunnable> shutdownRunnable =
|
||||
new StorageDBThread::ShutdownRunnable(done);
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
mBackgroundThread->Dispatch(shutdownRunnable, NS_DISPATCH_NORMAL));
|
||||
|
||||
MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return done; }));
|
||||
|
||||
mBackgroundThread = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -350,10 +381,13 @@ StorageObserver::Observe(nsISupports* aSubject,
|
||||
|
||||
#ifdef DOM_STORAGE_TESTS
|
||||
if (!strcmp(aTopic, "domstorage-test-flush-force")) {
|
||||
// XXX Fix me!
|
||||
#if 0
|
||||
StorageDBBridge* db = LocalStorageCache::GetDatabase();
|
||||
if (db) {
|
||||
db->AsyncFlush();
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -51,6 +51,9 @@ public:
|
||||
const nsAString& aOriginAttributesPattern = EmptyString(),
|
||||
const nsACString& aOriginScope = EmptyCString());
|
||||
|
||||
void
|
||||
NoteBackgroundThread(nsIEventTarget* aBackgroundThread);
|
||||
|
||||
private:
|
||||
virtual ~StorageObserver() {}
|
||||
|
||||
@ -58,6 +61,8 @@ private:
|
||||
|
||||
static StorageObserver* sSelf;
|
||||
|
||||
nsCOMPtr<nsIEventTarget> mBackgroundThread;
|
||||
|
||||
// Weak references
|
||||
nsTArray<StorageObserverSink*> mSinks;
|
||||
nsCOMPtr<nsITimer> mDBThreadStartDelayTimer;
|
||||
|
Loading…
Reference in New Issue
Block a user