dom/indexedDB/IndexedDatabaseManager.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=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/. */
     7 #include "IndexedDatabaseManager.h"
     9 #include "nsIConsoleService.h"
    10 #include "nsIDiskSpaceWatcher.h"
    11 #include "nsIFile.h"
    12 #include "nsIFileStorage.h"
    13 #include "nsIObserverService.h"
    14 #include "nsIScriptError.h"
    16 #include "jsapi.h"
    17 #include "mozilla/ClearOnShutdown.h"
    18 #include "mozilla/CondVar.h"
    19 #include "mozilla/ContentEvents.h"
    20 #include "mozilla/dom/ErrorEventBinding.h"
    21 #include "mozilla/dom/quota/OriginOrPatternString.h"
    22 #include "mozilla/dom/quota/QuotaManager.h"
    23 #include "mozilla/dom/quota/Utilities.h"
    24 #include "mozilla/dom/TabContext.h"
    25 #include "mozilla/EventDispatcher.h"
    26 #include "mozilla/Services.h"
    27 #include "mozilla/Preferences.h"
    28 #include "mozilla/storage.h"
    29 #include "nsContentUtils.h"
    30 #include "nsThreadUtils.h"
    32 #include "IDBEvents.h"
    33 #include "IDBFactory.h"
    34 #include "IDBKeyRange.h"
    35 #include "IDBRequest.h"
    37 // Bindings for ResolveConstructors
    38 #include "mozilla/dom/IDBCursorBinding.h"
    39 #include "mozilla/dom/IDBDatabaseBinding.h"
    40 #include "mozilla/dom/IDBFactoryBinding.h"
    41 #include "mozilla/dom/IDBFileHandleBinding.h"
    42 #include "mozilla/dom/IDBKeyRangeBinding.h"
    43 #include "mozilla/dom/IDBIndexBinding.h"
    44 #include "mozilla/dom/IDBObjectStoreBinding.h"
    45 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
    46 #include "mozilla/dom/IDBRequestBinding.h"
    47 #include "mozilla/dom/IDBTransactionBinding.h"
    48 #include "mozilla/dom/IDBVersionChangeEventBinding.h"
    50 #define IDB_STR "indexedDB"
    52 // The two possible values for the data argument when receiving the disk space
    53 // observer notification.
    54 #define LOW_DISK_SPACE_DATA_FULL "full"
    55 #define LOW_DISK_SPACE_DATA_FREE "free"
    57 USING_INDEXEDDB_NAMESPACE
    58 using namespace mozilla;
    59 using namespace mozilla::dom;
    60 USING_QUOTA_NAMESPACE
    62 BEGIN_INDEXEDDB_NAMESPACE
    64 class FileManagerInfo
    65 {
    66 public:
    67   already_AddRefed<FileManager>
    68   GetFileManager(PersistenceType aPersistenceType,
    69                  const nsAString& aName) const;
    71   void
    72   AddFileManager(FileManager* aFileManager);
    74   bool
    75   HasFileManagers() const
    76   {
    77     AssertIsOnIOThread();
    79     return !mPersistentStorageFileManagers.IsEmpty() ||
    80            !mTemporaryStorageFileManagers.IsEmpty();
    81   }
    83   void
    84   InvalidateAllFileManagers() const;
    86   void
    87   InvalidateAndRemoveFileManagers(PersistenceType aPersistenceType);
    89   void
    90   InvalidateAndRemoveFileManager(PersistenceType aPersistenceType,
    91                                  const nsAString& aName);
    93 private:
    94   nsTArray<nsRefPtr<FileManager> >&
    95   GetArray(PersistenceType aPersistenceType);
    97   const nsTArray<nsRefPtr<FileManager> >&
    98   GetImmutableArray(PersistenceType aPersistenceType) const
    99   {
   100     return const_cast<FileManagerInfo*>(this)->GetArray(aPersistenceType);
   101   }
   103   nsTArray<nsRefPtr<FileManager> > mPersistentStorageFileManagers;
   104   nsTArray<nsRefPtr<FileManager> > mTemporaryStorageFileManagers;
   105 };
   107 END_INDEXEDDB_NAMESPACE
   109 namespace {
   111 mozilla::StaticRefPtr<IndexedDatabaseManager> gDBManager;
   113 mozilla::Atomic<bool> gInitialized(false);
   114 mozilla::Atomic<bool> gClosed(false);
   116 class AsyncDeleteFileRunnable MOZ_FINAL : public nsIRunnable
   117 {
   118 public:
   119   NS_DECL_THREADSAFE_ISUPPORTS
   120   NS_DECL_NSIRUNNABLE
   122   AsyncDeleteFileRunnable(FileManager* aFileManager, int64_t aFileId);
   124 private:
   125   nsRefPtr<FileManager> mFileManager;
   126   int64_t mFileId;
   127 };
   129 class GetFileReferencesHelper MOZ_FINAL : public nsIRunnable
   130 {
   131 public:
   132   NS_DECL_THREADSAFE_ISUPPORTS
   133   NS_DECL_NSIRUNNABLE
   135   GetFileReferencesHelper(PersistenceType aPersistenceType,
   136                           const nsACString& aOrigin,
   137                           const nsAString& aDatabaseName,
   138                           int64_t aFileId)
   139   : mPersistenceType(aPersistenceType),
   140     mOrigin(aOrigin),
   141     mDatabaseName(aDatabaseName),
   142     mFileId(aFileId),
   143     mMutex(IndexedDatabaseManager::FileMutex()),
   144     mCondVar(mMutex, "GetFileReferencesHelper::mCondVar"),
   145     mMemRefCnt(-1),
   146     mDBRefCnt(-1),
   147     mSliceRefCnt(-1),
   148     mResult(false),
   149     mWaiting(true)
   150   { }
   152   nsresult
   153   DispatchAndReturnFileReferences(int32_t* aMemRefCnt,
   154                                   int32_t* aDBRefCnt,
   155                                   int32_t* aSliceRefCnt,
   156                                   bool* aResult);
   158 private:
   159   PersistenceType mPersistenceType;
   160   nsCString mOrigin;
   161   nsString mDatabaseName;
   162   int64_t mFileId;
   164   mozilla::Mutex& mMutex;
   165   mozilla::CondVar mCondVar;
   166   int32_t mMemRefCnt;
   167   int32_t mDBRefCnt;
   168   int32_t mSliceRefCnt;
   169   bool mResult;
   170   bool mWaiting;
   171 };
   173 struct MOZ_STACK_CLASS InvalidateInfo
   174 {
   175   InvalidateInfo(PersistenceType aPersistenceType, const nsACString& aPattern)
   176   : persistenceType(aPersistenceType), pattern(aPattern)
   177   { }
   179   PersistenceType persistenceType;
   180   const nsACString& pattern;
   181 };
   183 } // anonymous namespace
   185 IndexedDatabaseManager::IndexedDatabaseManager()
   186 : mFileMutex("IndexedDatabaseManager.mFileMutex")
   187 {
   188   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   189 }
   191 IndexedDatabaseManager::~IndexedDatabaseManager()
   192 {
   193   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   194 }
   196 bool IndexedDatabaseManager::sIsMainProcess = false;
   197 mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false);
   199 // static
   200 IndexedDatabaseManager*
   201 IndexedDatabaseManager::GetOrCreate()
   202 {
   203   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   205   if (IsClosed()) {
   206     NS_ERROR("Calling GetOrCreate() after shutdown!");
   207     return nullptr;
   208   }
   210   if (!gDBManager) {
   211     sIsMainProcess = XRE_GetProcessType() == GeckoProcessType_Default;
   213     if (sIsMainProcess && Preferences::GetBool("disk_space_watcher.enabled", false)) {
   214       // See if we're starting up in low disk space conditions.
   215       nsCOMPtr<nsIDiskSpaceWatcher> watcher =
   216         do_GetService(DISKSPACEWATCHER_CONTRACTID);
   217       if (watcher) {
   218         bool isDiskFull;
   219         if (NS_SUCCEEDED(watcher->GetIsDiskFull(&isDiskFull))) {
   220           sLowDiskSpaceMode = isDiskFull;
   221         }
   222         else {
   223           NS_WARNING("GetIsDiskFull failed!");
   224         }
   225       }
   226       else {
   227         NS_WARNING("No disk space watcher component available!");
   228       }
   229     }
   231     nsRefPtr<IndexedDatabaseManager> instance(new IndexedDatabaseManager());
   233     nsresult rv = instance->Init();
   234     NS_ENSURE_SUCCESS(rv, nullptr);
   236     if (gInitialized.exchange(true)) {
   237       NS_ERROR("Initialized more than once?!");
   238     }
   240     gDBManager = instance;
   242     ClearOnShutdown(&gDBManager);
   243   }
   245   return gDBManager;
   246 }
   248 // static
   249 IndexedDatabaseManager*
   250 IndexedDatabaseManager::Get()
   251 {
   252   // Does not return an owning reference.
   253   return gDBManager;
   254 }
   256 // static
   257 IndexedDatabaseManager*
   258 IndexedDatabaseManager::FactoryCreate()
   259 {
   260   // Returns a raw pointer that carries an owning reference! Lame, but the
   261   // singleton factory macros force this.
   262   IndexedDatabaseManager* mgr = GetOrCreate();
   263   NS_IF_ADDREF(mgr);
   264   return mgr;
   265 }
   267 nsresult
   268 IndexedDatabaseManager::Init()
   269 {
   270   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   272   // Make sure that the quota manager is up.
   273   QuotaManager* qm = QuotaManager::GetOrCreate();
   274   NS_ENSURE_STATE(qm);
   276   // During Init() we can't yet call IsMainProcess(), just check sIsMainProcess
   277   // directly.
   278   if (sIsMainProcess) {
   279     // Must initialize the storage service on the main thread.
   280     nsCOMPtr<mozIStorageService> ss =
   281       do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
   282     NS_ENSURE_STATE(ss);
   284     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   285     NS_ENSURE_STATE(obs);
   287     nsresult rv =
   288       obs->AddObserver(this, DISKSPACEWATCHER_OBSERVER_TOPIC, false);
   289     NS_ENSURE_SUCCESS(rv, rv);
   290   }
   292   return NS_OK;
   293 }
   295 void
   296 IndexedDatabaseManager::Destroy()
   297 {
   298   // Setting the closed flag prevents the service from being recreated.
   299   // Don't set it though if there's no real instance created.
   300   if (gInitialized && gClosed.exchange(true)) {
   301     NS_ERROR("Shutdown more than once?!");
   302   }
   304   delete this;
   305 }
   307 // static
   308 nsresult
   309 IndexedDatabaseManager::FireWindowOnError(nsPIDOMWindow* aOwner,
   310                                           EventChainPostVisitor& aVisitor)
   311 {
   312   NS_ENSURE_TRUE(aVisitor.mDOMEvent, NS_ERROR_UNEXPECTED);
   313   if (!aOwner) {
   314     return NS_OK;
   315   }
   317   if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
   318     return NS_OK;
   319   }
   321   nsString type;
   322   nsresult rv = aVisitor.mDOMEvent->GetType(type);
   323   NS_ENSURE_SUCCESS(rv, rv);
   325   if (!type.EqualsLiteral(ERROR_EVT_STR)) {
   326     return NS_OK;
   327   }
   329   nsCOMPtr<EventTarget> eventTarget =
   330     aVisitor.mDOMEvent->InternalDOMEvent()->GetTarget();
   332   IDBRequest* request = static_cast<IDBRequest*>(eventTarget.get());
   333   NS_ENSURE_TRUE(request, NS_ERROR_UNEXPECTED);
   335   ErrorResult ret;
   336   nsRefPtr<DOMError> error = request->GetError(ret);
   337   if (ret.Failed()) {
   338     return ret.ErrorCode();
   339   }
   341   nsString errorName;
   342   if (error) {
   343     error->GetName(errorName);
   344   }
   346   ThreadsafeAutoJSContext cx;
   347   RootedDictionary<ErrorEventInit> init(cx);
   348   request->FillScriptErrorEvent(init);
   350   init.mMessage = errorName;
   351   init.mCancelable = true;
   352   init.mBubbles = true;
   354   nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aOwner));
   355   NS_ASSERTION(sgo, "How can this happen?!");
   357   nsEventStatus status = nsEventStatus_eIgnore;
   358   if (NS_FAILED(sgo->HandleScriptError(init, &status))) {
   359     NS_WARNING("Failed to dispatch script error event");
   360     status = nsEventStatus_eIgnore;
   361   }
   363   bool preventDefaultCalled = status == nsEventStatus_eConsumeNoDefault;
   364   if (preventDefaultCalled) {
   365     return NS_OK;
   366   }
   368   // Log an error to the error console.
   369   nsCOMPtr<nsIScriptError> scriptError =
   370     do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
   371   NS_ENSURE_SUCCESS(rv, rv);
   373   if (NS_FAILED(scriptError->InitWithWindowID(errorName,
   374                                               init.mFilename,
   375                                               EmptyString(), init.mLineno,
   376                                               0, 0,
   377                                               "IndexedDB",
   378                                               aOwner->WindowID()))) {
   379     NS_WARNING("Failed to init script error!");
   380     return NS_ERROR_FAILURE;
   381   }
   383   nsCOMPtr<nsIConsoleService> consoleService =
   384     do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
   385   NS_ENSURE_SUCCESS(rv, rv);
   387   return consoleService->LogMessage(scriptError);
   388 }
   390 // static
   391 bool
   392 IndexedDatabaseManager::TabContextMayAccessOrigin(const TabContext& aContext,
   393                                                   const nsACString& aOrigin)
   394 {
   395   NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
   397   // If aContext is for a browser element, it's allowed only to access other
   398   // browser elements.  But if aContext is not for a browser element, it may
   399   // access both browser and non-browser elements.
   400   nsAutoCString pattern;
   401   QuotaManager::GetOriginPatternStringMaybeIgnoreBrowser(
   402                                                 aContext.OwnOrContainingAppId(),
   403                                                 aContext.IsBrowserElement(),
   404                                                 pattern);
   406   return PatternMatchesOrigin(pattern, aOrigin);
   407 }
   409 // static
   410 bool
   411 IndexedDatabaseManager::DefineIndexedDB(JSContext* aCx,
   412                                         JS::Handle<JSObject*> aGlobal)
   413 {
   414   MOZ_ASSERT(NS_IsMainThread());
   415   MOZ_ASSERT(nsContentUtils::IsCallerChrome(), "Only for chrome!");
   416   MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
   417              "Passed object is not a global object!");
   419   if (!IDBCursorBinding::GetConstructorObject(aCx, aGlobal) ||
   420       !IDBCursorWithValueBinding::GetConstructorObject(aCx, aGlobal) ||
   421       !IDBDatabaseBinding::GetConstructorObject(aCx, aGlobal) ||
   422       !IDBFactoryBinding::GetConstructorObject(aCx, aGlobal) ||
   423       !IDBFileHandleBinding::GetConstructorObject(aCx, aGlobal) ||
   424       !IDBIndexBinding::GetConstructorObject(aCx, aGlobal) ||
   425       !IDBKeyRangeBinding::GetConstructorObject(aCx, aGlobal) ||
   426       !IDBObjectStoreBinding::GetConstructorObject(aCx, aGlobal) ||
   427       !IDBOpenDBRequestBinding::GetConstructorObject(aCx, aGlobal) ||
   428       !IDBRequestBinding::GetConstructorObject(aCx, aGlobal) ||
   429       !IDBTransactionBinding::GetConstructorObject(aCx, aGlobal) ||
   430       !IDBVersionChangeEventBinding::GetConstructorObject(aCx, aGlobal))
   431   {
   432     return false;
   433   }
   435   nsRefPtr<IDBFactory> factory;
   436   if (NS_FAILED(IDBFactory::Create(aCx, aGlobal, nullptr,
   437                                    getter_AddRefs(factory)))) {
   438     return false;
   439   }
   441   MOZ_ASSERT(factory, "This should never fail for chrome!");
   443   JS::Rooted<JS::Value> indexedDB(aCx);
   444   js::AssertSameCompartment(aCx, aGlobal);
   445   if (!WrapNewBindingObject(aCx, factory, &indexedDB)) {
   446     return false;
   447   }
   449   return JS_DefineProperty(aCx, aGlobal, IDB_STR, indexedDB, JSPROP_ENUMERATE);
   450 }
   452 // static
   453 bool
   454 IndexedDatabaseManager::IsClosed()
   455 {
   456   return gClosed;
   457 }
   459 #ifdef DEBUG
   460 // static
   461 bool
   462 IndexedDatabaseManager::IsMainProcess()
   463 {
   464   NS_ASSERTION(gDBManager,
   465                "IsMainProcess() called before indexedDB has been initialized!");
   466   NS_ASSERTION((XRE_GetProcessType() == GeckoProcessType_Default) ==
   467                sIsMainProcess, "XRE_GetProcessType changed its tune!");
   468   return sIsMainProcess;
   469 }
   471 //static
   472 bool
   473 IndexedDatabaseManager::InLowDiskSpaceMode()
   474 {
   475   NS_ASSERTION(gDBManager,
   476                "InLowDiskSpaceMode() called before indexedDB has been "
   477                "initialized!");
   478   return sLowDiskSpaceMode;
   479 }
   480 #endif
   482 already_AddRefed<FileManager>
   483 IndexedDatabaseManager::GetFileManager(PersistenceType aPersistenceType,
   484                                        const nsACString& aOrigin,
   485                                        const nsAString& aDatabaseName)
   486 {
   487   AssertIsOnIOThread();
   489   FileManagerInfo* info;
   490   if (!mFileManagerInfos.Get(aOrigin, &info)) {
   491     return nullptr;
   492   }
   494   nsRefPtr<FileManager> fileManager =
   495     info->GetFileManager(aPersistenceType, aDatabaseName);
   497   return fileManager.forget();
   498 }
   500 void
   501 IndexedDatabaseManager::AddFileManager(FileManager* aFileManager)
   502 {
   503   AssertIsOnIOThread();
   504   NS_ASSERTION(aFileManager, "Null file manager!");
   506   FileManagerInfo* info;
   507   if (!mFileManagerInfos.Get(aFileManager->Origin(), &info)) {
   508     info = new FileManagerInfo();
   509     mFileManagerInfos.Put(aFileManager->Origin(), info);
   510   }
   512   info->AddFileManager(aFileManager);
   513 }
   515 // static
   516 PLDHashOperator
   517 IndexedDatabaseManager::InvalidateAndRemoveFileManagers(
   518                                              const nsACString& aKey,
   519                                              nsAutoPtr<FileManagerInfo>& aValue,
   520                                              void* aUserArg)
   521 {
   522   AssertIsOnIOThread();
   523   NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
   524   NS_ASSERTION(aValue, "Null pointer!");
   526   if (!aUserArg) {
   527     aValue->InvalidateAllFileManagers();
   528     return PL_DHASH_REMOVE;
   529   }
   531   InvalidateInfo* info = static_cast<InvalidateInfo*>(aUserArg);
   533   if (PatternMatchesOrigin(info->pattern, aKey)) {
   534     aValue->InvalidateAndRemoveFileManagers(info->persistenceType);
   536     if (!aValue->HasFileManagers()) {
   537       return PL_DHASH_REMOVE;
   538     }
   539   }
   541   return PL_DHASH_NEXT;
   542 }
   544 void
   545 IndexedDatabaseManager::InvalidateAllFileManagers()
   546 {
   547   AssertIsOnIOThread();
   549   mFileManagerInfos.Enumerate(InvalidateAndRemoveFileManagers, nullptr);
   550 }
   552 void
   553 IndexedDatabaseManager::InvalidateFileManagers(
   554                                   PersistenceType aPersistenceType,
   555                                   const OriginOrPatternString& aOriginOrPattern)
   556 {
   557   AssertIsOnIOThread();
   558   NS_ASSERTION(!aOriginOrPattern.IsEmpty(), "Empty pattern!");
   560   if (aOriginOrPattern.IsOrigin()) {
   561     FileManagerInfo* info;
   562     if (!mFileManagerInfos.Get(aOriginOrPattern, &info)) {
   563       return;
   564     }
   566     info->InvalidateAndRemoveFileManagers(aPersistenceType);
   568     if (!info->HasFileManagers()) {
   569       mFileManagerInfos.Remove(aOriginOrPattern);
   570     }
   571   }
   572   else {
   573     InvalidateInfo info(aPersistenceType, aOriginOrPattern);
   574     mFileManagerInfos.Enumerate(InvalidateAndRemoveFileManagers, &info);
   575   }
   576 }
   578 void
   579 IndexedDatabaseManager::InvalidateFileManager(PersistenceType aPersistenceType,
   580                                               const nsACString& aOrigin,
   581                                               const nsAString& aDatabaseName)
   582 {
   583   AssertIsOnIOThread();
   585   FileManagerInfo* info;
   586   if (!mFileManagerInfos.Get(aOrigin, &info)) {
   587     return;
   588   }
   590   info->InvalidateAndRemoveFileManager(aPersistenceType, aDatabaseName);
   592   if (!info->HasFileManagers()) {
   593     mFileManagerInfos.Remove(aOrigin);
   594   }
   595 }
   597 nsresult
   598 IndexedDatabaseManager::AsyncDeleteFile(FileManager* aFileManager,
   599                                         int64_t aFileId)
   600 {
   601   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   603   NS_ENSURE_ARG_POINTER(aFileManager);
   605   QuotaManager* quotaManager = QuotaManager::Get();
   606   NS_ASSERTION(quotaManager, "Shouldn't be null!");
   608   // See if we're currently clearing the storages for this origin. If so then
   609   // we pretend that we've already deleted everything.
   610   if (quotaManager->IsClearOriginPending(
   611                              aFileManager->Origin(),
   612                              Nullable<PersistenceType>(aFileManager->Type()))) {
   613     return NS_OK;
   614   }
   616   nsRefPtr<AsyncDeleteFileRunnable> runnable =
   617     new AsyncDeleteFileRunnable(aFileManager, aFileId);
   619   nsresult rv =
   620     quotaManager->IOThread()->Dispatch(runnable, NS_DISPATCH_NORMAL);
   621   NS_ENSURE_SUCCESS(rv, rv);
   623   return NS_OK;
   624 }
   626 nsresult
   627 IndexedDatabaseManager::BlockAndGetFileReferences(
   628                                                PersistenceType aPersistenceType,
   629                                                const nsACString& aOrigin,
   630                                                const nsAString& aDatabaseName,
   631                                                int64_t aFileId,
   632                                                int32_t* aRefCnt,
   633                                                int32_t* aDBRefCnt,
   634                                                int32_t* aSliceRefCnt,
   635                                                bool* aResult)
   636 {
   637   nsRefPtr<GetFileReferencesHelper> helper =
   638     new GetFileReferencesHelper(aPersistenceType, aOrigin, aDatabaseName,
   639                                 aFileId);
   641   nsresult rv = helper->DispatchAndReturnFileReferences(aRefCnt, aDBRefCnt,
   642                                                         aSliceRefCnt, aResult);
   643   NS_ENSURE_SUCCESS(rv, rv);
   645   return NS_OK;
   646 }
   648 NS_IMPL_ADDREF(IndexedDatabaseManager)
   649 NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())
   650 NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIIndexedDatabaseManager,
   651                         nsIObserver)
   653 NS_IMETHODIMP
   654 IndexedDatabaseManager::InitWindowless(JS::Handle<JS::Value> aGlobal, JSContext* aCx)
   655 {
   656   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
   658   JS::Rooted<JSObject*> global(aCx, JSVAL_TO_OBJECT(aGlobal));
   659   if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
   660     NS_WARNING("Passed object is not a global object!");
   661     return NS_ERROR_FAILURE;
   662   }
   664   bool hasIndexedDB;
   665   if (!JS_HasProperty(aCx, global, IDB_STR, &hasIndexedDB)) {
   666     return NS_ERROR_FAILURE;
   667   }
   669   if (hasIndexedDB) {
   670     NS_WARNING("Passed object already has an 'indexedDB' property!");
   671     return NS_ERROR_FAILURE;
   672   }
   674   if (!DefineIndexedDB(aCx, global)) {
   675     return NS_ERROR_FAILURE;
   676   }
   678   return NS_OK;
   679 }
   681 NS_IMETHODIMP
   682 IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic,
   683                                 const char16_t* aData)
   684 {
   685   NS_ASSERTION(IsMainProcess(), "Wrong process!");
   686   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   688   if (!strcmp(aTopic, DISKSPACEWATCHER_OBSERVER_TOPIC)) {
   689     NS_ASSERTION(aData, "No data?!");
   691     const nsDependentString data(aData);
   693     if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FULL)) {
   694       sLowDiskSpaceMode = true;
   695     }
   696     else if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FREE)) {
   697       sLowDiskSpaceMode = false;
   698     }
   699     else {
   700       NS_NOTREACHED("Unknown data value!");
   701     }
   703     return NS_OK;
   704   }
   706    NS_NOTREACHED("Unknown topic!");
   707    return NS_ERROR_UNEXPECTED;
   708  }
   710 already_AddRefed<FileManager>
   711 FileManagerInfo::GetFileManager(PersistenceType aPersistenceType,
   712                                 const nsAString& aName) const
   713 {
   714   AssertIsOnIOThread();
   716   const nsTArray<nsRefPtr<FileManager> >& managers =
   717     GetImmutableArray(aPersistenceType);
   719   for (uint32_t i = 0; i < managers.Length(); i++) {
   720     const nsRefPtr<FileManager>& fileManager = managers[i];
   722     if (fileManager->DatabaseName() == aName) {
   723       nsRefPtr<FileManager> result = fileManager;
   724       return result.forget();
   725     }
   726   }
   728   return nullptr;
   729 }
   731 void
   732 FileManagerInfo::AddFileManager(FileManager* aFileManager)
   733 {
   734   AssertIsOnIOThread();
   736   nsTArray<nsRefPtr<FileManager> >& managers = GetArray(aFileManager->Type());
   738   NS_ASSERTION(!managers.Contains(aFileManager), "Adding more than once?!");
   740   managers.AppendElement(aFileManager);
   741 }
   743 void
   744 FileManagerInfo::InvalidateAllFileManagers() const
   745 {
   746   AssertIsOnIOThread();
   748   uint32_t i;
   750   for (i = 0; i < mPersistentStorageFileManagers.Length(); i++) {
   751     mPersistentStorageFileManagers[i]->Invalidate();
   752   }
   754   for (i = 0; i < mTemporaryStorageFileManagers.Length(); i++) {
   755     mTemporaryStorageFileManagers[i]->Invalidate();
   756   }
   757 }
   759 void
   760 FileManagerInfo::InvalidateAndRemoveFileManagers(
   761                                                PersistenceType aPersistenceType)
   762 {
   763   AssertIsOnIOThread();
   765   nsTArray<nsRefPtr<FileManager > >& managers = GetArray(aPersistenceType);
   767   for (uint32_t i = 0; i < managers.Length(); i++) {
   768     managers[i]->Invalidate();
   769   }
   771   managers.Clear();
   772 }
   774 void
   775 FileManagerInfo::InvalidateAndRemoveFileManager(
   776                                                PersistenceType aPersistenceType,
   777                                                const nsAString& aName)
   778 {
   779   AssertIsOnIOThread();
   781   nsTArray<nsRefPtr<FileManager > >& managers = GetArray(aPersistenceType);
   783   for (uint32_t i = 0; i < managers.Length(); i++) {
   784     nsRefPtr<FileManager>& fileManager = managers[i];
   785     if (fileManager->DatabaseName() == aName) {
   786       fileManager->Invalidate();
   787       managers.RemoveElementAt(i);
   788       return;
   789     }
   790   }
   791 }
   793 nsTArray<nsRefPtr<FileManager> >&
   794 FileManagerInfo::GetArray(PersistenceType aPersistenceType)
   795 {
   796   switch (aPersistenceType) {
   797     case PERSISTENCE_TYPE_PERSISTENT:
   798       return mPersistentStorageFileManagers;
   799     case PERSISTENCE_TYPE_TEMPORARY:
   800       return mTemporaryStorageFileManagers;
   802     case PERSISTENCE_TYPE_INVALID:
   803     default:
   804       MOZ_CRASH("Bad storage type value!");
   805       return mPersistentStorageFileManagers;
   806   }
   807 }
   809 AsyncDeleteFileRunnable::AsyncDeleteFileRunnable(FileManager* aFileManager,
   810                                                  int64_t aFileId)
   811 : mFileManager(aFileManager), mFileId(aFileId)
   812 {
   813 }
   815 NS_IMPL_ISUPPORTS(AsyncDeleteFileRunnable,
   816                   nsIRunnable)
   818 NS_IMETHODIMP
   819 AsyncDeleteFileRunnable::Run()
   820 {
   821   AssertIsOnIOThread();
   823   nsCOMPtr<nsIFile> directory = mFileManager->GetDirectory();
   824   NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
   826   nsCOMPtr<nsIFile> file = mFileManager->GetFileForId(directory, mFileId);
   827   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
   829   nsresult rv;
   830   int64_t fileSize;
   832   if (mFileManager->Privilege() != Chrome) {
   833     rv = file->GetFileSize(&fileSize);
   834     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
   835   }
   837   rv = file->Remove(false);
   838   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
   840   if (mFileManager->Privilege() != Chrome) {
   841     QuotaManager* quotaManager = QuotaManager::Get();
   842     NS_ASSERTION(quotaManager, "Shouldn't be null!");
   844     quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
   845                                          mFileManager->Group(),
   846                                          mFileManager->Origin(), fileSize);
   847   }
   849   directory = mFileManager->GetJournalDirectory();
   850   NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
   852   file = mFileManager->GetFileForId(directory, mFileId);
   853   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
   855   rv = file->Remove(false);
   856   NS_ENSURE_SUCCESS(rv, rv);
   858   return NS_OK;
   859 }
   861 nsresult
   862 GetFileReferencesHelper::DispatchAndReturnFileReferences(int32_t* aMemRefCnt,
   863                                                          int32_t* aDBRefCnt,
   864                                                          int32_t* aSliceRefCnt,
   865                                                          bool* aResult)
   866 {
   867   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   869   QuotaManager* quotaManager = QuotaManager::Get();
   870   NS_ASSERTION(quotaManager, "Shouldn't be null!");
   872   nsresult rv =
   873     quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
   874   NS_ENSURE_SUCCESS(rv, rv);
   876   mozilla::MutexAutoLock autolock(mMutex);
   877   while (mWaiting) {
   878     mCondVar.Wait();
   879   }
   881   *aMemRefCnt = mMemRefCnt;
   882   *aDBRefCnt = mDBRefCnt;
   883   *aSliceRefCnt = mSliceRefCnt;
   884   *aResult = mResult;
   886   return NS_OK;
   887 }
   889 NS_IMPL_ISUPPORTS(GetFileReferencesHelper,
   890                   nsIRunnable)
   892 NS_IMETHODIMP
   893 GetFileReferencesHelper::Run()
   894 {
   895   AssertIsOnIOThread();
   897   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   898   NS_ASSERTION(mgr, "This should never fail!");
   900   nsRefPtr<FileManager> fileManager =
   901     mgr->GetFileManager(mPersistenceType, mOrigin, mDatabaseName);
   903   if (fileManager) {
   904     nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(mFileId);
   906     if (fileInfo) {
   907       fileInfo->GetReferences(&mMemRefCnt, &mDBRefCnt, &mSliceRefCnt);
   909       if (mMemRefCnt != -1) {
   910         // We added an extra temp ref, so account for that accordingly.
   911         mMemRefCnt--;
   912       }
   914       mResult = true;
   915     }
   916   }
   918   mozilla::MutexAutoLock lock(mMutex);
   919   NS_ASSERTION(mWaiting, "Huh?!");
   921   mWaiting = false;
   922   mCondVar.Notify();
   924   return NS_OK;
   925 }

mercurial