Bug 984789 - FileHandle: Eliminate nsIFileStorage; r=bent
authorJan Varga <jan.varga@gmail.com>
Wed, 07 May 2014 16:33:02 +0200
changeset 181992 ef60f8aa9a017213edff0e6413b43c4eed15e66b
parent 181991 03fdda1af1f4fc0bdf7bd71c765b89216a5a2737
child 181993 7fffbe8dc9ec9f0dc124485c112419b5a2882674
push id43181
push userJan.Varga@gmail.com
push dateWed, 07 May 2014 14:33:58 +0000
treeherdermozilla-inbound@ef60f8aa9a01 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs984789
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 984789 - FileHandle: Eliminate nsIFileStorage; r=bent
dom/filehandle/FileHandle.cpp
dom/filehandle/FileHandle.h
dom/filehandle/FileHelper.cpp
dom/filehandle/FileHelper.h
dom/filehandle/FileService.cpp
dom/filehandle/FileService.h
dom/filehandle/FileStreamWrappers.cpp
dom/filehandle/LockedFile.cpp
dom/filehandle/moz.build
dom/filehandle/nsIFileStorage.h
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBDatabase.h
dom/indexedDB/IDBFileHandle.cpp
dom/indexedDB/IDBFileHandle.h
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IndexedDatabaseManager.cpp
dom/quota/QuotaManager.cpp
dom/quota/nsIOfflineStorage.h
--- a/dom/filehandle/FileHandle.cpp
+++ b/dom/filehandle/FileHandle.cpp
@@ -15,17 +15,16 @@
 #include "mozilla/dom/FileHandleBinding.h"
 #include "mozilla/ErrorResult.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsIDOMFile.h"
 #include "nsIFile.h"
-#include "nsIFileStorage.h"
 #include "nsNetUtil.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 class GetFileHelper : public MetadataHelper
