michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "DOMStorageIPC.h" michael@0: michael@0: #include "DOMStorageManager.h" michael@0: michael@0: #include "mozilla/dom/ContentChild.h" michael@0: #include "mozilla/dom/ContentParent.h" michael@0: #include "mozilla/unused.h" michael@0: #include "nsIDiskSpaceWatcher.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: // ---------------------------------------------------------------------------- michael@0: // Child michael@0: // ---------------------------------------------------------------------------- michael@0: michael@0: NS_IMPL_ADDREF(DOMStorageDBChild) michael@0: michael@0: NS_IMETHODIMP_(MozExternalRefCountType) DOMStorageDBChild::Release(void) michael@0: { michael@0: NS_PRECONDITION(0 != mRefCnt, "dup release"); michael@0: nsrefcnt count = --mRefCnt; michael@0: NS_LOG_RELEASE(this, count, "DOMStorageDBChild"); michael@0: if (count == 1 && mIPCOpen) { michael@0: Send__delete__(this); michael@0: return 0; michael@0: } michael@0: if (count == 0) { michael@0: mRefCnt = 1; michael@0: delete this; michael@0: return 0; michael@0: } michael@0: return count; michael@0: } michael@0: michael@0: void michael@0: DOMStorageDBChild::AddIPDLReference() michael@0: { michael@0: NS_ABORT_IF_FALSE(!mIPCOpen, "Attempting to retain multiple IPDL references"); michael@0: mIPCOpen = true; michael@0: AddRef(); michael@0: } michael@0: michael@0: void michael@0: DOMStorageDBChild::ReleaseIPDLReference() michael@0: { michael@0: NS_ABORT_IF_FALSE(mIPCOpen, "Attempting to release non-existent IPDL reference"); michael@0: mIPCOpen = false; michael@0: Release(); michael@0: } michael@0: michael@0: DOMStorageDBChild::DOMStorageDBChild(DOMLocalStorageManager* aManager) michael@0: : mManager(aManager) michael@0: , mStatus(NS_OK) michael@0: , mIPCOpen(false) michael@0: { michael@0: } michael@0: michael@0: DOMStorageDBChild::~DOMStorageDBChild() michael@0: { michael@0: } michael@0: michael@0: nsTHashtable& michael@0: DOMStorageDBChild::ScopesHavingData() michael@0: { michael@0: if (!mScopesHavingData) { michael@0: mScopesHavingData = new nsTHashtable; michael@0: } michael@0: michael@0: return *mScopesHavingData; michael@0: } michael@0: michael@0: nsresult michael@0: DOMStorageDBChild::Init() michael@0: { michael@0: ContentChild* child = ContentChild::GetSingleton(); michael@0: AddIPDLReference(); michael@0: child->SendPStorageConstructor(this); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: DOMStorageDBChild::Shutdown() michael@0: { michael@0: // There is nothing to do here, IPC will release automatically and michael@0: // the actual thread running on the parent process will also stop michael@0: // automatically in profile-before-change topic observer. michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: DOMStorageDBChild::AsyncPreload(DOMStorageCacheBridge* aCache, bool aPriority) michael@0: { michael@0: if (mIPCOpen) { michael@0: // Adding ref to cache for the time of preload. This ensures a reference to michael@0: // to the cache and that all keys will load into this cache object. michael@0: mLoadingCaches.PutEntry(aCache); michael@0: SendAsyncPreload(aCache->Scope(), aPriority); michael@0: } else { michael@0: // No IPC, no love. But the LoadDone call is expected. michael@0: aCache->LoadDone(NS_ERROR_UNEXPECTED); michael@0: } michael@0: } michael@0: michael@0: void michael@0: DOMStorageDBChild::AsyncGetUsage(DOMStorageUsageBridge* aUsage) michael@0: { michael@0: if (mIPCOpen) { michael@0: SendAsyncGetUsage(aUsage->Scope()); michael@0: } michael@0: } michael@0: michael@0: void michael@0: DOMStorageDBChild::SyncPreload(DOMStorageCacheBridge* aCache, bool aForceSync) michael@0: { michael@0: if (NS_FAILED(mStatus)) { michael@0: aCache->LoadDone(mStatus); michael@0: return; michael@0: } michael@0: michael@0: if (!mIPCOpen) { michael@0: aCache->LoadDone(NS_ERROR_UNEXPECTED); michael@0: return; michael@0: } michael@0: michael@0: // There is no way to put the child process to a wait state to receive all michael@0: // incoming async responses from the parent, hence we have to do a sync preload michael@0: // instead. We are smart though, we only demand keys that are left to load in michael@0: // case the async preload has already loaded some keys. michael@0: InfallibleTArray keys, values; michael@0: nsresult rv; michael@0: SendPreload(aCache->Scope(), aCache->LoadedCount(), &keys, &values, &rv); michael@0: michael@0: for (uint32_t i = 0; i < keys.Length(); ++i) { michael@0: aCache->LoadItem(keys[i], values[i]); michael@0: } michael@0: michael@0: aCache->LoadDone(rv); michael@0: } michael@0: michael@0: nsresult michael@0: DOMStorageDBChild::AsyncAddItem(DOMStorageCacheBridge* aCache, michael@0: const nsAString& aKey, michael@0: const nsAString& aValue) michael@0: { michael@0: if (NS_FAILED(mStatus) || !mIPCOpen) { michael@0: return mStatus; michael@0: } michael@0: michael@0: SendAsyncAddItem(aCache->Scope(), nsString(aKey), nsString(aValue)); michael@0: ScopesHavingData().PutEntry(aCache->Scope()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: DOMStorageDBChild::AsyncUpdateItem(DOMStorageCacheBridge* aCache, michael@0: const nsAString& aKey, michael@0: const nsAString& aValue) michael@0: { michael@0: if (NS_FAILED(mStatus) || !mIPCOpen) { michael@0: return mStatus; michael@0: } michael@0: michael@0: SendAsyncUpdateItem(aCache->Scope(), nsString(aKey), nsString(aValue)); michael@0: ScopesHavingData().PutEntry(aCache->Scope()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: DOMStorageDBChild::AsyncRemoveItem(DOMStorageCacheBridge* aCache, michael@0: const nsAString& aKey) michael@0: { michael@0: if (NS_FAILED(mStatus) || !mIPCOpen) { michael@0: return mStatus; michael@0: } michael@0: michael@0: SendAsyncRemoveItem(aCache->Scope(), nsString(aKey)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: DOMStorageDBChild::AsyncClear(DOMStorageCacheBridge* aCache) michael@0: { michael@0: if (NS_FAILED(mStatus) || !mIPCOpen) { michael@0: return mStatus; michael@0: } michael@0: michael@0: SendAsyncClear(aCache->Scope()); michael@0: ScopesHavingData().RemoveEntry(aCache->Scope()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBChild::ShouldPreloadScope(const nsACString& aScope) michael@0: { michael@0: // Return true if we didn't receive the aScope list yet. michael@0: // I tend to rather preserve a bit of early-after-start performance michael@0: // then a bit of memory here. michael@0: return !mScopesHavingData || mScopesHavingData->Contains(aScope); michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBChild::RecvObserve(const nsCString& aTopic, michael@0: const nsCString& aScopePrefix) michael@0: { michael@0: DOMStorageObserver::Self()->Notify(aTopic.get(), aScopePrefix); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBChild::RecvScopesHavingData(const InfallibleTArray& aScopes) michael@0: { michael@0: for (uint32_t i = 0; i < aScopes.Length(); ++i) { michael@0: ScopesHavingData().PutEntry(aScopes[i]); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBChild::RecvLoadItem(const nsCString& aScope, michael@0: const nsString& aKey, michael@0: const nsString& aValue) michael@0: { michael@0: DOMStorageCache* aCache = mManager->GetCache(aScope); michael@0: if (aCache) { michael@0: aCache->LoadItem(aKey, aValue); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBChild::RecvLoadDone(const nsCString& aScope, const nsresult& aRv) michael@0: { michael@0: DOMStorageCache* aCache = mManager->GetCache(aScope); michael@0: if (aCache) { michael@0: aCache->LoadDone(aRv); michael@0: michael@0: // Just drop reference to this cache now since the load is done. michael@0: mLoadingCaches.RemoveEntry(static_cast(aCache)); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBChild::RecvLoadUsage(const nsCString& aScope, const int64_t& aUsage) michael@0: { michael@0: nsRefPtr scopeUsage = mManager->GetScopeUsage(aScope); michael@0: scopeUsage->LoadUsage(aUsage); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBChild::RecvError(const nsresult& aRv) michael@0: { michael@0: mStatus = aRv; michael@0: return true; michael@0: } michael@0: michael@0: // ---------------------------------------------------------------------------- michael@0: // Parent michael@0: // ---------------------------------------------------------------------------- michael@0: michael@0: NS_IMPL_ADDREF(DOMStorageDBParent) michael@0: NS_IMPL_RELEASE(DOMStorageDBParent) michael@0: michael@0: void michael@0: DOMStorageDBParent::AddIPDLReference() michael@0: { michael@0: NS_ABORT_IF_FALSE(!mIPCOpen, "Attempting to retain multiple IPDL references"); michael@0: mIPCOpen = true; michael@0: AddRef(); michael@0: } michael@0: michael@0: void michael@0: DOMStorageDBParent::ReleaseIPDLReference() michael@0: { michael@0: NS_ABORT_IF_FALSE(mIPCOpen, "Attempting to release non-existent IPDL reference"); michael@0: mIPCOpen = false; michael@0: Release(); michael@0: } michael@0: michael@0: namespace { // anon michael@0: michael@0: class SendInitialChildDataRunnable : public nsRunnable michael@0: { michael@0: public: michael@0: SendInitialChildDataRunnable(DOMStorageDBParent* aParent) michael@0: : mParent(aParent) michael@0: {} michael@0: michael@0: private: michael@0: NS_IMETHOD Run() michael@0: { michael@0: if (!mParent->IPCOpen()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: DOMStorageDBBridge* db = DOMStorageCache::GetDatabase(); michael@0: if (db) { michael@0: InfallibleTArray scopes; michael@0: db->GetScopesHavingData(&scopes); michael@0: mozilla::unused << mParent->SendScopesHavingData(scopes); michael@0: } michael@0: michael@0: // We need to check if the device is in a low disk space situation, so michael@0: // we can forbid in that case any write in localStorage. michael@0: nsCOMPtr diskSpaceWatcher = michael@0: do_GetService("@mozilla.org/toolkit/disk-space-watcher;1"); michael@0: if (!diskSpaceWatcher) { michael@0: NS_WARNING("Could not get disk information from DiskSpaceWatcher"); michael@0: return NS_OK; michael@0: } michael@0: bool lowDiskSpace = false; michael@0: diskSpaceWatcher->GetIsDiskFull(&lowDiskSpace); michael@0: if (lowDiskSpace) { michael@0: mozilla::unused << mParent->SendObserve( michael@0: nsDependentCString("low-disk-space"), EmptyCString()); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsRefPtr mParent; michael@0: }; michael@0: michael@0: } // anon michael@0: michael@0: DOMStorageDBParent::DOMStorageDBParent() michael@0: : mIPCOpen(false) michael@0: { michael@0: DOMStorageObserver* observer = DOMStorageObserver::Self(); michael@0: if (observer) { michael@0: observer->AddSink(this); michael@0: } michael@0: michael@0: // We are always open by IPC only michael@0: AddIPDLReference(); michael@0: michael@0: // Cannot send directly from here since the channel michael@0: // is not completely built at this moment. michael@0: nsRefPtr r = michael@0: new SendInitialChildDataRunnable(this); michael@0: NS_DispatchToCurrentThread(r); michael@0: } michael@0: michael@0: DOMStorageDBParent::~DOMStorageDBParent() michael@0: { michael@0: DOMStorageObserver* observer = DOMStorageObserver::Self(); michael@0: if (observer) { michael@0: observer->RemoveSink(this); michael@0: } michael@0: } michael@0: michael@0: mozilla::ipc::IProtocol* michael@0: DOMStorageDBParent::CloneProtocol(Channel* aChannel, michael@0: mozilla::ipc::ProtocolCloneContext* aCtx) michael@0: { michael@0: ContentParent* contentParent = aCtx->GetContentParent(); michael@0: nsAutoPtr actor(contentParent->AllocPStorageParent()); michael@0: if (!actor || !contentParent->RecvPStorageConstructor(actor)) { michael@0: return nullptr; michael@0: } michael@0: return actor.forget(); michael@0: } michael@0: michael@0: DOMStorageDBParent::CacheParentBridge* michael@0: DOMStorageDBParent::NewCache(const nsACString& aScope) michael@0: { michael@0: return new CacheParentBridge(this, aScope); michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBParent::RecvAsyncPreload(const nsCString& aScope, const bool& aPriority) michael@0: { michael@0: DOMStorageDBBridge* db = DOMStorageCache::StartDatabase(); michael@0: if (!db) { michael@0: return false; michael@0: } michael@0: michael@0: db->AsyncPreload(NewCache(aScope), aPriority); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBParent::RecvAsyncGetUsage(const nsCString& aScope) michael@0: { michael@0: DOMStorageDBBridge* db = DOMStorageCache::StartDatabase(); michael@0: if (!db) { michael@0: return false; michael@0: } michael@0: michael@0: // The object releases it self in LoadUsage method michael@0: nsRefPtr usage = new UsageParentBridge(this, aScope); michael@0: db->AsyncGetUsage(usage); michael@0: return true; michael@0: } michael@0: michael@0: namespace { // anon michael@0: michael@0: // We need another implementation of DOMStorageCacheBridge to do michael@0: // synchronous IPC preload. This class just receives Load* notifications michael@0: // and fills the returning arguments of RecvPreload with the database michael@0: // values for us. michael@0: class SyncLoadCacheHelper : public DOMStorageCacheBridge michael@0: { michael@0: public: michael@0: SyncLoadCacheHelper(const nsCString& aScope, michael@0: uint32_t aAlreadyLoadedCount, michael@0: InfallibleTArray* aKeys, michael@0: InfallibleTArray* aValues, michael@0: nsresult* rv) michael@0: : mMonitor("DOM Storage SyncLoad IPC") michael@0: , mScope(aScope) michael@0: , mKeys(aKeys) michael@0: , mValues(aValues) michael@0: , mRv(rv) michael@0: , mLoaded(false) michael@0: , mLoadedCount(aAlreadyLoadedCount) michael@0: { michael@0: // Precaution michael@0: *mRv = NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: virtual const nsCString& Scope() const { return mScope; } michael@0: virtual bool Loaded() { return mLoaded; } michael@0: virtual uint32_t LoadedCount() { return mLoadedCount; } michael@0: virtual bool LoadItem(const nsAString& aKey, const nsString& aValue) michael@0: { michael@0: // Called on the aCache background thread michael@0: if (mLoaded) { michael@0: return false; michael@0: } michael@0: michael@0: ++mLoadedCount; michael@0: mKeys->AppendElement(aKey); michael@0: mValues->AppendElement(aValue); michael@0: return true; michael@0: } michael@0: michael@0: virtual void LoadDone(nsresult aRv) michael@0: { michael@0: // Called on the aCache background thread michael@0: MonitorAutoLock monitor(mMonitor); michael@0: mLoaded = true; michael@0: *mRv = aRv; michael@0: monitor.Notify(); michael@0: } michael@0: michael@0: virtual void LoadWait() michael@0: { michael@0: // Called on the main thread, exits after LoadDone() call michael@0: MonitorAutoLock monitor(mMonitor); michael@0: while (!mLoaded) { michael@0: monitor.Wait(); michael@0: } michael@0: } michael@0: michael@0: private: michael@0: Monitor mMonitor; michael@0: nsCString mScope; michael@0: InfallibleTArray* mKeys; michael@0: InfallibleTArray* mValues; michael@0: nsresult* mRv; michael@0: bool mLoaded; michael@0: uint32_t mLoadedCount; michael@0: }; michael@0: michael@0: } // anon michael@0: michael@0: bool michael@0: DOMStorageDBParent::RecvPreload(const nsCString& aScope, michael@0: const uint32_t& aAlreadyLoadedCount, michael@0: InfallibleTArray* aKeys, michael@0: InfallibleTArray* aValues, michael@0: nsresult* aRv) michael@0: { michael@0: DOMStorageDBBridge* db = DOMStorageCache::StartDatabase(); michael@0: if (!db) { michael@0: return false; michael@0: } michael@0: michael@0: nsRefPtr cache( michael@0: new SyncLoadCacheHelper(aScope, aAlreadyLoadedCount, aKeys, aValues, aRv)); michael@0: michael@0: db->SyncPreload(cache, true); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBParent::RecvAsyncAddItem(const nsCString& aScope, michael@0: const nsString& aKey, michael@0: const nsString& aValue) michael@0: { michael@0: DOMStorageDBBridge* db = DOMStorageCache::StartDatabase(); michael@0: if (!db) { michael@0: return false; michael@0: } michael@0: michael@0: nsresult rv = db->AsyncAddItem(NewCache(aScope), aKey, aValue); michael@0: if (NS_FAILED(rv) && mIPCOpen) { michael@0: mozilla::unused << SendError(rv); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBParent::RecvAsyncUpdateItem(const nsCString& aScope, michael@0: const nsString& aKey, michael@0: const nsString& aValue) michael@0: { michael@0: DOMStorageDBBridge* db = DOMStorageCache::StartDatabase(); michael@0: if (!db) { michael@0: return false; michael@0: } michael@0: michael@0: nsresult rv = db->AsyncUpdateItem(NewCache(aScope), aKey, aValue); michael@0: if (NS_FAILED(rv) && mIPCOpen) { michael@0: mozilla::unused << SendError(rv); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBParent::RecvAsyncRemoveItem(const nsCString& aScope, michael@0: const nsString& aKey) michael@0: { michael@0: DOMStorageDBBridge* db = DOMStorageCache::StartDatabase(); michael@0: if (!db) { michael@0: return false; michael@0: } michael@0: michael@0: nsresult rv = db->AsyncRemoveItem(NewCache(aScope), aKey); michael@0: if (NS_FAILED(rv) && mIPCOpen) { michael@0: mozilla::unused << SendError(rv); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBParent::RecvAsyncClear(const nsCString& aScope) michael@0: { michael@0: DOMStorageDBBridge* db = DOMStorageCache::StartDatabase(); michael@0: if (!db) { michael@0: return false; michael@0: } michael@0: michael@0: nsresult rv = db->AsyncClear(NewCache(aScope)); michael@0: if (NS_FAILED(rv) && mIPCOpen) { michael@0: mozilla::unused << SendError(rv); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DOMStorageDBParent::RecvAsyncFlush() michael@0: { michael@0: DOMStorageDBBridge* db = DOMStorageCache::GetDatabase(); michael@0: if (!db) { michael@0: return false; michael@0: } michael@0: michael@0: db->AsyncFlush(); michael@0: return true; michael@0: } michael@0: michael@0: // DOMStorageObserverSink michael@0: michael@0: nsresult michael@0: DOMStorageDBParent::Observe(const char* aTopic, michael@0: const nsACString& aScopePrefix) michael@0: { michael@0: if (mIPCOpen) { michael@0: mozilla::unused << SendObserve(nsDependentCString(aTopic), michael@0: nsCString(aScopePrefix)); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: namespace { // anon michael@0: michael@0: // Results must be sent back on the main thread michael@0: class LoadRunnable : public nsRunnable michael@0: { michael@0: public: michael@0: enum TaskType { michael@0: loadItem, michael@0: loadDone michael@0: }; michael@0: michael@0: LoadRunnable(DOMStorageDBParent* aParent, michael@0: TaskType aType, michael@0: const nsACString& aScope, michael@0: const nsAString& aKey = EmptyString(), michael@0: const nsAString& aValue = EmptyString()) michael@0: : mParent(aParent) michael@0: , mType(aType) michael@0: , mScope(aScope) michael@0: , mKey(aKey) michael@0: , mValue(aValue) michael@0: { } michael@0: michael@0: LoadRunnable(DOMStorageDBParent* aParent, michael@0: TaskType aType, michael@0: const nsACString& aScope, michael@0: nsresult aRv) michael@0: : mParent(aParent) michael@0: , mType(aType) michael@0: , mScope(aScope) michael@0: , mRv(aRv) michael@0: { } michael@0: michael@0: private: michael@0: nsRefPtr mParent; michael@0: TaskType mType; michael@0: nsCString mScope; michael@0: nsString mKey; michael@0: nsString mValue; michael@0: nsresult mRv; michael@0: michael@0: NS_IMETHOD Run() michael@0: { michael@0: if (!mParent->IPCOpen()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: switch (mType) michael@0: { michael@0: case loadItem: michael@0: mozilla::unused << mParent->SendLoadItem(mScope, mKey, mValue); michael@0: break; michael@0: case loadDone: michael@0: mozilla::unused << mParent->SendLoadDone(mScope, mRv); michael@0: break; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: } // anon michael@0: michael@0: // DOMStorageDBParent::CacheParentBridge michael@0: michael@0: bool michael@0: DOMStorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey, const nsString& aValue) michael@0: { michael@0: if (mLoaded) { michael@0: return false; michael@0: } michael@0: michael@0: ++mLoadedCount; michael@0: michael@0: nsRefPtr r = michael@0: new LoadRunnable(mParent, LoadRunnable::loadItem, mScope, aKey, aValue); michael@0: NS_DispatchToMainThread(r); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: DOMStorageDBParent::CacheParentBridge::LoadDone(nsresult aRv) michael@0: { michael@0: // Prevent send of duplicate LoadDone. michael@0: if (mLoaded) { michael@0: return; michael@0: } michael@0: michael@0: mLoaded = true; michael@0: michael@0: nsRefPtr r = michael@0: new LoadRunnable(mParent, LoadRunnable::loadDone, mScope, aRv); michael@0: NS_DispatchToMainThread(r); michael@0: } michael@0: michael@0: void michael@0: DOMStorageDBParent::CacheParentBridge::LoadWait() michael@0: { michael@0: // Should never be called on this implementation michael@0: MOZ_ASSERT(false); michael@0: } michael@0: michael@0: // DOMStorageDBParent::UsageParentBridge michael@0: michael@0: namespace { // anon michael@0: michael@0: class UsageRunnable : public nsRunnable michael@0: { michael@0: public: michael@0: UsageRunnable(DOMStorageDBParent* aParent, const nsACString& aScope, const int64_t& aUsage) michael@0: : mParent(aParent) michael@0: , mScope(aScope) michael@0: , mUsage(aUsage) michael@0: {} michael@0: michael@0: private: michael@0: NS_IMETHOD Run() michael@0: { michael@0: if (!mParent->IPCOpen()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: mozilla::unused << mParent->SendLoadUsage(mScope, mUsage); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsRefPtr mParent; michael@0: nsCString mScope; michael@0: int64_t mUsage; michael@0: }; michael@0: michael@0: } // anon michael@0: michael@0: void michael@0: DOMStorageDBParent::UsageParentBridge::LoadUsage(const int64_t aUsage) michael@0: { michael@0: nsRefPtr r = new UsageRunnable(mParent, mScope, aUsage); michael@0: NS_DispatchToMainThread(r); michael@0: } michael@0: michael@0: } // ::dom michael@0: } // ::mozilla