LCOV - code coverage report
Current view: top level - dom/indexedDB - IndexedDatabaseManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 117 542 21.6 %
Date: 2017-07-14 16:53:18 Functions: 15 67 22.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "IndexedDatabaseManager.h"
       8             : 
       9             : #include "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize
      10             : #include "nsIConsoleService.h"
      11             : #include "nsIDiskSpaceWatcher.h"
      12             : #include "nsIDOMWindow.h"
      13             : #include "nsIEventTarget.h"
      14             : #include "nsIFile.h"
      15             : #include "nsIObserverService.h"
      16             : #include "nsIScriptError.h"
      17             : #include "nsIScriptGlobalObject.h"
      18             : 
      19             : #include "jsapi.h"
      20             : #include "mozilla/ClearOnShutdown.h"
      21             : #include "mozilla/CondVar.h"
      22             : #include "mozilla/ContentEvents.h"
      23             : #include "mozilla/EventDispatcher.h"
      24             : #include "mozilla/Preferences.h"
      25             : #include "mozilla/Services.h"
      26             : #include "mozilla/dom/DOMError.h"
      27             : #include "mozilla/dom/ErrorEvent.h"
      28             : #include "mozilla/dom/ErrorEventBinding.h"
      29             : #include "mozilla/dom/quota/QuotaManager.h"
      30             : #include "mozilla/ipc/BackgroundChild.h"
      31             : #include "mozilla/ipc/BackgroundParent.h"
      32             : #include "mozilla/ipc/PBackgroundChild.h"
      33             : #include "nsContentUtils.h"
      34             : #include "nsGlobalWindow.h"
      35             : #include "nsThreadUtils.h"
      36             : #include "mozilla/Logging.h"
      37             : 
      38             : #include "FileInfo.h"
      39             : #include "FileManager.h"
      40             : #include "IDBEvents.h"
      41             : #include "IDBFactory.h"
      42             : #include "IDBKeyRange.h"
      43             : #include "IDBRequest.h"
      44             : #include "ProfilerHelpers.h"
      45             : #include "ScriptErrorHelper.h"
      46             : #include "WorkerScope.h"
      47             : #include "WorkerPrivate.h"
      48             : 
      49             : // Bindings for ResolveConstructors
      50             : #include "mozilla/dom/IDBCursorBinding.h"
      51             : #include "mozilla/dom/IDBDatabaseBinding.h"
      52             : #include "mozilla/dom/IDBFactoryBinding.h"
      53             : #include "mozilla/dom/IDBIndexBinding.h"
      54             : #include "mozilla/dom/IDBKeyRangeBinding.h"
      55             : #include "mozilla/dom/IDBMutableFileBinding.h"
      56             : #include "mozilla/dom/IDBObjectStoreBinding.h"
      57             : #include "mozilla/dom/IDBOpenDBRequestBinding.h"
      58             : #include "mozilla/dom/IDBRequestBinding.h"
      59             : #include "mozilla/dom/IDBTransactionBinding.h"
      60             : #include "mozilla/dom/IDBVersionChangeEventBinding.h"
      61             : 
      62             : #ifdef ENABLE_INTL_API
      63             : #include "nsCharSeparatedTokenizer.h"
      64             : #include "unicode/locid.h"
      65             : #endif
      66             : 
      67             : #define IDB_STR "indexedDB"
      68             : 
      69             : // The two possible values for the data argument when receiving the disk space
      70             : // observer notification.
      71             : #define LOW_DISK_SPACE_DATA_FULL "full"
      72             : #define LOW_DISK_SPACE_DATA_FREE "free"
      73             : 
      74             : namespace mozilla {
      75             : namespace dom {
      76             : namespace indexedDB {
      77             : 
      78             : using namespace mozilla::dom::quota;
      79             : using namespace mozilla::dom::workers;
      80             : using namespace mozilla::ipc;
      81             : 
      82           0 : class FileManagerInfo
      83             : {
      84             : public:
      85             :   already_AddRefed<FileManager>
      86             :   GetFileManager(PersistenceType aPersistenceType,
      87             :                  const nsAString& aName) const;
      88             : 
      89             :   void
      90             :   AddFileManager(FileManager* aFileManager);
      91             : 
      92             :   bool
      93           0 :   HasFileManagers() const
      94             :   {
      95           0 :     AssertIsOnIOThread();
      96             : 
      97           0 :     return !mPersistentStorageFileManagers.IsEmpty() ||
      98           0 :            !mTemporaryStorageFileManagers.IsEmpty() ||
      99           0 :            !mDefaultStorageFileManagers.IsEmpty();
     100             :   }
     101             : 
     102             :   void
     103             :   InvalidateAllFileManagers() const;
     104             : 
     105             :   void
     106             :   InvalidateAndRemoveFileManagers(PersistenceType aPersistenceType);
     107             : 
     108             :   void
     109             :   InvalidateAndRemoveFileManager(PersistenceType aPersistenceType,
     110             :                                  const nsAString& aName);
     111             : 
     112             : private:
     113             :   nsTArray<RefPtr<FileManager> >&
     114             :   GetArray(PersistenceType aPersistenceType);
     115             : 
     116             :   const nsTArray<RefPtr<FileManager> >&
     117           0 :   GetImmutableArray(PersistenceType aPersistenceType) const
     118             :   {
     119           0 :     return const_cast<FileManagerInfo*>(this)->GetArray(aPersistenceType);
     120             :   }
     121             : 
     122             :   nsTArray<RefPtr<FileManager> > mPersistentStorageFileManagers;
     123             :   nsTArray<RefPtr<FileManager> > mTemporaryStorageFileManagers;
     124             :   nsTArray<RefPtr<FileManager> > mDefaultStorageFileManagers;
     125             : };
     126             : 
     127             : } // namespace indexedDB
     128             : 
     129             : using namespace mozilla::dom::indexedDB;
     130             : 
     131             : namespace {
     132             : 
     133             : NS_DEFINE_IID(kIDBRequestIID, PRIVATE_IDBREQUEST_IID);
     134             : 
     135             : const uint32_t kDeleteTimeoutMs = 1000;
     136             : 
     137             : // The threshold we use for structured clone data storing.
     138             : // Anything smaller than the threshold is compressed and stored in the database.
     139             : // Anything larger is compressed and stored outside the database.
     140             : const int32_t kDefaultDataThresholdBytes = 1024 * 1024; // 1MB
     141             : 
     142             : // The maximal size of a serialized object to be transfered through IPC.
     143             : const int32_t kDefaultMaxSerializedMsgSize = IPC::Channel::kMaximumMessageSize;
     144             : 
     145             : #define IDB_PREF_BRANCH_ROOT "dom.indexedDB."
     146             : 
     147             : const char kTestingPref[] = IDB_PREF_BRANCH_ROOT "testing";
     148             : const char kPrefExperimental[] = IDB_PREF_BRANCH_ROOT "experimental";
     149             : const char kPrefFileHandle[] = "dom.fileHandle.enabled";
     150             : const char kDataThresholdPref[] = IDB_PREF_BRANCH_ROOT "dataThreshold";
     151             : const char kPrefMaxSerilizedMsgSize[] = IDB_PREF_BRANCH_ROOT "maxSerializedMsgSize";
     152             : 
     153             : #define IDB_PREF_LOGGING_BRANCH_ROOT IDB_PREF_BRANCH_ROOT "logging."
     154             : 
     155             : const char kPrefLoggingEnabled[] = IDB_PREF_LOGGING_BRANCH_ROOT "enabled";
     156             : const char kPrefLoggingDetails[] = IDB_PREF_LOGGING_BRANCH_ROOT "details";
     157             : 
     158             : #if defined(DEBUG) || defined(MOZ_GECKO_PROFILER)
     159             : const char kPrefLoggingProfiler[] =
     160             :   IDB_PREF_LOGGING_BRANCH_ROOT "profiler-marks";
     161             : #endif
     162             : 
     163             : #undef IDB_PREF_LOGGING_BRANCH_ROOT
     164             : #undef IDB_PREF_BRANCH_ROOT
     165             : 
     166           3 : StaticRefPtr<IndexedDatabaseManager> gDBManager;
     167             : 
     168             : Atomic<bool> gInitialized(false);
     169             : Atomic<bool> gClosed(false);
     170             : Atomic<bool> gTestingMode(false);
     171             : Atomic<bool> gExperimentalFeaturesEnabled(false);
     172             : Atomic<bool> gFileHandleEnabled(false);
     173             : Atomic<int32_t> gDataThresholdBytes(0);
     174             : Atomic<int32_t> gMaxSerializedMsgSize(0);
     175             : 
     176             : class DeleteFilesRunnable final
     177             :   : public nsIRunnable
     178             :   , public OpenDirectoryListener
     179             : {
     180             :   typedef mozilla::dom::quota::DirectoryLock DirectoryLock;
     181             : 
     182             :   enum State
     183             :   {
     184             :     // Just created on the main thread. Next step is State_DirectoryOpenPending.
     185             :     State_Initial,
     186             : 
     187             :     // Waiting for directory open allowed on the main thread. The next step is
     188             :     // State_DatabaseWorkOpen.
     189             :     State_DirectoryOpenPending,
     190             : 
     191             :     // Waiting to do/doing work on the QuotaManager IO thread. The next step is
     192             :     // State_UnblockingOpen.
     193             :     State_DatabaseWorkOpen,
     194             : 
     195             :     // Notifying the QuotaManager that it can proceed to the next operation on
     196             :     // the main thread. Next step is State_Completed.
     197             :     State_UnblockingOpen,
     198             : 
     199             :     // All done.
     200             :     State_Completed
     201             :   };
     202             : 
     203             :   nsCOMPtr<nsIEventTarget> mBackgroundThread;
     204             : 
     205             :   RefPtr<FileManager> mFileManager;
     206             :   nsTArray<int64_t> mFileIds;
     207             : 
     208             :   RefPtr<DirectoryLock> mDirectoryLock;
     209             : 
     210             :   nsCOMPtr<nsIFile> mDirectory;
     211             :   nsCOMPtr<nsIFile> mJournalDirectory;
     212             : 
     213             :   State mState;
     214             : 
     215             : public:
     216             :   DeleteFilesRunnable(nsIEventTarget* aBackgroundThread,
     217             :                       FileManager* aFileManager,
     218             :                       nsTArray<int64_t>& aFileIds);
     219             : 
     220             :   void
     221             :   Dispatch();
     222             : 
     223             :   NS_DECL_THREADSAFE_ISUPPORTS
     224             :   NS_DECL_NSIRUNNABLE
     225             : 
     226             :   virtual void
     227             :   DirectoryLockAcquired(DirectoryLock* aLock) override;
     228             : 
     229             :   virtual void
     230             :   DirectoryLockFailed() override;
     231             : 
     232             : private:
     233           0 :   ~DeleteFilesRunnable() {}
     234             : 
     235             :   nsresult
     236             :   Open();
     237             : 
     238             :   nsresult
     239             :   DeleteFile(int64_t aFileId);
     240             : 
     241             :   nsresult
     242             :   DoDatabaseWork();
     243             : 
     244             :   void
     245             :   Finish();
     246             : 
     247             :   void
     248             :   UnblockOpen();
     249             : };
     250             : 
     251             : void
     252           3 : AtomicBoolPrefChangedCallback(const char* aPrefName, void* aClosure)
     253             : {
     254           3 :   MOZ_ASSERT(NS_IsMainThread());
     255           3 :   MOZ_ASSERT(aClosure);
     256             : 
     257           3 :   *static_cast<Atomic<bool>*>(aClosure) = Preferences::GetBool(aPrefName);
     258           3 : }
     259             : 
     260             : void
     261           1 : DataThresholdPrefChangedCallback(const char* aPrefName, void* aClosure)
     262             : {
     263           1 :   MOZ_ASSERT(NS_IsMainThread());
     264           1 :   MOZ_ASSERT(!strcmp(aPrefName, kDataThresholdPref));
     265           1 :   MOZ_ASSERT(!aClosure);
     266             : 
     267             :   int32_t dataThresholdBytes =
     268           1 :     Preferences::GetInt(aPrefName, kDefaultDataThresholdBytes);
     269             : 
     270             :   // The magic -1 is for use only by tests that depend on stable blob file id's.
     271           1 :   if (dataThresholdBytes == -1) {
     272           0 :     dataThresholdBytes = INT32_MAX;
     273             :   }
     274             : 
     275           1 :   gDataThresholdBytes = dataThresholdBytes;
     276           1 : }
     277             : 
     278             : void
     279           1 : MaxSerializedMsgSizePrefChangeCallback(const char* aPrefName, void* aClosure)
     280             : {
     281           1 :   MOZ_ASSERT(NS_IsMainThread());
     282           1 :   MOZ_ASSERT(!strcmp(aPrefName, kPrefMaxSerilizedMsgSize));
     283           1 :   MOZ_ASSERT(!aClosure);
     284             : 
     285           1 :   gMaxSerializedMsgSize =
     286           1 :     Preferences::GetInt(aPrefName, kDefaultMaxSerializedMsgSize);
     287           1 :   MOZ_ASSERT(gMaxSerializedMsgSize > 0);
     288           1 : }
     289             : 
     290             : } // namespace
     291             : 
     292           1 : IndexedDatabaseManager::IndexedDatabaseManager()
     293             :   : mFileMutex("IndexedDatabaseManager.mFileMutex")
     294           1 :   , mBackgroundActor(nullptr)
     295             : {
     296           1 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     297           1 : }
     298             : 
     299           0 : IndexedDatabaseManager::~IndexedDatabaseManager()
     300             : {
     301           0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     302             : 
     303           0 :   if (mBackgroundActor) {
     304           0 :     mBackgroundActor->SendDeleteMeInternal();
     305           0 :     MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
     306             :   }
     307           0 : }
     308             : 
     309             : bool IndexedDatabaseManager::sIsMainProcess = false;
     310             : bool IndexedDatabaseManager::sFullSynchronousMode = false;
     311             : 
     312             : mozilla::LazyLogModule IndexedDatabaseManager::sLoggingModule("IndexedDB");
     313             : 
     314             : Atomic<IndexedDatabaseManager::LoggingMode>
     315             :   IndexedDatabaseManager::sLoggingMode(
     316             :     IndexedDatabaseManager::Logging_Disabled);
     317             : 
     318             : mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false);
     319             : 
     320             : // static
     321             : IndexedDatabaseManager*
     322          72 : IndexedDatabaseManager::GetOrCreate()
     323             : {
     324          72 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     325             : 
     326          72 :   if (IsClosed()) {
     327           0 :     NS_ERROR("Calling GetOrCreate() after shutdown!");
     328           0 :     return nullptr;
     329             :   }
     330             : 
     331          72 :   if (!gDBManager) {
     332           1 :     sIsMainProcess = XRE_IsParentProcess();
     333             : 
     334           1 :     if (sIsMainProcess && Preferences::GetBool("disk_space_watcher.enabled", false)) {
     335             :       // See if we're starting up in low disk space conditions.
     336             :       nsCOMPtr<nsIDiskSpaceWatcher> watcher =
     337           0 :         do_GetService(DISKSPACEWATCHER_CONTRACTID);
     338           0 :       if (watcher) {
     339             :         bool isDiskFull;
     340           0 :         if (NS_SUCCEEDED(watcher->GetIsDiskFull(&isDiskFull))) {
     341           0 :           sLowDiskSpaceMode = isDiskFull;
     342             :         }
     343             :         else {
     344           0 :           NS_WARNING("GetIsDiskFull failed!");
     345             :         }
     346             :       }
     347             :       else {
     348           0 :         NS_WARNING("No disk space watcher component available!");
     349             :       }
     350             :     }
     351             : 
     352           2 :     RefPtr<IndexedDatabaseManager> instance(new IndexedDatabaseManager());
     353             : 
     354           1 :     nsresult rv = instance->Init();
     355           1 :     NS_ENSURE_SUCCESS(rv, nullptr);
     356             : 
     357           1 :     if (gInitialized.exchange(true)) {
     358           0 :       NS_ERROR("Initialized more than once?!");
     359             :     }
     360             : 
     361           1 :     gDBManager = instance;
     362             : 
     363           1 :     ClearOnShutdown(&gDBManager);
     364             :   }
     365             : 
     366          72 :   return gDBManager;
     367             : }
     368             : 
     369             : // static
     370             : IndexedDatabaseManager*
     371           3 : IndexedDatabaseManager::Get()
     372             : {
     373             :   // Does not return an owning reference.
     374           3 :   return gDBManager;
     375             : }
     376             : 
     377             : nsresult
     378           1 : IndexedDatabaseManager::Init()
     379             : {
     380           1 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     381             : 
     382             :   // During Init() we can't yet call IsMainProcess(), just check sIsMainProcess
     383             :   // directly.
     384           1 :   if (sIsMainProcess) {
     385           2 :     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     386           1 :     NS_ENSURE_STATE(obs);
     387             : 
     388             :     nsresult rv =
     389           1 :       obs->AddObserver(this, DISKSPACEWATCHER_OBSERVER_TOPIC, false);
     390           1 :     NS_ENSURE_SUCCESS(rv, rv);
     391             : 
     392           1 :     mDeleteTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
     393           1 :     NS_ENSURE_STATE(mDeleteTimer);
     394             : 
     395           1 :     if (QuotaManager* quotaManager = QuotaManager::Get()) {
     396           0 :       NoteLiveQuotaManager(quotaManager);
     397             :     }
     398             :   }
     399             : 
     400             :   Preferences::RegisterCallbackAndCall(AtomicBoolPrefChangedCallback,
     401             :                                        kTestingPref,
     402           1 :                                        &gTestingMode);
     403             :   Preferences::RegisterCallbackAndCall(AtomicBoolPrefChangedCallback,
     404             :                                        kPrefExperimental,
     405           1 :                                        &gExperimentalFeaturesEnabled);
     406             :   Preferences::RegisterCallbackAndCall(AtomicBoolPrefChangedCallback,
     407             :                                        kPrefFileHandle,
     408           1 :                                        &gFileHandleEnabled);
     409             : 
     410             :   // By default IndexedDB uses SQLite with PRAGMA synchronous = NORMAL. This
     411             :   // guarantees (unlike synchronous = OFF) atomicity and consistency, but not
     412             :   // necessarily durability in situations such as power loss. This preference
     413             :   // allows enabling PRAGMA synchronous = FULL on SQLite, which does guarantee
     414             :   // durability, but with an extra fsync() and the corresponding performance
     415             :   // hit.
     416           1 :   sFullSynchronousMode = Preferences::GetBool("dom.indexedDB.fullSynchronous");
     417             : 
     418             :   Preferences::RegisterCallback(LoggingModePrefChangedCallback,
     419           1 :                                 kPrefLoggingDetails);
     420             : #ifdef MOZ_GECKO_PROFILER
     421             :   Preferences::RegisterCallback(LoggingModePrefChangedCallback,
     422           1 :                                 kPrefLoggingProfiler);
     423             : #endif
     424             :   Preferences::RegisterCallbackAndCall(LoggingModePrefChangedCallback,
     425           1 :                                        kPrefLoggingEnabled);
     426             : 
     427             :   Preferences::RegisterCallbackAndCall(DataThresholdPrefChangedCallback,
     428           1 :                                        kDataThresholdPref);
     429             : 
     430             :   Preferences::RegisterCallbackAndCall(MaxSerializedMsgSizePrefChangeCallback,
     431           1 :                                        kPrefMaxSerilizedMsgSize);
     432             : 
     433             : #ifdef ENABLE_INTL_API
     434             :   const nsAdoptingCString& acceptLang =
     435           2 :     Preferences::GetLocalizedCString("intl.accept_languages");
     436             : 
     437             :   // Split values on commas.
     438           1 :   nsCCharSeparatedTokenizer langTokenizer(acceptLang, ',');
     439           1 :   while (langTokenizer.hasMoreTokens()) {
     440           1 :     nsAutoCString lang(langTokenizer.nextToken());
     441           1 :     icu::Locale locale = icu::Locale::createCanonical(lang.get());
     442           1 :     if (!locale.isBogus()) {
     443             :       // icu::Locale::getBaseName is always ASCII as per BCP 47
     444           1 :       mLocale.AssignASCII(locale.getBaseName());
     445           1 :       break;
     446             :     }
     447             :   }
     448             : 
     449           1 :   if (mLocale.IsEmpty()) {
     450           0 :     mLocale.AssignLiteral("en_US");
     451             :   }
     452             : #endif
     453             : 
     454           1 :   return NS_OK;
     455             : }
     456             : 
     457             : void
     458           0 : IndexedDatabaseManager::Destroy()
     459             : {
     460             :   // Setting the closed flag prevents the service from being recreated.
     461             :   // Don't set it though if there's no real instance created.
     462           0 :   if (gInitialized && gClosed.exchange(true)) {
     463           0 :     NS_ERROR("Shutdown more than once?!");
     464             :   }
     465             : 
     466           0 :   if (sIsMainProcess && mDeleteTimer) {
     467           0 :     if (NS_FAILED(mDeleteTimer->Cancel())) {
     468           0 :       NS_WARNING("Failed to cancel timer!");
     469             :     }
     470             : 
     471           0 :     mDeleteTimer = nullptr;
     472             :   }
     473             : 
     474             :   Preferences::UnregisterCallback(AtomicBoolPrefChangedCallback,
     475             :                                   kTestingPref,
     476           0 :                                   &gTestingMode);
     477             :   Preferences::UnregisterCallback(AtomicBoolPrefChangedCallback,
     478             :                                   kPrefExperimental,
     479           0 :                                   &gExperimentalFeaturesEnabled);
     480             :   Preferences::UnregisterCallback(AtomicBoolPrefChangedCallback,
     481             :                                   kPrefFileHandle,
     482           0 :                                   &gFileHandleEnabled);
     483             : 
     484             :   Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
     485           0 :                                   kPrefLoggingDetails);
     486             : #ifdef MOZ_GECKO_PROFILER
     487             :   Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
     488           0 :                                   kPrefLoggingProfiler);
     489             : #endif
     490             :   Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
     491           0 :                                   kPrefLoggingEnabled);
     492             : 
     493             :   Preferences::UnregisterCallback(DataThresholdPrefChangedCallback,
     494           0 :                                   kDataThresholdPref);
     495             : 
     496             :   Preferences::UnregisterCallback(MaxSerializedMsgSizePrefChangeCallback,
     497           0 :                                   kPrefMaxSerilizedMsgSize);
     498             : 
     499           0 :   delete this;
     500           0 : }
     501             : 
     502             : // static
     503             : nsresult
     504           0 : IndexedDatabaseManager::CommonPostHandleEvent(EventChainPostVisitor& aVisitor,
     505             :                                               IDBFactory* aFactory)
     506             : {
     507           0 :   MOZ_ASSERT(aVisitor.mDOMEvent);
     508           0 :   MOZ_ASSERT(aFactory);
     509             : 
     510           0 :   if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
     511           0 :     return NS_OK;
     512             :   }
     513             : 
     514           0 :   Event* internalEvent = aVisitor.mDOMEvent->InternalDOMEvent();
     515           0 :   MOZ_ASSERT(internalEvent);
     516             : 
     517           0 :   if (!internalEvent->IsTrusted()) {
     518           0 :     return NS_OK;
     519             :   }
     520             : 
     521           0 :   nsString type;
     522           0 :   MOZ_ALWAYS_SUCCEEDS(internalEvent->GetType(type));
     523             : 
     524           0 :   MOZ_ASSERT(nsDependentString(kErrorEventType).EqualsLiteral("error"));
     525           0 :   if (!type.EqualsLiteral("error")) {
     526           0 :     return NS_OK;
     527             :   }
     528             : 
     529           0 :   nsCOMPtr<EventTarget> eventTarget = internalEvent->GetTarget();
     530           0 :   MOZ_ASSERT(eventTarget);
     531             : 
     532             :   // Only mess with events that were originally targeted to an IDBRequest.
     533           0 :   RefPtr<IDBRequest> request;
     534           0 :   if (NS_FAILED(eventTarget->QueryInterface(kIDBRequestIID,
     535           0 :                                             getter_AddRefs(request))) ||
     536           0 :       !request) {
     537           0 :     return NS_OK;
     538             :   }
     539             : 
     540           0 :   RefPtr<DOMError> error = request->GetErrorAfterResult();
     541             : 
     542           0 :   nsString errorName;
     543           0 :   if (error) {
     544           0 :     error->GetName(errorName);
     545             :   }
     546             : 
     547           0 :   RootedDictionary<ErrorEventInit> init(RootingCx());
     548           0 :   request->GetCallerLocation(init.mFilename, &init.mLineno, &init.mColno);
     549             : 
     550           0 :   init.mMessage = errorName;
     551           0 :   init.mCancelable = true;
     552           0 :   init.mBubbles = true;
     553             : 
     554           0 :   nsEventStatus status = nsEventStatus_eIgnore;
     555             : 
     556           0 :   if (NS_IsMainThread()) {
     557           0 :     nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(eventTarget->GetOwnerGlobal());
     558           0 :     if (window) {
     559           0 :       nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
     560           0 :       MOZ_ASSERT(sgo);
     561             : 
     562           0 :       if (NS_WARN_IF(NS_FAILED(sgo->HandleScriptError(init, &status)))) {
     563           0 :         status = nsEventStatus_eIgnore;
     564             :       }
     565             :     } else {
     566             :       // We don't fire error events at any global for non-window JS on the main
     567             :       // thread.
     568             :     }
     569             :   } else {
     570             :     // Not on the main thread, must be in a worker.
     571           0 :     WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     572           0 :     MOZ_ASSERT(workerPrivate);
     573             : 
     574           0 :     RefPtr<WorkerGlobalScope> globalScope = workerPrivate->GlobalScope();
     575           0 :     MOZ_ASSERT(globalScope);
     576             : 
     577             :     RefPtr<ErrorEvent> errorEvent =
     578           0 :       ErrorEvent::Constructor(globalScope,
     579           0 :                               nsDependentString(kErrorEventType),
     580           0 :                               init);
     581           0 :     MOZ_ASSERT(errorEvent);
     582             : 
     583           0 :     errorEvent->SetTrusted(true);
     584             : 
     585           0 :     auto* target = static_cast<EventTarget*>(globalScope.get());
     586             : 
     587           0 :     if (NS_WARN_IF(NS_FAILED(
     588             :       EventDispatcher::DispatchDOMEvent(target,
     589             :                                         /* aWidgetEvent */ nullptr,
     590             :                                         errorEvent,
     591             :                                         /* aPresContext */ nullptr,
     592             :                                         &status)))) {
     593           0 :       status = nsEventStatus_eIgnore;
     594             :     }
     595             :   }
     596             : 
     597           0 :   if (status == nsEventStatus_eConsumeNoDefault) {
     598           0 :     return NS_OK;
     599             :   }
     600             : 
     601             :   // Log the error to the error console.
     602           0 :   ScriptErrorHelper::Dump(errorName,
     603             :                           init.mFilename,
     604             :                           init.mLineno,
     605             :                           init.mColno,
     606             :                           nsIScriptError::errorFlag,
     607           0 :                           aFactory->IsChrome(),
     608           0 :                           aFactory->InnerWindowID());
     609             : 
     610           0 :   return NS_OK;
     611             : }
     612             : 
     613             : // static
     614             : bool
     615          14 : IndexedDatabaseManager::ResolveSandboxBinding(JSContext* aCx)
     616             : {
     617          14 :   MOZ_ASSERT(NS_IsMainThread());
     618          14 :   MOZ_ASSERT(js::GetObjectClass(JS::CurrentGlobalOrNull(aCx))->flags &
     619             :              JSCLASS_DOM_GLOBAL,
     620             :              "Passed object is not a global object!");
     621             : 
     622             :   // We need to ensure that the manager has been created already here so that we
     623             :   // load preferences that may control which properties are exposed.
     624          14 :   if (NS_WARN_IF(!GetOrCreate())) {
     625           0 :     return false;
     626             :   }
     627             : 
     628          42 :   if (!IDBCursorBinding::GetConstructorObject(aCx) ||
     629          28 :       !IDBCursorWithValueBinding::GetConstructorObject(aCx) ||
     630          28 :       !IDBDatabaseBinding::GetConstructorObject(aCx) ||
     631          28 :       !IDBFactoryBinding::GetConstructorObject(aCx) ||
     632          28 :       !IDBIndexBinding::GetConstructorObject(aCx) ||
     633          28 :       !IDBKeyRangeBinding::GetConstructorObject(aCx) ||
     634          28 :       !IDBLocaleAwareKeyRangeBinding::GetConstructorObject(aCx) ||
     635          28 :       !IDBMutableFileBinding::GetConstructorObject(aCx) ||
     636          28 :       !IDBObjectStoreBinding::GetConstructorObject(aCx) ||
     637          28 :       !IDBOpenDBRequestBinding::GetConstructorObject(aCx) ||
     638          28 :       !IDBRequestBinding::GetConstructorObject(aCx) ||
     639          42 :       !IDBTransactionBinding::GetConstructorObject(aCx) ||
     640          14 :       !IDBVersionChangeEventBinding::GetConstructorObject(aCx))
     641             :   {
     642           0 :     return false;
     643             :   }
     644             : 
     645          14 :   return true;
     646             : }
     647             : 
     648             : // static
     649             : bool
     650          14 : IndexedDatabaseManager::DefineIndexedDB(JSContext* aCx,
     651             :                                         JS::Handle<JSObject*> aGlobal)
     652             : {
     653          14 :   MOZ_ASSERT(NS_IsMainThread());
     654          14 :   MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
     655             :              "Passed object is not a global object!");
     656             : 
     657          28 :   RefPtr<IDBFactory> factory;
     658          14 :   if (NS_FAILED(IDBFactory::CreateForMainThreadJS(aCx,
     659             :                                                   aGlobal,
     660             :                                                   getter_AddRefs(factory)))) {
     661           0 :     return false;
     662             :   }
     663             : 
     664          14 :   MOZ_ASSERT(factory, "This should never fail for chrome!");
     665             : 
     666          28 :   JS::Rooted<JS::Value> indexedDB(aCx);
     667          14 :   js::AssertSameCompartment(aCx, aGlobal);
     668          14 :   if (!GetOrCreateDOMReflector(aCx, factory, &indexedDB)) {
     669           0 :     return false;
     670             :   }
     671             : 
     672          14 :   return JS_DefineProperty(aCx, aGlobal, IDB_STR, indexedDB, JSPROP_ENUMERATE);
     673             : }
     674             : 
     675             : // static
     676             : bool
     677          72 : IndexedDatabaseManager::IsClosed()
     678             : {
     679          72 :   return gClosed;
     680             : }
     681             : 
     682             : #ifdef DEBUG
     683             : // static
     684             : bool
     685           0 : IndexedDatabaseManager::IsMainProcess()
     686             : {
     687           0 :   NS_ASSERTION(gDBManager,
     688             :                "IsMainProcess() called before indexedDB has been initialized!");
     689           0 :   NS_ASSERTION((XRE_IsParentProcess()) ==
     690             :                sIsMainProcess, "XRE_GetProcessType changed its tune!");
     691           0 :   return sIsMainProcess;
     692             : }
     693             : 
     694             : //static
     695             : bool
     696           0 : IndexedDatabaseManager::InLowDiskSpaceMode()
     697             : {
     698           0 :   NS_ASSERTION(gDBManager,
     699             :                "InLowDiskSpaceMode() called before indexedDB has been "
     700             :                "initialized!");
     701           0 :   return sLowDiskSpaceMode;
     702             : }
     703             : 
     704             : // static
     705             : IndexedDatabaseManager::LoggingMode
     706           0 : IndexedDatabaseManager::GetLoggingMode()
     707             : {
     708           0 :   MOZ_ASSERT(gDBManager,
     709             :              "GetLoggingMode called before IndexedDatabaseManager has been "
     710             :              "initialized!");
     711             : 
     712           0 :   return sLoggingMode;
     713             : }
     714             : 
     715             : // static
     716             : mozilla::LogModule*
     717           0 : IndexedDatabaseManager::GetLoggingModule()
     718             : {
     719           0 :   MOZ_ASSERT(gDBManager,
     720             :              "GetLoggingModule called before IndexedDatabaseManager has been "
     721             :              "initialized!");
     722             : 
     723           0 :   return sLoggingModule;
     724             : }
     725             : 
     726             : #endif // DEBUG
     727             : 
     728             : // static
     729             : bool
     730           0 : IndexedDatabaseManager::InTestingMode()
     731             : {
     732           0 :   MOZ_ASSERT(gDBManager,
     733             :              "InTestingMode() called before indexedDB has been initialized!");
     734             : 
     735           0 :   return gTestingMode;
     736             : }
     737             : 
     738             : // static
     739             : bool
     740           0 : IndexedDatabaseManager::FullSynchronous()
     741             : {
     742           0 :   MOZ_ASSERT(gDBManager,
     743             :              "FullSynchronous() called before indexedDB has been initialized!");
     744             : 
     745           0 :   return sFullSynchronousMode;
     746             : }
     747             : 
     748             : // static
     749             : bool
     750          31 : IndexedDatabaseManager::ExperimentalFeaturesEnabled()
     751             : {
     752          31 :   if (NS_IsMainThread()) {
     753          28 :     if (NS_WARN_IF(!GetOrCreate())) {
     754           0 :       return false;
     755             :     }
     756             :   } else {
     757           3 :     MOZ_ASSERT(Get(),
     758             :                "ExperimentalFeaturesEnabled() called off the main thread "
     759             :                "before indexedDB has been initialized!");
     760             :   }
     761             : 
     762          31 :   return gExperimentalFeaturesEnabled;
     763             : }
     764             : 
     765             : // static
     766             : bool
     767          31 : IndexedDatabaseManager::ExperimentalFeaturesEnabled(JSContext* aCx, JSObject* aGlobal)
     768             : {
     769             :   // If, in the child process, properties of the global object are enumerated
     770             :   // before the chrome registry (and thus the value of |intl.accept_languages|)
     771             :   // is ready, calling IndexedDatabaseManager::Init will permanently break
     772             :   // that preference. We can retrieve gExperimentalFeaturesEnabled without
     773             :   // actually going through IndexedDatabaseManager.
     774             :   // See Bug 1198093 comment 14 for detailed explanation.
     775          31 :   if (IsNonExposedGlobal(aCx, js::GetGlobalForObjectCrossCompartment(aGlobal),
     776             :                          GlobalNames::BackstagePass)) {
     777           0 :     MOZ_ASSERT(NS_IsMainThread());
     778             :     static bool featureRetrieved = false;
     779           0 :     if (!featureRetrieved) {
     780           0 :       gExperimentalFeaturesEnabled = Preferences::GetBool(kPrefExperimental);
     781           0 :       featureRetrieved = true;
     782             :     }
     783           0 :     return gExperimentalFeaturesEnabled;
     784             :   }
     785             : 
     786          31 :   return ExperimentalFeaturesEnabled();
     787             : }
     788             : 
     789             : // static
     790             : bool
     791           0 : IndexedDatabaseManager::IsFileHandleEnabled()
     792             : {
     793           0 :   MOZ_ASSERT(gDBManager,
     794             :              "IsFileHandleEnabled() called before indexedDB has been "
     795             :              "initialized!");
     796             : 
     797           0 :   return gFileHandleEnabled;
     798             : }
     799             : 
     800             : // static
     801             : uint32_t
     802           0 : IndexedDatabaseManager::DataThreshold()
     803             : {
     804           0 :   MOZ_ASSERT(gDBManager,
     805             :              "DataThreshold() called before indexedDB has been initialized!");
     806             : 
     807           0 :   return gDataThresholdBytes;
     808             : }
     809             : 
     810             : // static
     811             : uint32_t
     812           0 : IndexedDatabaseManager::MaxSerializedMsgSize()
     813             : {
     814           0 :   MOZ_ASSERT(gDBManager,
     815             :              "MaxSerializedMsgSize() called before indexedDB has been initialized!");
     816           0 :   MOZ_ASSERT(gMaxSerializedMsgSize > 0);
     817             : 
     818           0 :   return gMaxSerializedMsgSize;
     819             : }
     820             : 
     821             : void
     822           0 : IndexedDatabaseManager::ClearBackgroundActor()
     823             : {
     824           0 :   MOZ_ASSERT(NS_IsMainThread());
     825             : 
     826           0 :   mBackgroundActor = nullptr;
     827           0 : }
     828             : 
     829             : void
     830           0 : IndexedDatabaseManager::NoteLiveQuotaManager(QuotaManager* aQuotaManager)
     831             : {
     832           0 :   MOZ_ASSERT(IsMainProcess());
     833           0 :   MOZ_ASSERT(NS_IsMainThread());
     834           0 :   MOZ_ASSERT(aQuotaManager);
     835             : 
     836           0 :   mBackgroundThread = aQuotaManager->OwningThread();
     837           0 : }
     838             : 
     839             : void
     840           0 : IndexedDatabaseManager::NoteShuttingDownQuotaManager()
     841             : {
     842           0 :   MOZ_ASSERT(IsMainProcess());
     843           0 :   MOZ_ASSERT(NS_IsMainThread());
     844             : 
     845           0 :   MOZ_ALWAYS_SUCCEEDS(mDeleteTimer->Cancel());
     846             : 
     847           0 :   mBackgroundThread = nullptr;
     848           0 : }
     849             : 
     850             : already_AddRefed<FileManager>
     851           0 : IndexedDatabaseManager::GetFileManager(PersistenceType aPersistenceType,
     852             :                                        const nsACString& aOrigin,
     853             :                                        const nsAString& aDatabaseName)
     854             : {
     855           0 :   AssertIsOnIOThread();
     856             : 
     857             :   FileManagerInfo* info;
     858           0 :   if (!mFileManagerInfos.Get(aOrigin, &info)) {
     859           0 :     return nullptr;
     860             :   }
     861             : 
     862             :   RefPtr<FileManager> fileManager =
     863           0 :     info->GetFileManager(aPersistenceType, aDatabaseName);
     864             : 
     865           0 :   return fileManager.forget();
     866             : }
     867             : 
     868             : void
     869           0 : IndexedDatabaseManager::AddFileManager(FileManager* aFileManager)
     870             : {
     871           0 :   AssertIsOnIOThread();
     872           0 :   NS_ASSERTION(aFileManager, "Null file manager!");
     873             : 
     874             :   FileManagerInfo* info;
     875           0 :   if (!mFileManagerInfos.Get(aFileManager->Origin(), &info)) {
     876           0 :     info = new FileManagerInfo();
     877           0 :     mFileManagerInfos.Put(aFileManager->Origin(), info);
     878             :   }
     879             : 
     880           0 :   info->AddFileManager(aFileManager);
     881           0 : }
     882             : 
     883             : void
     884           0 : IndexedDatabaseManager::InvalidateAllFileManagers()
     885             : {
     886           0 :   AssertIsOnIOThread();
     887             : 
     888           0 :   for (auto iter = mFileManagerInfos.ConstIter(); !iter.Done(); iter.Next()) {
     889           0 :     auto value = iter.Data();
     890           0 :     MOZ_ASSERT(value);
     891             : 
     892           0 :     value->InvalidateAllFileManagers();
     893             :   }
     894             : 
     895           0 :   mFileManagerInfos.Clear();
     896           0 : }
     897             : 
     898             : void
     899           0 : IndexedDatabaseManager::InvalidateFileManagers(PersistenceType aPersistenceType,
     900             :                                                const nsACString& aOrigin)
     901             : {
     902           0 :   AssertIsOnIOThread();
     903           0 :   MOZ_ASSERT(!aOrigin.IsEmpty());
     904             : 
     905             :   FileManagerInfo* info;
     906           0 :   if (!mFileManagerInfos.Get(aOrigin, &info)) {
     907           0 :     return;
     908             :   }
     909             : 
     910           0 :   info->InvalidateAndRemoveFileManagers(aPersistenceType);
     911             : 
     912           0 :   if (!info->HasFileManagers()) {
     913           0 :     mFileManagerInfos.Remove(aOrigin);
     914             :   }
     915             : }
     916             : 
     917             : void
     918           0 : IndexedDatabaseManager::InvalidateFileManager(PersistenceType aPersistenceType,
     919             :                                               const nsACString& aOrigin,
     920             :                                               const nsAString& aDatabaseName)
     921             : {
     922           0 :   AssertIsOnIOThread();
     923             : 
     924             :   FileManagerInfo* info;
     925           0 :   if (!mFileManagerInfos.Get(aOrigin, &info)) {
     926           0 :     return;
     927             :   }
     928             : 
     929           0 :   info->InvalidateAndRemoveFileManager(aPersistenceType, aDatabaseName);
     930             : 
     931           0 :   if (!info->HasFileManagers()) {
     932           0 :     mFileManagerInfos.Remove(aOrigin);
     933             :   }
     934             : }
     935             : 
     936             : nsresult
     937           0 : IndexedDatabaseManager::AsyncDeleteFile(FileManager* aFileManager,
     938             :                                         int64_t aFileId)
     939             : {
     940           0 :   MOZ_ASSERT(IsMainProcess());
     941           0 :   MOZ_ASSERT(NS_IsMainThread());
     942           0 :   MOZ_ASSERT(aFileManager);
     943           0 :   MOZ_ASSERT(aFileId > 0);
     944           0 :   MOZ_ASSERT(mDeleteTimer);
     945             : 
     946           0 :   if (!mBackgroundThread) {
     947           0 :     return NS_OK;
     948             :   }
     949             : 
     950           0 :   nsresult rv = mDeleteTimer->Cancel();
     951           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     952           0 :     return rv;
     953             :   }
     954             : 
     955           0 :   rv = mDeleteTimer->InitWithCallback(this, kDeleteTimeoutMs,
     956           0 :                                       nsITimer::TYPE_ONE_SHOT);
     957           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     958           0 :     return rv;
     959             :   }
     960             : 
     961             :   nsTArray<int64_t>* array;
     962           0 :   if (!mPendingDeleteInfos.Get(aFileManager, &array)) {
     963           0 :     array = new nsTArray<int64_t>();
     964           0 :     mPendingDeleteInfos.Put(aFileManager, array);
     965             :   }
     966             : 
     967           0 :   array->AppendElement(aFileId);
     968             : 
     969           0 :   return NS_OK;
     970             : }
     971             : 
     972             : nsresult
     973           0 : IndexedDatabaseManager::BlockAndGetFileReferences(
     974             :                                                PersistenceType aPersistenceType,
     975             :                                                const nsACString& aOrigin,
     976             :                                                const nsAString& aDatabaseName,
     977             :                                                int64_t aFileId,
     978             :                                                int32_t* aRefCnt,
     979             :                                                int32_t* aDBRefCnt,
     980             :                                                int32_t* aSliceRefCnt,
     981             :                                                bool* aResult)
     982             : {
     983           0 :   MOZ_ASSERT(NS_IsMainThread());
     984             : 
     985           0 :   if (NS_WARN_IF(!InTestingMode())) {
     986           0 :     return NS_ERROR_UNEXPECTED;
     987             :   }
     988             : 
     989           0 :   if (!mBackgroundActor) {
     990           0 :     PBackgroundChild* bgActor = BackgroundChild::GetForCurrentThread();
     991           0 :     if (NS_WARN_IF(!bgActor)) {
     992           0 :       return NS_ERROR_FAILURE;
     993             :     }
     994             : 
     995           0 :     BackgroundUtilsChild* actor = new BackgroundUtilsChild(this);
     996             : 
     997             :     // We don't set event target for BackgroundUtilsChild because:
     998             :     // 1. BackgroundUtilsChild is a singleton.
     999             :     // 2. SendGetFileReferences is a sync operation to be returned asap if unlabeled.
    1000             :     // 3. The rest operations like DeleteMe/__delete__ only happens at shutdown.
    1001             :     // Hence, we should keep it unlabeled.
    1002           0 :     mBackgroundActor =
    1003             :       static_cast<BackgroundUtilsChild*>(
    1004           0 :         bgActor->SendPBackgroundIndexedDBUtilsConstructor(actor));
    1005             :   }
    1006             : 
    1007           0 :   if (NS_WARN_IF(!mBackgroundActor)) {
    1008           0 :     return NS_ERROR_FAILURE;
    1009             :   }
    1010             : 
    1011           0 :   if (!mBackgroundActor->SendGetFileReferences(aPersistenceType,
    1012           0 :                                                nsCString(aOrigin),
    1013           0 :                                                nsString(aDatabaseName),
    1014             :                                                aFileId,
    1015             :                                                aRefCnt,
    1016             :                                                aDBRefCnt,
    1017             :                                                aSliceRefCnt,
    1018             :                                                aResult)) {
    1019           0 :     return NS_ERROR_FAILURE;
    1020             :   }
    1021             : 
    1022           0 :   return NS_OK;
    1023             : }
    1024             : 
    1025             : nsresult
    1026           0 : IndexedDatabaseManager::FlushPendingFileDeletions()
    1027             : {
    1028           0 :   MOZ_ASSERT(NS_IsMainThread());
    1029             : 
    1030           0 :   if (NS_WARN_IF(!InTestingMode())) {
    1031           0 :     return NS_ERROR_UNEXPECTED;
    1032             :   }
    1033             : 
    1034           0 :   if (IsMainProcess()) {
    1035           0 :     nsresult rv = mDeleteTimer->Cancel();
    1036           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1037           0 :       return rv;
    1038             :     }
    1039             : 
    1040           0 :     rv = Notify(mDeleteTimer);
    1041           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1042           0 :       return rv;
    1043             :     }
    1044             :   } else {
    1045           0 :     PBackgroundChild* bgActor = BackgroundChild::GetForCurrentThread();
    1046           0 :     if (NS_WARN_IF(!bgActor)) {
    1047           0 :       return NS_ERROR_FAILURE;
    1048             :     }
    1049             : 
    1050           0 :     if (!bgActor->SendFlushPendingFileDeletions()) {
    1051           0 :       return NS_ERROR_FAILURE;
    1052             :     }
    1053             :   }
    1054             : 
    1055           0 :   return NS_OK;
    1056             : }
    1057             : 
    1058             : // static
    1059             : void
    1060           1 : IndexedDatabaseManager::LoggingModePrefChangedCallback(
    1061             :                                                     const char* /* aPrefName */,
    1062             :                                                     void* /* aClosure */)
    1063             : {
    1064           1 :   MOZ_ASSERT(NS_IsMainThread());
    1065             : 
    1066           1 :   if (!Preferences::GetBool(kPrefLoggingEnabled)) {
    1067           0 :     sLoggingMode = Logging_Disabled;
    1068           0 :     return;
    1069             :   }
    1070             : 
    1071             :   bool useProfiler =
    1072             : #if defined(DEBUG) || defined(MOZ_GECKO_PROFILER)
    1073           1 :     Preferences::GetBool(kPrefLoggingProfiler);
    1074             : #if !defined(MOZ_GECKO_PROFILER)
    1075             :   if (useProfiler) {
    1076             :     NS_WARNING("IndexedDB cannot create profiler marks because this build does "
    1077             :                "not have profiler extensions enabled!");
    1078             :     useProfiler = false;
    1079             :   }
    1080             : #endif
    1081             : #else
    1082             :     false;
    1083             : #endif
    1084             : 
    1085           1 :   const bool logDetails = Preferences::GetBool(kPrefLoggingDetails);
    1086             : 
    1087           1 :   if (useProfiler) {
    1088           0 :     sLoggingMode = logDetails ?
    1089             :                    Logging_DetailedProfilerMarks :
    1090           0 :                    Logging_ConciseProfilerMarks;
    1091             :   } else {
    1092           1 :     sLoggingMode = logDetails ? Logging_Detailed : Logging_Concise;
    1093             :   }
    1094             : }
    1095             : 
    1096             : #ifdef ENABLE_INTL_API
    1097             : // static
    1098             : const nsCString&
    1099           0 : IndexedDatabaseManager::GetLocale()
    1100             : {
    1101           0 :   IndexedDatabaseManager* idbManager = Get();
    1102           0 :   MOZ_ASSERT(idbManager, "IDBManager is not ready!");
    1103             : 
    1104           0 :   return idbManager->mLocale;
    1105             : }
    1106             : #endif
    1107             : 
    1108           3 : NS_IMPL_ADDREF(IndexedDatabaseManager)
    1109           1 : NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())
    1110           0 : NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIObserver, nsITimerCallback)
    1111             : 
    1112             : NS_IMETHODIMP
    1113           0 : IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic,
    1114             :                                 const char16_t* aData)
    1115             : {
    1116           0 :   NS_ASSERTION(IsMainProcess(), "Wrong process!");
    1117           0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1118             : 
    1119           0 :   if (!strcmp(aTopic, DISKSPACEWATCHER_OBSERVER_TOPIC)) {
    1120           0 :     NS_ASSERTION(aData, "No data?!");
    1121             : 
    1122           0 :     const nsDependentString data(aData);
    1123             : 
    1124           0 :     if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FULL)) {
    1125           0 :       sLowDiskSpaceMode = true;
    1126             :     }
    1127           0 :     else if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FREE)) {
    1128           0 :       sLowDiskSpaceMode = false;
    1129             :     }
    1130             :     else {
    1131           0 :       NS_NOTREACHED("Unknown data value!");
    1132             :     }
    1133             : 
    1134           0 :     return NS_OK;
    1135             :   }
    1136             : 
    1137           0 :    NS_NOTREACHED("Unknown topic!");
    1138           0 :    return NS_ERROR_UNEXPECTED;
    1139             : }
    1140             : 
    1141             : NS_IMETHODIMP
    1142           0 : IndexedDatabaseManager::Notify(nsITimer* aTimer)
    1143             : {
    1144           0 :   MOZ_ASSERT(IsMainProcess());
    1145           0 :   MOZ_ASSERT(NS_IsMainThread());
    1146           0 :   MOZ_ASSERT(mBackgroundThread);
    1147             : 
    1148           0 :   for (auto iter = mPendingDeleteInfos.ConstIter(); !iter.Done(); iter.Next()) {
    1149           0 :     auto key = iter.Key();
    1150           0 :     auto value = iter.Data();
    1151           0 :     MOZ_ASSERT(!value->IsEmpty());
    1152             : 
    1153             :     RefPtr<DeleteFilesRunnable> runnable =
    1154           0 :       new DeleteFilesRunnable(mBackgroundThread, key, *value);
    1155             : 
    1156           0 :     MOZ_ASSERT(value->IsEmpty());
    1157             : 
    1158           0 :     runnable->Dispatch();
    1159             :   }
    1160             : 
    1161           0 :   mPendingDeleteInfos.Clear();
    1162             : 
    1163           0 :   return NS_OK;
    1164             : }
    1165             : 
    1166             : already_AddRefed<FileManager>
    1167           0 : FileManagerInfo::GetFileManager(PersistenceType aPersistenceType,
    1168             :                                 const nsAString& aName) const
    1169             : {
    1170           0 :   AssertIsOnIOThread();
    1171             : 
    1172             :   const nsTArray<RefPtr<FileManager> >& managers =
    1173           0 :     GetImmutableArray(aPersistenceType);
    1174             : 
    1175           0 :   for (uint32_t i = 0; i < managers.Length(); i++) {
    1176           0 :     const RefPtr<FileManager>& fileManager = managers[i];
    1177             : 
    1178           0 :     if (fileManager->DatabaseName() == aName) {
    1179           0 :       RefPtr<FileManager> result = fileManager;
    1180           0 :       return result.forget();
    1181             :     }
    1182             :   }
    1183             : 
    1184           0 :   return nullptr;
    1185             : }
    1186             : 
    1187             : void
    1188           0 : FileManagerInfo::AddFileManager(FileManager* aFileManager)
    1189             : {
    1190           0 :   AssertIsOnIOThread();
    1191             : 
    1192           0 :   nsTArray<RefPtr<FileManager> >& managers = GetArray(aFileManager->Type());
    1193             : 
    1194           0 :   NS_ASSERTION(!managers.Contains(aFileManager), "Adding more than once?!");
    1195             : 
    1196           0 :   managers.AppendElement(aFileManager);
    1197           0 : }
    1198             : 
    1199             : void
    1200           0 : FileManagerInfo::InvalidateAllFileManagers() const
    1201             : {
    1202           0 :   AssertIsOnIOThread();
    1203             : 
    1204             :   uint32_t i;
    1205             : 
    1206           0 :   for (i = 0; i < mPersistentStorageFileManagers.Length(); i++) {
    1207           0 :     mPersistentStorageFileManagers[i]->Invalidate();
    1208             :   }
    1209             : 
    1210           0 :   for (i = 0; i < mTemporaryStorageFileManagers.Length(); i++) {
    1211           0 :     mTemporaryStorageFileManagers[i]->Invalidate();
    1212             :   }
    1213             : 
    1214           0 :   for (i = 0; i < mDefaultStorageFileManagers.Length(); i++) {
    1215           0 :     mDefaultStorageFileManagers[i]->Invalidate();
    1216             :   }
    1217           0 : }
    1218             : 
    1219             : void
    1220           0 : FileManagerInfo::InvalidateAndRemoveFileManagers(
    1221             :                                                PersistenceType aPersistenceType)
    1222             : {
    1223           0 :   AssertIsOnIOThread();
    1224             : 
    1225           0 :   nsTArray<RefPtr<FileManager > >& managers = GetArray(aPersistenceType);
    1226             : 
    1227           0 :   for (uint32_t i = 0; i < managers.Length(); i++) {
    1228           0 :     managers[i]->Invalidate();
    1229             :   }
    1230             : 
    1231           0 :   managers.Clear();
    1232           0 : }
    1233             : 
    1234             : void
    1235           0 : FileManagerInfo::InvalidateAndRemoveFileManager(
    1236             :                                                PersistenceType aPersistenceType,
    1237             :                                                const nsAString& aName)
    1238             : {
    1239           0 :   AssertIsOnIOThread();
    1240             : 
    1241           0 :   nsTArray<RefPtr<FileManager > >& managers = GetArray(aPersistenceType);
    1242             : 
    1243           0 :   for (uint32_t i = 0; i < managers.Length(); i++) {
    1244           0 :     RefPtr<FileManager>& fileManager = managers[i];
    1245           0 :     if (fileManager->DatabaseName() == aName) {
    1246           0 :       fileManager->Invalidate();
    1247           0 :       managers.RemoveElementAt(i);
    1248           0 :       return;
    1249             :     }
    1250             :   }
    1251             : }
    1252             : 
    1253             : nsTArray<RefPtr<FileManager> >&
    1254           0 : FileManagerInfo::GetArray(PersistenceType aPersistenceType)
    1255             : {
    1256           0 :   switch (aPersistenceType) {
    1257             :     case PERSISTENCE_TYPE_PERSISTENT:
    1258           0 :       return mPersistentStorageFileManagers;
    1259             :     case PERSISTENCE_TYPE_TEMPORARY:
    1260           0 :       return mTemporaryStorageFileManagers;
    1261             :     case PERSISTENCE_TYPE_DEFAULT:
    1262           0 :       return mDefaultStorageFileManagers;
    1263             : 
    1264             :     case PERSISTENCE_TYPE_INVALID:
    1265             :     default:
    1266           0 :       MOZ_CRASH("Bad storage type value!");
    1267             :   }
    1268             : }
    1269             : 
    1270           0 : DeleteFilesRunnable::DeleteFilesRunnable(nsIEventTarget* aBackgroundThread,
    1271             :                                          FileManager* aFileManager,
    1272           0 :                                          nsTArray<int64_t>& aFileIds)
    1273             :   : mBackgroundThread(aBackgroundThread)
    1274             :   , mFileManager(aFileManager)
    1275           0 :   , mState(State_Initial)
    1276             : {
    1277           0 :   mFileIds.SwapElements(aFileIds);
    1278           0 : }
    1279             : 
    1280             : void
    1281           0 : DeleteFilesRunnable::Dispatch()
    1282             : {
    1283           0 :   MOZ_ASSERT(NS_IsMainThread());
    1284           0 :   MOZ_ASSERT(mState == State_Initial);
    1285             : 
    1286           0 :   MOZ_ALWAYS_SUCCEEDS(mBackgroundThread->Dispatch(this, NS_DISPATCH_NORMAL));
    1287           0 : }
    1288             : 
    1289           0 : NS_IMPL_ISUPPORTS(DeleteFilesRunnable, nsIRunnable)
    1290             : 
    1291             : NS_IMETHODIMP
    1292           0 : DeleteFilesRunnable::Run()
    1293             : {
    1294             :   nsresult rv;
    1295             : 
    1296           0 :   switch (mState) {
    1297             :     case State_Initial:
    1298           0 :       rv = Open();
    1299           0 :       break;
    1300             : 
    1301             :     case State_DatabaseWorkOpen:
    1302           0 :       rv = DoDatabaseWork();
    1303           0 :       break;
    1304             : 
    1305             :     case State_UnblockingOpen:
    1306           0 :       UnblockOpen();
    1307           0 :       return NS_OK;
    1308             : 
    1309             :     case State_DirectoryOpenPending:
    1310             :     default:
    1311           0 :       MOZ_CRASH("Should never get here!");
    1312             :   }
    1313             : 
    1314           0 :   if (NS_WARN_IF(NS_FAILED(rv)) && mState != State_UnblockingOpen) {
    1315           0 :     Finish();
    1316             :   }
    1317             : 
    1318           0 :   return NS_OK;
    1319             : }
    1320             : 
    1321             : void
    1322           0 : DeleteFilesRunnable::DirectoryLockAcquired(DirectoryLock* aLock)
    1323             : {
    1324           0 :   AssertIsOnBackgroundThread();
    1325           0 :   MOZ_ASSERT(mState == State_DirectoryOpenPending);
    1326           0 :   MOZ_ASSERT(!mDirectoryLock);
    1327             : 
    1328           0 :   mDirectoryLock = aLock;
    1329             : 
    1330           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    1331           0 :   MOZ_ASSERT(quotaManager);
    1332             : 
    1333             :   // Must set this before dispatching otherwise we will race with the IO thread
    1334           0 :   mState = State_DatabaseWorkOpen;
    1335             : 
    1336           0 :   nsresult rv = quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
    1337           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1338           0 :     Finish();
    1339           0 :     return;
    1340             :   }
    1341             : }
    1342             : 
    1343             : void
    1344           0 : DeleteFilesRunnable::DirectoryLockFailed()
    1345             : {
    1346           0 :   AssertIsOnBackgroundThread();
    1347           0 :   MOZ_ASSERT(mState == State_DirectoryOpenPending);
    1348           0 :   MOZ_ASSERT(!mDirectoryLock);
    1349             : 
    1350           0 :   Finish();
    1351           0 : }
    1352             : 
    1353             : nsresult
    1354           0 : DeleteFilesRunnable::Open()
    1355             : {
    1356           0 :   AssertIsOnBackgroundThread();
    1357           0 :   MOZ_ASSERT(mState == State_Initial);
    1358             : 
    1359           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    1360           0 :   if (NS_WARN_IF(!quotaManager)) {
    1361           0 :     return NS_ERROR_FAILURE;
    1362             :   }
    1363             : 
    1364           0 :   mState = State_DirectoryOpenPending;
    1365             : 
    1366           0 :   quotaManager->OpenDirectory(mFileManager->Type(),
    1367             :                               mFileManager->Group(),
    1368             :                               mFileManager->Origin(),
    1369             :                               Client::IDB,
    1370             :                               /* aExclusive */ false,
    1371           0 :                               this);
    1372             : 
    1373           0 :   return NS_OK;
    1374             : }
    1375             : 
    1376             : nsresult
    1377           0 : DeleteFilesRunnable::DeleteFile(int64_t aFileId)
    1378             : {
    1379           0 :   MOZ_ASSERT(mDirectory);
    1380           0 :   MOZ_ASSERT(mJournalDirectory);
    1381             : 
    1382           0 :   nsCOMPtr<nsIFile> file = mFileManager->GetFileForId(mDirectory, aFileId);
    1383           0 :   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
    1384             : 
    1385             :   nsresult rv;
    1386             :   int64_t fileSize;
    1387             : 
    1388           0 :   if (mFileManager->EnforcingQuota()) {
    1389           0 :     rv = file->GetFileSize(&fileSize);
    1390           0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    1391             :   }
    1392             : 
    1393           0 :   rv = file->Remove(false);
    1394           0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    1395             : 
    1396           0 :   if (mFileManager->EnforcingQuota()) {
    1397           0 :     QuotaManager* quotaManager = QuotaManager::Get();
    1398           0 :     NS_ASSERTION(quotaManager, "Shouldn't be null!");
    1399             : 
    1400           0 :     quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
    1401             :                                          mFileManager->Group(),
    1402           0 :                                          mFileManager->Origin(), fileSize);
    1403             :   }
    1404             : 
    1405           0 :   file = mFileManager->GetFileForId(mJournalDirectory, aFileId);
    1406           0 :   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
    1407             : 
    1408           0 :   rv = file->Remove(false);
    1409           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1410             : 
    1411           0 :   return NS_OK;
    1412             : }
    1413             : 
    1414             : nsresult
    1415           0 : DeleteFilesRunnable::DoDatabaseWork()
    1416             : {
    1417           0 :   AssertIsOnIOThread();
    1418           0 :   MOZ_ASSERT(mState == State_DatabaseWorkOpen);
    1419             : 
    1420           0 :   if (!mFileManager->Invalidated()) {
    1421           0 :     mDirectory = mFileManager->GetDirectory();
    1422           0 :     if (NS_WARN_IF(!mDirectory)) {
    1423           0 :       return NS_ERROR_FAILURE;
    1424             :     }
    1425             : 
    1426           0 :     mJournalDirectory = mFileManager->GetJournalDirectory();
    1427           0 :     if (NS_WARN_IF(!mJournalDirectory)) {
    1428           0 :       return NS_ERROR_FAILURE;
    1429             :     }
    1430             : 
    1431           0 :     for (int64_t fileId : mFileIds) {
    1432           0 :       if (NS_FAILED(DeleteFile(fileId))) {
    1433           0 :         NS_WARNING("Failed to delete file!");
    1434             :       }
    1435             :     }
    1436             :   }
    1437             : 
    1438           0 :   Finish();
    1439             : 
    1440           0 :   return NS_OK;
    1441             : }
    1442             : 
    1443             : void
    1444           0 : DeleteFilesRunnable::Finish()
    1445             : {
    1446             :   // Must set mState before dispatching otherwise we will race with the main
    1447             :   // thread.
    1448           0 :   mState = State_UnblockingOpen;
    1449             : 
    1450           0 :   MOZ_ALWAYS_SUCCEEDS(mBackgroundThread->Dispatch(this, NS_DISPATCH_NORMAL));
    1451           0 : }
    1452             : 
    1453             : void
    1454           0 : DeleteFilesRunnable::UnblockOpen()
    1455             : {
    1456           0 :   AssertIsOnBackgroundThread();
    1457           0 :   MOZ_ASSERT(mState == State_UnblockingOpen);
    1458             : 
    1459           0 :   mDirectoryLock = nullptr;
    1460             : 
    1461           0 :   mState = State_Completed;
    1462           0 : }
    1463             : 
    1464             : } // namespace dom
    1465             : } // namespace mozilla

Generated by: LCOV version 1.13