@@ -66,45 +65,20 @@ FileHandle::FileHandle(DOMEventTargetHel
   : DOMEventTargetHelper(aOwner)
 {
 }
 
 FileHandle::~FileHandle()
 {
 }
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(FileHandle, DOMEventTargetHelper,
-                                   mFileStorage)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileHandle)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-NS_IMPL_ADDREF_INHERITED(FileHandle, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(FileHandle, DOMEventTargetHelper)
-
-// static
-already_AddRefed<FileHandle>
-FileHandle::Create(nsPIDOMWindow* aWindow,
-                   nsIFileStorage* aFileStorage,
-                   nsIFile* aFile)
+bool
+FileHandle::IsShuttingDown()
 {
-  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-
-  nsRefPtr<FileHandle> newFileHandle = new FileHandle(aWindow);
-
-  newFileHandle->mFileStorage = aFileStorage;
-  nsresult rv = aFile->GetLeafName(newFileHandle->mName);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return nullptr;
-  }
-
-  newFileHandle->mFile = aFile;
-  newFileHandle->mFileName = newFileHandle->mName;
-
-  return newFileHandle.forget();
+  return FileService::IsShuttingDown();
 }
 
 // virtual
 already_AddRefed<nsISupports>
 FileHandle::CreateStream(nsIFile* aFile, bool aReadOnly)
 {
   nsresult rv;
 
@@ -144,17 +118,17 @@ FileHandle::WrapObject(JSContext* aCx)
   return FileHandleBinding::Wrap(aCx, this);
 }
 
 already_AddRefed<LockedFile>
 FileHandle::Open(FileMode aMode, ErrorResult& aError)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (FileService::IsShuttingDown() || mFileStorage->IsShuttingDown()) {
+  if (IsShuttingDown()) {
     aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<LockedFile> lockedFile = LockedFile::Create(this, aMode);
   if (!lockedFile) {
     aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
--- a/dom/filehandle/FileHandle.h
+++ b/dom/filehandle/FileHandle.h
@@ -7,22 +7,21 @@
 #ifndef mozilla_dom_FileHandle_h
 #define mozilla_dom_FileHandle_h
 
 #include "js/TypeDecls.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/FileModeBinding.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsCOMPtr.h"
-#include "nsCycleCollectionParticipant.h"
 #include "nsString.h"
 
 class nsIDOMFile;
 class nsIFile;
-class nsIFileStorage;
+class nsIOfflineStorage;
 class nsPIDOMWindow;
 
 namespace mozilla {
 
 class ErrorResult;
 
 namespace dom {
 
@@ -34,36 +33,28 @@ class FileHelper;
 
 namespace indexedDB {
 class FileInfo;
 } // namespace indexedDB
 
 /**
  * This class provides a default FileHandle implementation, but it can be also
  * subclassed. The subclass can override implementation of GetFileId,
- * GetFileInfo, CreateStream and CreateFileObject.
+ * GetFileInfo, IsShuttingDown, IsInvalid, CreateStream, SetThreadLocals,
+ * UnsetThreadLocals and CreateFileObject.
  * (for example IDBFileHandle provides IndexedDB specific implementation).
  */
 class FileHandle : public DOMEventTargetHelper
 {
   friend class FileService;
   friend class LockedFile;
   friend class FinishHelper;
   friend class FileHelper;
 
 public:
-  NS_DECL_ISUPPORTS_INHERITED
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileHandle, DOMEventTargetHelper)
-
-  static already_AddRefed<FileHandle>
-  Create(nsPIDOMWindow* aWindow,
-         nsIFileStorage* aFileStorage,
-         nsIFile* aFile);
-
   const nsAString&
   Name() const
   {
     return mName;
   }
 
   const nsAString&
   Type() const
@@ -78,19 +69,43 @@ public:
   }
 
   virtual mozilla::dom::indexedDB::FileInfo*
   GetFileInfo()
   {
     return nullptr;
   }
 
+  virtual bool
+  IsShuttingDown();
+
+  virtual bool
+  IsInvalid()
+  {
+    return false;
+  }
+
+  // A temporary method that will be removed along with nsIOfflineStorage
+  // interface.
+  virtual nsIOfflineStorage*
+  Storage() = 0;
+
   virtual already_AddRefed<nsISupports>
   CreateStream(nsIFile* aFile, bool aReadOnly);
 
+  virtual void
+  SetThreadLocals()
+  {
+  }
+
+  virtual void
+  UnsetThreadLocals()
+  {
+  }
+
   virtual already_AddRefed<nsIDOMFile>
   CreateFileObject(LockedFile* aLockedFile, uint32_t aFileSize);
 
   // nsWrapperCache
   virtual JSObject*
   WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   // WebIDL
@@ -123,21 +138,21 @@ public:
 
 protected:
   FileHandle(nsPIDOMWindow* aWindow);
 
   FileHandle(DOMEventTargetHelper* aOwner);
 
   virtual ~FileHandle();
 
-  nsCOMPtr<nsIFileStorage> mFileStorage;
-
   nsString mName;
   nsString mType;
 
   nsCOMPtr<nsIFile> mFile;
+
+  nsCString mStorageId;
   nsString mFileName;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_FileHandle_h
--- a/dom/filehandle/FileHelper.cpp
+++ b/dom/filehandle/FileHelper.cpp
@@ -7,45 +7,45 @@
 #include "FileHelper.h"
 
 #include "FileHandle.h"
 #include "FileRequest.h"
 #include "FileService.h"
 #include "js/Value.h"
 #include "LockedFile.h"
 #include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
 #include "nsDebug.h"
 #include "nsError.h"
-#include "nsIFileStorage.h"
 #include "nsIRequest.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 LockedFile* gCurrentLockedFile = nullptr;
 
 } // anonymous namespace
 
 FileHelper::FileHelper(LockedFile* aLockedFile,
                        FileRequest* aFileRequest)
-: mFileStorage(aLockedFile->mFileHandle->mFileStorage),
+: mFileHandle(aLockedFile->mFileHandle),
   mLockedFile(aLockedFile),
   mFileRequest(aFileRequest),
   mResultCode(NS_OK),
   mFinished(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 FileHelper::~FileHelper()
 {
-  NS_ASSERTION(!mFileStorage && !mLockedFile && !mFileRequest && !mListener &&
-               !mRequest, "Should have cleared this!");
+  MOZ_ASSERT(!mFileHandle && !mLockedFile && !mFileRequest && !mListener &&
+             !mRequest, "Should have cleared this!");
 }
 
 NS_IMPL_ISUPPORTS(FileHelper, nsIRequestObserver)
 
 nsresult
 FileHelper::Enqueue()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -164,17 +164,17 @@ FileHelper::GetSuccessResult(JSContext* 
   return NS_OK;
 }
 
 void
 FileHelper::ReleaseObjects()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  mFileStorage = nullptr;
+  mFileHandle = nullptr;
   mLockedFile = nullptr;
   mFileRequest = nullptr;
   mListener = nullptr;
   mRequest = nullptr;
 }
 
 void
 FileHelper::Finish()
@@ -207,18 +207,18 @@ FileHelper::Finish()
   gCurrentLockedFile = oldLockedFile;
 
   mLockedFile->OnRequestFinished();
 
   mListener->OnFileHelperComplete(this);
 
   ReleaseObjects();
 
-  NS_ASSERTION(!(mFileStorage || mLockedFile || mFileRequest || mListener ||
-                 mRequest), "Subclass didn't call FileHelper::ReleaseObjects!");
+  MOZ_ASSERT(!(mFileHandle || mLockedFile || mFileRequest || mListener ||
+               mRequest), "Subclass didn't call FileHelper::ReleaseObjects!");
 
 }
 
 void
 FileHelper::OnStreamClose()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   Finish();
--- a/dom/filehandle/FileHelper.h
+++ b/dom/filehandle/FileHelper.h
@@ -7,22 +7,21 @@
 #ifndef mozilla_dom_FileHelper_h
 #define mozilla_dom_FileHelper_h
 
 #include "js/TypeDecls.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIRequestObserver.h"
 
-class nsIFileStorage;
-
 namespace mozilla {
 namespace dom {
 
 class FileHelper;
+class FileHandle;
 class FileRequest;
 class FileOutputStreamWrapper;
 class LockedFile;
 
 class FileHelperListener
 {
 public:
   NS_IMETHOD_(MozExternalRefCountType)
@@ -79,17 +78,17 @@ protected:
   GetSuccessResult(JSContext* aCx, JS::MutableHandle<JS::Value> aVal);
 
   virtual void
   ReleaseObjects();
 
   void
   Finish();
 
-  nsCOMPtr<nsIFileStorage> mFileStorage;
+  nsRefPtr<FileHandle> mFileHandle;
   nsRefPtr<LockedFile> mLockedFile;
   nsRefPtr<FileRequest> mFileRequest;
 
   nsRefPtr<FileHelperListener> mListener;
   nsCOMPtr<nsIRequest> mRequest;
 
 private:
   nsresult mResultCode;
--- a/dom/filehandle/FileService.cpp
+++ b/dom/filehandle/FileService.cpp
@@ -4,20 +4,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FileService.h"
 
 #include "FileHandle.h"
 #include "LockedFile.h"
 #include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
 #include "nsError.h"
 #include "nsIEventTarget.h"
-#include "nsIFileStorage.h"
 #include "nsIObserverService.h"
+#include "nsIOfflineStorage.h"
 #include "nsNetCID.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace {
@@ -50,17 +51,17 @@ FileService::Init()
 }
 
 nsresult
 FileService::Cleanup()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsIThread* thread = NS_GetCurrentThread();
-  while (mFileStorageInfos.Count()) {
+  while (mStorageInfos.Count()) {
     if (!NS_ProcessNextEvent(thread)) {
       NS_ERROR("Failed to process next event!");
       break;
     }
   }
 
   // Make sure the service is still accessible while any generated callbacks
   // are processed.
@@ -147,167 +148,166 @@ FileService::IsShuttingDown()
 nsresult
 FileService::Enqueue(LockedFile* aLockedFile, FileHelper* aFileHelper)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aLockedFile, "Null pointer!");
 
   FileHandle* fileHandle = aLockedFile->mFileHandle;
 
-  if (fileHandle->mFileStorage->IsInvalidated()) {
+  if (fileHandle->IsInvalid()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  const nsACString& storageId = fileHandle->mFileStorage->Id();
+  const nsACString& storageId = fileHandle->mStorageId;
   const nsAString& fileName = fileHandle->mFileName;
   bool modeIsWrite = aLockedFile->mMode == FileMode::Readwrite;
 
-  FileStorageInfo* fileStorageInfo;
-  if (!mFileStorageInfos.Get(storageId, &fileStorageInfo)) {
-    nsAutoPtr<FileStorageInfo> newFileStorageInfo(new FileStorageInfo());
+  StorageInfo* storageInfo;
+  if (!mStorageInfos.Get(storageId, &storageInfo)) {
+    nsAutoPtr<StorageInfo> newStorageInfo(new StorageInfo());
 
-    mFileStorageInfos.Put(storageId, newFileStorageInfo);
+    mStorageInfos.Put(storageId, newStorageInfo);
 
-    fileStorageInfo = newFileStorageInfo.forget();
+    storageInfo = newStorageInfo.forget();
   }
 
   LockedFileQueue* existingLockedFileQueue =
-    fileStorageInfo->GetLockedFileQueue(aLockedFile);
+    storageInfo->GetLockedFileQueue(aLockedFile);
 
   if (existingLockedFileQueue) {
     existingLockedFileQueue->Enqueue(aFileHelper);
     return NS_OK;
   }
 
-  bool lockedForReading = fileStorageInfo->IsFileLockedForReading(fileName);
-  bool lockedForWriting = fileStorageInfo->IsFileLockedForWriting(fileName);
+  bool lockedForReading = storageInfo->IsFileLockedForReading(fileName);
+  bool lockedForWriting = storageInfo->IsFileLockedForWriting(fileName);
 
   if (modeIsWrite) {
     if (!lockedForWriting) {
-      fileStorageInfo->LockFileForWriting(fileName);
+      storageInfo->LockFileForWriting(fileName);
     }
   }
   else {
     if (!lockedForReading) {
-      fileStorageInfo->LockFileForReading(fileName);
+      storageInfo->LockFileForReading(fileName);
     }
   }
 
   if (lockedForWriting || (lockedForReading && modeIsWrite)) {
-    fileStorageInfo->CreateDelayedEnqueueInfo(aLockedFile, aFileHelper);
+    storageInfo->CreateDelayedEnqueueInfo(aLockedFile, aFileHelper);
   }
   else {
     LockedFileQueue* lockedFileQueue =
-      fileStorageInfo->CreateLockedFileQueue(aLockedFile);
+      storageInfo->CreateLockedFileQueue(aLockedFile);
 
     if (aFileHelper) {
       // Enqueue() will queue the file helper if there's already something
       // running. That can't fail, so no need to eventually remove
-      // fileStorageInfo from the hash table.
+      // storageInfo from the hash table.
       //
       // If the file helper is free to run then AsyncRun() is called on the
       // file helper. AsyncRun() is responsible for calling all necessary
       // callbacks when something fails. We're propagating the error here,
-      // however there's no need to eventually remove fileStorageInfo from
+      // however there's no need to eventually remove storageInfo from
       // the hash table. Code behind AsyncRun() will take care of it. The last
       // item in the code path is NotifyLockedFileCompleted() which removes
-      // fileStorageInfo from the hash table if there are no locked files for
+      // storageInfo from the hash table if there are no locked files for
       // the file storage.
       nsresult rv = lockedFileQueue->Enqueue(aFileHelper);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   return NS_OK;
 }
 
 void
 FileService::NotifyLockedFileCompleted(LockedFile* aLockedFile)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aLockedFile, "Null pointer!");
 
   FileHandle* fileHandle = aLockedFile->mFileHandle;
-  const nsACString& storageId = fileHandle->mFileStorage->Id();
+  const nsACString& storageId = fileHandle->mStorageId;
 
-  FileStorageInfo* fileStorageInfo;
-  if (!mFileStorageInfos.Get(storageId, &fileStorageInfo)) {
+  StorageInfo* storageInfo;
+  if (!mStorageInfos.Get(storageId, &storageInfo)) {
     NS_ERROR("We don't know anyting about this locked file?!");
     return;
   }
 
-  fileStorageInfo->RemoveLockedFileQueue(aLockedFile);
+  storageInfo->RemoveLockedFileQueue(aLockedFile);
 
-  if (!fileStorageInfo->HasRunningLockedFiles()) {
-    mFileStorageInfos.Remove(storageId);
+  if (!storageInfo->HasRunningLockedFiles()) {
+    mStorageInfos.Remove(storageId);
 
     // See if we need to fire any complete callbacks.
     uint32_t index = 0;
     while (index < mCompleteCallbacks.Length()) {
       if (MaybeFireCallback(mCompleteCallbacks[index])) {
         mCompleteCallbacks.RemoveElementAt(index);
       }
       else {
         index++;
       }
     }
   }
 }
 
 void
 FileService::WaitForStoragesToComplete(
-                                 nsTArray<nsCOMPtr<nsIFileStorage> >& aStorages,
+                                 nsTArray<nsCOMPtr<nsIOfflineStorage> >& aStorages,
                                  nsIRunnable* aCallback)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!aStorages.IsEmpty(), "No databases to wait on!");
   NS_ASSERTION(aCallback, "Null pointer!");
 
   StoragesCompleteCallback* callback = mCompleteCallbacks.AppendElement();
   callback->mCallback = aCallback;
   callback->mStorages.SwapElements(aStorages);
 
   if (MaybeFireCallback(*callback)) {
     mCompleteCallbacks.RemoveElementAt(mCompleteCallbacks.Length() - 1);
   }
 }
 
 void
-FileService::AbortLockedFilesForStorage(nsIFileStorage* aFileStorage)
+FileService::AbortLockedFilesForStorage(nsIOfflineStorage* aStorage)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(aFileStorage, "Null pointer!");
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+  MOZ_ASSERT(aStorage, "Null pointer!");
 
-  FileStorageInfo* fileStorageInfo;
-  if (!mFileStorageInfos.Get(aFileStorage->Id(), &fileStorageInfo)) {
+  StorageInfo* storageInfo;
+  if (!mStorageInfos.Get(aStorage->Id(), &storageInfo)) {
     return;
   }
 
   nsAutoTArray<nsRefPtr<LockedFile>, 10> lockedFiles;
-  fileStorageInfo->CollectRunningAndDelayedLockedFiles(aFileStorage,
-                                                       lockedFiles);
+  storageInfo->CollectRunningAndDelayedLockedFiles(aStorage, lockedFiles);
 
   for (uint32_t index = 0; index < lockedFiles.Length(); index++) {
     ErrorResult ignored;
     lockedFiles[index]->Abort(ignored);
   }
 }
 
 bool
-FileService::HasLockedFilesForStorage(nsIFileStorage* aFileStorage)
+FileService::HasLockedFilesForStorage(nsIOfflineStorage* aStorage)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(aFileStorage, "Null pointer!");
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+  MOZ_ASSERT(aStorage, "Null pointer!");
 
-  FileStorageInfo* fileStorageInfo;
-  if (!mFileStorageInfos.Get(aFileStorage->Id(), &fileStorageInfo)) {
+  StorageInfo* storageInfo;
+  if (!mStorageInfos.Get(aStorage->Id(), &storageInfo)) {
     return false;
   }
 
-  return fileStorageInfo->HasRunningLockedFiles(aFileStorage);
+  return storageInfo->HasRunningLockedFiles(aStorage);
 }
 
 NS_IMPL_ISUPPORTS(FileService, nsIObserver)
 
 NS_IMETHODIMP
 FileService::Observe(nsISupports* aSubject, const char*  aTopic,
                      const char16_t* aData)
 {
@@ -320,17 +320,17 @@ FileService::Observe(nsISupports* aSubje
 }
 
 bool
 FileService::MaybeFireCallback(StoragesCompleteCallback& aCallback)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   for (uint32_t index = 0; index < aCallback.mStorages.Length(); index++) {
-    if (mFileStorageInfos.Get(aCallback.mStorages[index]->Id(), nullptr)) {
+    if (mStorageInfos.Get(aCallback.mStorages[index]->Id(), nullptr)) {
       return false;
     }
   }
 
   aCallback.mCallback->Run();
   return true;
 }
 
@@ -401,39 +401,39 @@ FileService::DelayedEnqueueInfo::Delayed
 {
 }
 
 FileService::DelayedEnqueueInfo::~DelayedEnqueueInfo()
 {
 }
 
 FileService::LockedFileQueue*
-FileService::FileStorageInfo::CreateLockedFileQueue(LockedFile* aLockedFile)
+FileService::StorageInfo::CreateLockedFileQueue(LockedFile* aLockedFile)
 {
   nsRefPtr<LockedFileQueue>* lockedFileQueue =
     mLockedFileQueues.AppendElement();
   *lockedFileQueue = new LockedFileQueue(aLockedFile);
   return lockedFileQueue->get();
 }
 
 FileService::LockedFileQueue*
-FileService::FileStorageInfo::GetLockedFileQueue(LockedFile* aLockedFile)
+FileService::StorageInfo::GetLockedFileQueue(LockedFile* aLockedFile)
 {
   uint32_t count = mLockedFileQueues.Length();
   for (uint32_t index = 0; index < count; index++) {
     nsRefPtr<LockedFileQueue>& lockedFileQueue = mLockedFileQueues[index];
     if (lockedFileQueue->mLockedFile == aLockedFile) {
       return lockedFileQueue;
     }
   }
   return nullptr;
 }
 
 void
-FileService::FileStorageInfo::RemoveLockedFileQueue(LockedFile* aLockedFile)
+FileService::StorageInfo::RemoveLockedFileQueue(LockedFile* aLockedFile)
 {
   for (uint32_t index = 0; index < mDelayedEnqueueInfos.Length(); index++) {
     if (mDelayedEnqueueInfos[index].mLockedFile == aLockedFile) {
       NS_ASSERTION(!mDelayedEnqueueInfos[index].mFileHelper, "Should be null!");
       mDelayedEnqueueInfos.RemoveElementAt(index);
       return;
     }
   }
@@ -484,52 +484,51 @@ FileService::FileStorageInfo::RemoveLock
     if (NS_FAILED(gInstance->Enqueue(delayedEnqueueInfo.mLockedFile,
                                      delayedEnqueueInfo.mFileHelper))) {
       NS_WARNING("Enqueue failed!");
     }
   }
 }
 
 bool
-FileService::FileStorageInfo::HasRunningLockedFiles(
-                                                   nsIFileStorage* aFileStorage)
+FileService::StorageInfo::HasRunningLockedFiles(nsIOfflineStorage* aStorage)
 {
   for (uint32_t index = 0; index < mLockedFileQueues.Length(); index++) {
     LockedFile* lockedFile = mLockedFileQueues[index]->mLockedFile;
-    if (lockedFile->mFileHandle->mFileStorage == aFileStorage) {
+    if (lockedFile->mFileHandle->Storage() == aStorage) {
       return true;
     }
   }
   return false;
 }
 
 FileService::DelayedEnqueueInfo*
-FileService::FileStorageInfo::CreateDelayedEnqueueInfo(LockedFile* aLockedFile,
-                                                       FileHelper* aFileHelper)
+FileService::StorageInfo::CreateDelayedEnqueueInfo(LockedFile* aLockedFile,
+                                                   FileHelper* aFileHelper)
 {
   DelayedEnqueueInfo* info = mDelayedEnqueueInfos.AppendElement();
   info->mLockedFile = aLockedFile;
   info->mFileHelper = aFileHelper;
   return info;
 }
 
 void
-FileService::FileStorageInfo::CollectRunningAndDelayedLockedFiles(
-                                 nsIFileStorage* aFileStorage,
+FileService::StorageInfo::CollectRunningAndDelayedLockedFiles(
+                                 nsIOfflineStorage* aStorage,
                                  nsTArray<nsRefPtr<LockedFile> >& aLockedFiles)
 {
   for (uint32_t index = 0; index < mLockedFileQueues.Length(); index++) {
     LockedFile* lockedFile = mLockedFileQueues[index]->mLockedFile;
-    if (lockedFile->mFileHandle->mFileStorage == aFileStorage) {
+    if (lockedFile->mFileHandle->Storage() == aStorage) {
       aLockedFiles.AppendElement(lockedFile);
     }
   }
 
   for (uint32_t index = 0; index < mDelayedEnqueueInfos.Length(); index++) {
     LockedFile* lockedFile = mDelayedEnqueueInfos[index].mLockedFile;
-    if (lockedFile->mFileHandle->mFileStorage == aFileStorage) {
+    if (lockedFile->mFileHandle->Storage() == aStorage) {
       aLockedFiles.AppendElement(lockedFile);
     }
   }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/filehandle/FileService.h
+++ b/dom/filehandle/FileService.h
@@ -15,17 +15,17 @@
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsHashKeys.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 
 class nsAString;
 class nsIEventTarget;
-class nsIFileStorage;
+class nsIOfflineStorage;
 class nsIRunnable;
 
 namespace mozilla {
 namespace dom {
 
 class LockedFile;
 
 class FileService MOZ_FINAL : public nsIObserver
@@ -51,24 +51,24 @@ public:
 
   nsresult
   Enqueue(LockedFile* aLockedFile, FileHelper* aFileHelper);
 
   void
   NotifyLockedFileCompleted(LockedFile* aLockedFile);
 
   void
-  WaitForStoragesToComplete(nsTArray<nsCOMPtr<nsIFileStorage> >& aStorages,
+  WaitForStoragesToComplete(nsTArray<nsCOMPtr<nsIOfflineStorage> >& aStorages,
                             nsIRunnable* aCallback);
 
   void
-  AbortLockedFilesForStorage(nsIFileStorage* aFileStorage);
+  AbortLockedFilesForStorage(nsIOfflineStorage* aStorage);
 
   bool
-  HasLockedFilesForStorage(nsIFileStorage* aFileStorage);
+  HasLockedFilesForStorage(nsIOfflineStorage* aStorage);
 
   nsIEventTarget*
   StreamTransportTarget()
   {
     NS_ASSERTION(mStreamTransportTarget, "This should never be null!");
     return mStreamTransportTarget;
   }
 
@@ -108,17 +108,17 @@ private:
   {
     DelayedEnqueueInfo();
     ~DelayedEnqueueInfo();
 
     nsRefPtr<LockedFile> mLockedFile;
     nsRefPtr<FileHelper> mFileHelper;
   };
 
-  class FileStorageInfo
+  class StorageInfo
   {
     friend class FileService;
 
   public:
     inline LockedFileQueue*
     CreateLockedFileQueue(LockedFile* aLockedFile);
 
     inline LockedFileQueue*
@@ -129,24 +129,24 @@ private:
 
     bool
     HasRunningLockedFiles()
     {
       return !mLockedFileQueues.IsEmpty();
     }
 
     inline bool
-    HasRunningLockedFiles(nsIFileStorage* aFileStorage);
+    HasRunningLockedFiles(nsIOfflineStorage* aStorage);
 
     inline DelayedEnqueueInfo*
     CreateDelayedEnqueueInfo(LockedFile* aLockedFile, FileHelper* aFileHelper);
 
     inline void
     CollectRunningAndDelayedLockedFiles(
-                                 nsIFileStorage* aFileStorage,
+                                 nsIOfflineStorage* aStorage,
                                  nsTArray<nsRefPtr<LockedFile> >& aLockedFiles);
 
     void
     LockFileForReading(const nsAString& aFileName)
     {
       mFilesReading.PutEntry(aFileName);
     }
 
@@ -164,45 +164,45 @@ private:
 
     bool
     IsFileLockedForWriting(const nsAString& aFileName)
     {
       return mFilesWriting.Contains(aFileName);
     }
 
   private:
-    FileStorageInfo()
+    StorageInfo()
     {
     }
 
     nsTArray<nsRefPtr<LockedFileQueue> > mLockedFileQueues;
     nsTArray<DelayedEnqueueInfo> mDelayedEnqueueInfos;
     nsTHashtable<nsStringHashKey> mFilesReading;
     nsTHashtable<nsStringHashKey> mFilesWriting;
   };
 
   struct StoragesCompleteCallback
   {
-    nsTArray<nsCOMPtr<nsIFileStorage> > mStorages;
+    nsTArray<nsCOMPtr<nsIOfflineStorage> > mStorages;
     nsCOMPtr<nsIRunnable> mCallback;
   };
 
   FileService();
   ~FileService();
 
   nsresult
   Init();
 
   nsresult
   Cleanup();
 
   bool
   MaybeFireCallback(StoragesCompleteCallback& aCallback);
 
   nsCOMPtr<nsIEventTarget> mStreamTransportTarget;
-  nsClassHashtable<nsCStringHashKey, FileStorageInfo> mFileStorageInfos;
+  nsClassHashtable<nsCStringHashKey, StorageInfo> mStorageInfos;
   nsTArray<StoragesCompleteCallback> mCompleteCallbacks;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_FileService_h
--- a/dom/filehandle/FileStreamWrappers.cpp
+++ b/dom/filehandle/FileStreamWrappers.cpp
@@ -1,22 +1,22 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FileStreamWrappers.h"
 
+#include "FileHandle.h"
 #include "FileHelper.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Attributes.h"
 #include "nsDebug.h"
 #include "nsError.h"
-#include "nsIFileStorage.h"
 #include "nsIRunnable.h"
 #include "nsISeekableStream.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace {
@@ -247,17 +247,17 @@ FileOutputStreamWrapper::Close()
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
   nsresult rv = NS_OK;
 
   if (!mFirstTime) {
     NS_ASSERTION(PR_GetCurrentThread() == mWriteThread,
                  "Unsetting thread locals on wrong thread!");
-    mFileHelper->mFileStorage->UnsetThreadLocals();
+    mFileHelper->mFileHandle->UnsetThreadLocals();
   }
 
   if (mFlags & NOTIFY_CLOSE) {
     nsCOMPtr<nsIRunnable> runnable = new CloseRunnable(mFileHelper);
 
     if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
       NS_WARNING("Failed to dispatch to the main thread!");
     }
@@ -278,17 +278,17 @@ FileOutputStreamWrapper::Write(const cha
   nsresult rv;
 
   if (mFirstTime) {
     mFirstTime = false;
 
 #ifdef DEBUG
     mWriteThread = PR_GetCurrentThread();
 #endif
-    mFileHelper->mFileStorage->SetThreadLocals();
+    mFileHelper->mFileHandle->SetThreadLocals();
 
     nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mOutputStream);
     if (seekable) {
       if (mOffset == UINT64_MAX) {
         rv = seekable->Seek(nsISeekableStream::NS_SEEK_END, 0);
       }
       else {
         rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, mOffset);
--- a/dom/filehandle/LockedFile.cpp
+++ b/dom/filehandle/LockedFile.cpp
@@ -19,17 +19,16 @@
 #include "mozilla/EventDispatcher.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsIAppShell.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMFile.h"
 #include "nsIEventTarget.h"
-#include "nsIFileStorage.h"
 #include "nsISeekableStream.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsStringStream.h"
 #include "nsThreadUtils.h"
 #include "nsWidgetsCID.h"
 
@@ -311,18 +310,17 @@ LockedFile::OnRequestFinished()
   }
 }
 
 nsresult
 LockedFile::CreateParallelStream(nsISupports** aStream)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  nsIFileStorage* fileStorage = mFileHandle->mFileStorage;
-  if (fileStorage->IsInvalidated()) {
+  if (mFileHandle->IsInvalid()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsCOMPtr<nsISupports> stream =
     mFileHandle->CreateStream(mFileHandle->mFile, mMode == FileMode::Readonly);
   NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);
 
   mParallelStreams.AppendElement(stream);
@@ -331,18 +329,17 @@ LockedFile::CreateParallelStream(nsISupp
   return NS_OK;
 }
 
 nsresult
 LockedFile::GetOrCreateStream(nsISupports** aStream)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  nsIFileStorage* fileStorage = mFileHandle->mFileStorage;
-  if (fileStorage->IsInvalidated()) {
+  if (mFileHandle->IsInvalid()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (!mStream) {
     nsCOMPtr<nsISupports> stream =
       mFileHandle->CreateStream(mFileHandle->mFile, mMode == FileMode::Readonly);
     NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);
 
@@ -848,18 +845,17 @@ FinishHelper::Run()
       NS_WARNING("Dispatch failed!");
     }
 
     mLockedFile = nullptr;
 
     return NS_OK;
   }
 
-  nsIFileStorage* fileStorage = mLockedFile->mFileHandle->mFileStorage;
-  if (fileStorage->IsInvalidated()) {
+  if (mLockedFile->mFileHandle->IsInvalid()) {
     mAborted = true;
   }
 
   for (uint32_t index = 0; index < mParallelStreams.Length(); index++) {
     nsCOMPtr<nsIInputStream> stream =
       do_QueryInterface(mParallelStreams[index]);
 
     if (NS_FAILED(stream->Close())) {
--- a/dom/filehandle/moz.build
+++ b/dom/filehandle/moz.build
@@ -1,20 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 TEST_DIRS += ['test']
 
-EXPORTS += [
-    'nsIFileStorage.h',
-]
-
 EXPORTS.mozilla.dom += [
     'File.h',
     'FileHandle.h',
     'FileHelper.h',
     'FileRequest.h',
     'FileService.h',
     'LockedFile.h',
 ]
deleted file mode 100644
--- a/dom/filehandle/nsIFileStorage.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsIFileStorage_h__
-#define nsIFileStorage_h__
-
-#include "nsISupports.h"
-
-#define NS_FILESTORAGE_IID \
-  {0x6278f453, 0xd557, 0x4a55, \
-  { 0x99, 0x3e, 0xf4, 0x69, 0xe2, 0xa5, 0xe1, 0xd0 } }
-
-class nsACString;
-
-class nsIFileStorage : public nsISupports
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_FILESTORAGE_IID)
-
-  NS_IMETHOD_(const nsACString&)
-  Id() = 0;
-
-  // Whether or not the storage has been invalidated. If it has then no further
-  // operations for this storage will be allowed to run.
-  NS_IMETHOD_(bool)
-  IsInvalidated() = 0;
-
-  NS_IMETHOD_(bool)
-  IsShuttingDown() = 0;
-
-  NS_IMETHOD_(void)
-  SetThreadLocals() = 0;
-
-  NS_IMETHOD_(void)
-  UnsetThreadLocals() = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIFileStorage, NS_FILESTORAGE_IID)
-
-#define NS_DECL_NSIFILESTORAGE                                                 \
-  NS_IMETHOD_(const nsACString&)                                               \
-  Id() MOZ_OVERRIDE;                                                           \
-                                                                               \
-  NS_IMETHOD_(bool)                                                            \
-  IsInvalidated() MOZ_OVERRIDE;                                                \
-                                                                               \
-  NS_IMETHOD_(bool)                                                            \
-  IsShuttingDown() MOZ_OVERRIDE;                                               \
-                                                                               \
-  NS_IMETHOD_(void)                                                            \
-  SetThreadLocals() MOZ_OVERRIDE;                                              \
-                                                                               \
-  NS_IMETHOD_(void)                                                            \
-  UnsetThreadLocals() MOZ_OVERRIDE;
-
-#endif // nsIFileStorage_h__
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -482,17 +482,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
   // Don't unlink mFactory!
 
   // Do some cleanup.
   tmp->OnUnlink();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBDatabase)
-  NS_INTERFACE_MAP_ENTRY(nsIFileStorage)
   NS_INTERFACE_MAP_ENTRY(nsIOfflineStorage)
 NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
 
 NS_IMPL_ADDREF_INHERITED(IDBDatabase, IDBWrapperCache)
 NS_IMPL_RELEASE_INHERITED(IDBDatabase, IDBWrapperCache)
 
 JSObject*
 IDBDatabase::WrapObject(JSContext* aCx)
@@ -740,41 +739,16 @@ IDBDatabase::Close()
 }
 
 NS_IMETHODIMP_(const nsACString&)
 IDBDatabase::Id()
 {
   return mDatabaseId;
 }
 
-NS_IMETHODIMP_(bool)
-IDBDatabase::IsInvalidated()
-{
-  return mInvalidated;
-}
-
-NS_IMETHODIMP_(bool)
-IDBDatabase::IsShuttingDown()
-{
-  return QuotaManager::IsShuttingDown();
-}
-
-NS_IMETHODIMP_(void)
-IDBDatabase::SetThreadLocals()
-{
-  NS_ASSERTION(GetOwner(), "Should have owner!");
-  QuotaManager::SetCurrentWindow(GetOwner());
-}
-
-NS_IMETHODIMP_(void)
-IDBDatabase::UnsetThreadLocals()
-{
-  QuotaManager::SetCurrentWindow(nullptr);
-}
-
 NS_IMETHODIMP_(mozilla::dom::quota::Client*)
 IDBDatabase::GetClient()
 {
   return mQuotaClient;
 }
 
 NS_IMETHODIMP_(bool)
 IDBDatabase::IsOwned(nsPIDOMWindow* aOwner)
@@ -949,13 +923,13 @@ CreateFileHelper::DoDatabaseWork(mozISto
   return NS_OK;
 }
 
 nsresult
 CreateFileHelper::GetSuccessResult(JSContext* aCx,
                                    JS::MutableHandle<JS::Value> aVal)
 {
   nsRefPtr<IDBFileHandle> fileHandle =
-    IDBFileHandle::Create(mDatabase, mName, mType, mFileInfo.forget());
+    IDBFileHandle::Create(mName, mType, mDatabase, mFileInfo.forget());
   IDB_ENSURE_TRUE(fileHandle, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return WrapNative(aCx, NS_ISUPPORTS_CAST(EventTarget*, fileHandle), aVal);
 }
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_indexeddb_idbdatabase_h__
 #define mozilla_dom_indexeddb_idbdatabase_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
 #include "nsIDocument.h"
-#include "nsIFileStorage.h"
 #include "nsIOfflineStorage.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/IDBObjectStoreBinding.h"
 #include "mozilla/dom/IDBTransactionBinding.h"
 #include "mozilla/dom/quota/PersistenceType.h"
 
@@ -54,39 +53,31 @@ class IDBDatabase : public IDBWrapperCac
 {
   friend class AsyncConnectionHelper;
   friend class IndexedDatabaseManager;
   friend class IndexedDBDatabaseParent;
   friend class IndexedDBDatabaseChild;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIFILESTORAGE
   NS_DECL_NSIOFFLINESTORAGE
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBDatabase, IDBWrapperCache)
 
   static already_AddRefed<IDBDatabase>
   Create(IDBWrapperCache* aOwnerCache,
          IDBFactory* aFactory,
          already_AddRefed<DatabaseInfo> aDatabaseInfo,
          const nsACString& aASCIIOrigin,
          FileManager* aFileManager,
          mozilla::dom::ContentParent* aContentParent);
 
   static IDBDatabase*
   FromStorage(nsIOfflineStorage* aStorage);
 
-  static IDBDatabase*
-  FromStorage(nsIFileStorage* aStorage)
-  {
-    nsCOMPtr<nsIOfflineStorage> storage = do_QueryInterface(aStorage);
-    return storage ? FromStorage(storage) : nullptr;
-  }
-
   // nsIDOMEventTarget
   virtual nsresult PostHandleEvent(
                      EventChainPostVisitor& aVisitor) MOZ_OVERRIDE;
 
   DatabaseInfo* Info() const
   {
     return mDatabaseInfo;
   }
@@ -106,16 +97,24 @@ public:
     if (!GetOwner()) {
       return nullptr;
     }
 
     nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
     return doc.forget();
   }
 
+  // Whether or not the database has been invalidated. If it has then no further
+  // transactions for this database will be allowed to run. This function may be
+  // called on any thread.
+  bool IsInvalidated() const
+  {
+    return mInvalidated;
+  }
+
   void DisconnectFromActorParent();
 
   void CloseInternal(bool aIsDead);
 
   void EnterSetVersionTransaction();
   void ExitSetVersionTransaction();
 
   // Called when a versionchange transaction is aborted to reset the
--- a/dom/indexedDB/IDBFileHandle.cpp
+++ b/dom/indexedDB/IDBFileHandle.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IDBFileHandle.h"
 
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/IDBFileHandleBinding.h"
 #include "mozilla/dom/quota/FileStreams.h"
+#include "mozilla/dom/quota/QuotaManager.h"
 
 #include "IDBDatabase.h"
 
 USING_INDEXEDDB_NAMESPACE
 USING_QUOTA_NAMESPACE
 
 namespace {
 
@@ -35,52 +36,77 @@ GetFileFor(FileInfo* aFileInfo)
 
 } // anonymous namespace
 
 IDBFileHandle::IDBFileHandle(IDBDatabase* aOwner)
   : FileHandle(aOwner)
 {
 }
 
+NS_IMPL_CYCLE_COLLECTION_INHERITED(IDBFileHandle, FileHandle, mDatabase)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBFileHandle)
+NS_INTERFACE_MAP_END_INHERITING(FileHandle)
+
+NS_IMPL_ADDREF_INHERITED(IDBFileHandle, FileHandle)
+NS_IMPL_RELEASE_INHERITED(IDBFileHandle, FileHandle)
+
 // static
 already_AddRefed<IDBFileHandle>
-IDBFileHandle::Create(IDBDatabase* aDatabase,
-                      const nsAString& aName,
+IDBFileHandle::Create(const nsAString& aName,
                       const nsAString& aType,
+                      IDBDatabase* aDatabase,
                       already_AddRefed<FileInfo> aFileInfo)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsRefPtr<FileInfo> fileInfo(aFileInfo);
   NS_ASSERTION(fileInfo, "Null pointer!");
 
   nsRefPtr<IDBFileHandle> newFile = new IDBFileHandle(aDatabase);
 
-  newFile->mFileStorage = aDatabase;
   newFile->mName = aName;
   newFile->mType = aType;
 
   newFile->mFile = GetFileFor(fileInfo);
   NS_ENSURE_TRUE(newFile->mFile, nullptr);
+
+  newFile->mStorageId = aDatabase->Id();
   newFile->mFileName.AppendInt(fileInfo->Id());
 
+  newFile->mDatabase = aDatabase;
   fileInfo.swap(newFile->mFileInfo);
 
   return newFile.forget();
 }
 
+bool
+IDBFileHandle::IsShuttingDown()
+{
+  return QuotaManager::IsShuttingDown() || FileHandle::IsShuttingDown();
+}
+
+bool
+IDBFileHandle::IsInvalid()
+{
+  return mDatabase->IsInvalidated();
+}
+
+nsIOfflineStorage*
+IDBFileHandle::Storage()
+{
+  return mDatabase;
+}
+
 already_AddRefed<nsISupports>
 IDBFileHandle::CreateStream(nsIFile* aFile, bool aReadOnly)
 {
-  nsCOMPtr<nsIOfflineStorage> storage = do_QueryInterface(mFileStorage);
-  NS_ASSERTION(storage, "This should always succeed!");
-
-  PersistenceType persistenceType = storage->Type();
-  const nsACString& group = storage->Group();
-  const nsACString& origin = storage->Origin();
+  PersistenceType persistenceType = mDatabase->Type();
+  const nsACString& group = mDatabase->Group();
+  const nsACString& origin = mDatabase->Origin();
 
   nsCOMPtr<nsISupports> result;
 
   if (aReadOnly) {
     nsRefPtr<FileInputStream> stream =
       FileInputStream::Create(persistenceType, group, origin, aFile, -1, -1,
                               nsIFileInputStream::DEFER_OPEN);
     result = NS_ISUPPORTS_CAST(nsIFileInputStream*, stream);
@@ -91,35 +117,37 @@ IDBFileHandle::CreateStream(nsIFile* aFi
                          nsIFileStream::DEFER_OPEN);
     result = NS_ISUPPORTS_CAST(nsIFileStream*, stream);
   }
   NS_ENSURE_TRUE(result, nullptr);
 
   return result.forget();
 }
 
+void
+IDBFileHandle::SetThreadLocals()
+{
+  MOZ_ASSERT(mDatabase->GetOwner(), "Should have owner!");
+  QuotaManager::SetCurrentWindow(mDatabase->GetOwner());
+}
+
+void
+IDBFileHandle::UnsetThreadLocals()
+{
+  QuotaManager::SetCurrentWindow(nullptr);
+}
+
 already_AddRefed<nsIDOMFile>
 IDBFileHandle::CreateFileObject(mozilla::dom::LockedFile* aLockedFile,
                                 uint32_t aFileSize)
 {
   nsCOMPtr<nsIDOMFile> file =
     new File(mName, mType, aFileSize, mFile, aLockedFile, mFileInfo);
 
   return file.forget();
 }
 
 // virtual
 JSObject*
 IDBFileHandle::WrapObject(JSContext* aCx)
 {
   return IDBFileHandleBinding::Wrap(aCx, this);
 }
-
-IDBDatabase*
-IDBFileHandle::Database()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  IDBDatabase* database = static_cast<IDBDatabase*>(mFileStorage.get());
-  MOZ_ASSERT(database);
-
-  return database;
-}
--- a/dom/indexedDB/IDBFileHandle.h
+++ b/dom/indexedDB/IDBFileHandle.h
@@ -4,64 +4,93 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_indexeddb_idbfilehandle_h__
 #define mozilla_dom_indexeddb_idbfilehandle_h__
 
 #include "IndexedDatabase.h"
 
+#include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/dom/FileHandle.h"
 #include "mozilla/dom/indexedDB/FileInfo.h"
+#include "nsCycleCollectionParticipant.h"
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class IDBDatabase;
 
 class IDBFileHandle : public FileHandle
 {
   typedef mozilla::dom::LockedFile LockedFile;
 
 public:
+  NS_DECL_ISUPPORTS_INHERITED
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBFileHandle, FileHandle)
+
   static already_AddRefed<IDBFileHandle>
-  Create(IDBDatabase* aDatabase, const nsAString& aName,
-         const nsAString& aType, already_AddRefed<FileInfo> aFileInfo);
+  Create(const nsAString& aName, const nsAString& aType,
+         IDBDatabase* aDatabase, already_AddRefed<FileInfo> aFileInfo);
 
 
   virtual int64_t
   GetFileId() MOZ_OVERRIDE
   {
     return mFileInfo->Id();
   }
 
   virtual FileInfo*
   GetFileInfo() MOZ_OVERRIDE
   {
     return mFileInfo;
   }
 
+  virtual bool
+  IsShuttingDown() MOZ_OVERRIDE;
+
+  virtual bool
+  IsInvalid() MOZ_OVERRIDE;
+
+  virtual nsIOfflineStorage*
+  Storage() MOZ_OVERRIDE;
+
   virtual already_AddRefed<nsISupports>
   CreateStream(nsIFile* aFile, bool aReadOnly) MOZ_OVERRIDE;
 
+  virtual void
+  SetThreadLocals() MOZ_OVERRIDE;
+
+  virtual void
+  UnsetThreadLocals() MOZ_OVERRIDE;
+
   virtual already_AddRefed<nsIDOMFile>
   CreateFileObject(LockedFile* aLockedFile, uint32_t aFileSize) MOZ_OVERRIDE;
 
   // nsWrapperCache
   virtual JSObject*
   WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   // WebIDL
   IDBDatabase*
-  Database();
+  Database()
+  {
+    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+    return mDatabase;
+  }
 
 private:
   IDBFileHandle(IDBDatabase* aOwner);
 
   ~IDBFileHandle()
   {
   }
 
+  nsRefPtr<IDBDatabase> mDatabase;
   nsRefPtr<FileInfo> mFileInfo;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbfilehandle_h__
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -772,18 +772,18 @@ public:
                                            IDBDatabase* aDatabase,
                                            StructuredCloneFile& aFile,
                                            const FileHandleData& aData)
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     nsRefPtr<FileInfo>& fileInfo = aFile.mFileInfo;
 
-    nsRefPtr<IDBFileHandle> fileHandle = IDBFileHandle::Create(aDatabase,
-      aData.name, aData.type, fileInfo.forget());
+    nsRefPtr<IDBFileHandle> fileHandle = IDBFileHandle::Create(aData.name,
+      aData.type, aDatabase, fileInfo.forget());
 
     return fileHandle->WrapObject(aCx);
   }
 
   static JSObject* CreateAndWrapBlobOrFile(JSContext* aCx,
                                            IDBDatabase* aDatabase,
                                            StructuredCloneFile& aFile,
                                            const BlobOrFileData& aData)
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -4,17 +4,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IndexedDatabaseManager.h"
 
 #include "nsIConsoleService.h"
 #include "nsIDiskSpaceWatcher.h"
 #include "nsIFile.h"
-#include "nsIFileStorage.h"
 #include "nsIObserverService.h"
 #include "nsIScriptError.h"
 
 #include "jsapi.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/dom/ErrorEventBinding.h"
--- a/dom/quota/QuotaManager.cpp
+++ b/dom/quota/QuotaManager.cpp
@@ -2414,17 +2414,17 @@ QuotaManager::Observe(nsISupports* aSubj
 
         nsTArray<uint32_t> indexes;
         for (uint32_t index = 0; index < Client::TYPE_MAX; index++) {
           if (mClients[index]->IsFileServiceUtilized()) {
             indexes.AppendElement(index);
           }
         }
 
-        StorageMatcher<nsTArray<nsCOMPtr<nsIFileStorage> > > liveStorages;
+        StorageMatcher<nsTArray<nsCOMPtr<nsIOfflineStorage>>> liveStorages;
         liveStorages.Find(mLiveStorages, &indexes);
 
         if (!liveStorages.IsEmpty()) {
           nsRefPtr<WaitForLockedFilesToFinishRunnable> runnable =
             new WaitForLockedFilesToFinishRunnable();
 
           service->WaitForStoragesToComplete(liveStorages, runnable);
 
@@ -2791,17 +2791,17 @@ QuotaManager::RunSynchronizedOp(nsIOffli
   nsRefPtr<WaitForTransactionsToFinishRunnable> runnable =
     new WaitForTransactionsToFinishRunnable(aOp);
 
   // Ask the file service to call us back when it's done with this storage.
   FileService* service = FileService::Get();
 
   if (service) {
     // Have to copy here in case a transaction service needs a list too.
-    nsTArray<nsCOMPtr<nsIFileStorage> > array;
+    nsTArray<nsCOMPtr<nsIOfflineStorage>> array;
 
     for (uint32_t index = startIndex; index < endIndex; index++)  {
       if (!storages[index].IsEmpty() &&
           mClients[index]->IsFileServiceUtilized()) {
         array.AppendElements(storages[index]);
       }
     }
 
--- a/dom/quota/nsIOfflineStorage.h
+++ b/dom/quota/nsIOfflineStorage.h
@@ -2,42 +2,43 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsIOfflineStorage_h__
 #define nsIOfflineStorage_h__
 
-#include "nsIFileStorage.h"
-
 #include "mozilla/dom/quota/PersistenceType.h"
 
 #define NS_OFFLINESTORAGE_IID \
-  {0xec7e878d, 0xc8c1, 0x402e, \
-  { 0xa2, 0xc4, 0xf6, 0x82, 0x29, 0x4e, 0x3c, 0xb1 } }
+  {0x3ae00063, 0x6c13, 0x4afd, \
+  { 0x86, 0x7d, 0x33, 0xc2, 0x12, 0xd8, 0x97, 0x25 } }
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 namespace quota {
 class Client;
 }
 }
 }
 
-class nsIOfflineStorage : public nsIFileStorage
+class nsIOfflineStorage : public nsISupports
 {
 public:
   typedef mozilla::dom::quota::Client Client;
   typedef mozilla::dom::quota::PersistenceType PersistenceType;
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_OFFLINESTORAGE_IID)
 
+  NS_IMETHOD_(const nsACString&)
+  Id() = 0;
+
   NS_IMETHOD_(Client*)
   GetClient() = 0;
 
   NS_IMETHOD_(bool)
   IsOwned(nsPIDOMWindow* aOwner) = 0;
 
   NS_IMETHOD_(PersistenceType)
   Type()
@@ -78,16 +79,19 @@ protected:
 
   PersistenceType mPersistenceType;
   nsCString mGroup;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIOfflineStorage, NS_OFFLINESTORAGE_IID)
 
 #define NS_DECL_NSIOFFLINESTORAGE                                              \
+  NS_IMETHOD_(const nsACString&)                                               \
+  Id() MOZ_OVERRIDE;                                                           \
+                                                                               \
   NS_IMETHOD_(Client*)                                                         \
   GetClient() MOZ_OVERRIDE;                                                    \
                                                                                \
   NS_IMETHOD_(bool)                                                            \
   IsOwned(nsPIDOMWindow* aOwner) MOZ_OVERRIDE;                                 \
                                                                                \
   NS_IMETHOD_(const nsACString&)                                               \
   Origin() MOZ_OVERRIDE;                                                       \