Bug 984789 - FileHandle: Eliminate nsIFileStorage; r=bent
authorJan Varga <jan.varga@gmail.com>
Wed, 07 May 2014 16:33:02 +0200
changeset 182047 ef60f8aa9a017213edff0e6413b43c4eed15e66b
parent 182046 03fdda1af1f4fc0bdf7bd71c765b89216a5a2737
child 182048 7fffbe8dc9ec9f0dc124485c112419b5a2882674
push idunknown
push userunknown
push dateunknown
reviewersbent
bugs984789
milestone32.0a1
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;                                                       \