Bug 1290481 - P4: Update padding size to the QuotaManager. r=bkelly, janv
authorTom Tung <shes050117@gmail.com>
Mon, 10 Jul 2017 17:02:44 +0800
changeset 429024 8c60914e10e9595831071bcb6e02de39a90b1e96
parent 429023 3b635d9ede1b2bb834abd31a0a81ead928695bdf
child 429025 bafa89b7f292ed24d69c57c5dcc041723b386e32
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbkelly, janv
bugs1290481
milestone57.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 1290481 - P4: Update padding size to the QuotaManager. r=bkelly, janv MozReview-Commit-ID: 6poDeyErBjc
dom/cache/FileUtils.cpp
dom/cache/FileUtils.h
dom/cache/Manager.cpp
dom/quota/ActorsParent.cpp
dom/quota/QuotaManager.h
dom/quota/QuotaObject.h
--- a/dom/cache/FileUtils.cpp
+++ b/dom/cache/FileUtils.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=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 "mozilla/dom/cache/FileUtils.h"
 
+#include "mozilla/dom/InternalResponse.h"
 #include "mozilla/dom/quota/FileStreams.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/SnappyCompressOutputStream.h"
 #include "mozilla/Unused.h"
 #include "nsIFile.h"
 #include "nsIUUIDGenerator.h"
 #include "nsNetCID.h"
 #include "nsISimpleEnumerator.h"
@@ -21,29 +22,33 @@
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 using mozilla::dom::quota::FileInputStream;
 using mozilla::dom::quota::FileOutputStream;
 using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
 using mozilla::dom::quota::QuotaManager;
+using mozilla::dom::quota::QuotaObject;
 
 namespace {
 
 enum BodyFileType
 {
   BODY_FILE_FINAL,
   BODY_FILE_TMP
 };
 
 nsresult
 BodyIdToFile(nsIFile* aBaseDir, const nsID& aId, BodyFileType aType,
              nsIFile** aBodyFileOut);
 
+int64_t
+BodyGeneratePadding(const int64_t aBodyFileSize);
+
 } // namespace
 
 // static
 nsresult
 BodyCreateDir(nsIFile* aBaseDir)
 {
   MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
 
@@ -243,16 +248,54 @@ BodyOpen(const QuotaInfo& aQuotaInfo, ns
 
   fileStream.forget(aStreamOut);
 
   return rv;
 }
 
 // static
 nsresult
+BodyMaybeUpdatePaddingSize(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
+                           const nsID& aId, int64_t* aPaddingSizeOut)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
+  MOZ_DIAGNOSTIC_ASSERT(aPaddingSizeOut);
+
+  nsCOMPtr<nsIFile> bodyFile;
+  nsresult rv =
+    BodyIdToFile(aBaseDir, aId, BODY_FILE_TMP, getter_AddRefs(bodyFile));
+  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
+  MOZ_DIAGNOSTIC_ASSERT(bodyFile);
+
+  QuotaManager* quotaManager = QuotaManager::Get();
+  MOZ_DIAGNOSTIC_ASSERT(quotaManager);
+
+  int64_t fileSize = 0;
+  RefPtr<QuotaObject> quotaObject =
+    quotaManager->GetQuotaObject(PERSISTENCE_TYPE_DEFAULT, aQuotaInfo.mGroup,
+                                 aQuotaInfo.mOrigin, bodyFile, &fileSize);
+  MOZ_DIAGNOSTIC_ASSERT(quotaObject);
+  MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0);
+
+  if (*aPaddingSizeOut == InternalResponse::UNKNOWN_PADDING_SIZE) {
+    *aPaddingSizeOut = BodyGeneratePadding(fileSize);
+  }
+
+  MOZ_DIAGNOSTIC_ASSERT(*aPaddingSizeOut >= 0);
+
+  if (!quotaObject->IncreaseSize(*aPaddingSizeOut)) {
+    return NS_ERROR_FILE_NO_DEVICE_SPACE;
+  }
+
+  return rv;
+}
+
+// static
+nsresult
 BodyDeleteFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
                 const nsTArray<nsID>& aIdList)
 {
   nsresult rv = NS_OK;
 
   for (uint32_t i = 0; i < aIdList.Length(); ++i) {
     nsCOMPtr<nsIFile> tmpFile;
     rv = BodyIdToFile(aBaseDir, aIdList[i], BODY_FILE_TMP,
@@ -305,16 +348,23 @@ BodyIdToFile(nsIFile* aBaseDir, const ns
   }
 
   rv = (*aBodyFileOut)->Append(fileName);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
+int64_t
+BodyGeneratePadding(const int64_t aBodyFileSize)
+{
+  // XXXtt: Will deal with it in the next patch.
+  return 0;
+}
+
 } // namespace
 
 nsresult
 BodyDeleteOrphanedFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
                         nsTArray<nsID>& aKnownBodyIdList)
 {
   MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
 
@@ -543,21 +593,33 @@ RemoveNsIFile(const QuotaInfo& aQuotaInf
       rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
     return NS_OK;
   }
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = aFile->Remove( /* recursive */ false);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
+  if (fileSize > 0) {
+    DecreaseUsageForQuotaInfo(aQuotaInfo, fileSize);
+  }
+
+  return rv;
+}
+
+// static
+void
+DecreaseUsageForQuotaInfo(const QuotaInfo& aQuotaInfo,
+                          const int64_t& aUpdatingSize)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aUpdatingSize > 0);
+
   QuotaManager* quotaManager = QuotaManager::Get();
   MOZ_DIAGNOSTIC_ASSERT(quotaManager);
 
   quotaManager->DecreaseUsageForOrigin(PERSISTENCE_TYPE_DEFAULT,
                                        aQuotaInfo.mGroup, aQuotaInfo.mOrigin,
-                                       fileSize);
-
-  return rv;
+                                       aUpdatingSize);
 }
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/cache/FileUtils.h
+++ b/dom/cache/FileUtils.h
@@ -43,16 +43,20 @@ BodyCancelWrite(nsIFile* aBaseDir, nsISu
 nsresult
 BodyFinalizeWrite(nsIFile* aBaseDir, const nsID& aId);
 
 nsresult
 BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, const nsID& aId,
          nsIInputStream** aStreamOut);
 
 nsresult
+BodyMaybeUpdatePaddingSize(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
+                           const nsID& aId, int64_t* aPaddingSizeOut);
+
+nsresult
 BodyDeleteFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
                 const nsTArray<nsID>& aIdList);
 
 nsresult
 BodyDeleteOrphanedFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
                         nsTArray<nsID>& aKnownBodyIdList);
 
 nsresult
@@ -65,13 +69,16 @@ bool
 MarkerFileExists(const QuotaInfo& aQuotaInfo);
 
 nsresult
 RemoveNsIFileRecursively(const QuotaInfo& aQuotaInfo, nsIFile* aFile);
 
 nsresult
 RemoveNsIFile(const QuotaInfo& aQuotaInfo, nsIFile* aFile);
 
+void
+DecreaseUsageForQuotaInfo(const QuotaInfo& aQuotaInfo,
+                          const int64_t& aUpdatingSize);
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_cache_FileUtils_h
--- a/dom/cache/Manager.cpp
+++ b/dom/cache/Manager.cpp
@@ -81,16 +81,20 @@ public:
         AutoTArray<nsID, 16> deletedBodyIdList;
         int64_t deletedPaddingSize = 0;
         rv = db::DeleteCacheId(aConn, orphanedCacheIdList[i], deletedBodyIdList,
                                &deletedPaddingSize);
         if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
         rv = BodyDeleteFiles(aQuotaInfo, aDBDir, deletedBodyIdList);
         if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
+        if (deletedPaddingSize > 0) {
+          DecreaseUsageForQuotaInfo(aQuotaInfo, deletedPaddingSize);
+        }
       }
 
       // Clean up orphaned body objects
       AutoTArray<nsID, 64> knownBodyIdList;
       rv = db::GetKnownBodyIds(aConn, knownBodyIdList);
 
       rv = BodyDeleteOrphanedFiles(aQuotaInfo, aDBDir, knownBodyIdList);
       if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -444,16 +448,18 @@ public:
     , mCacheId(aCacheId)
     , mDeletedPaddingSize(0)
   { }
 
   virtual nsresult
   RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
                         mozIStorageConnection* aConn) override
   {
+    mQuotaInfo.emplace(aQuotaInfo);
+
     mozStorageTransaction trans(aConn, false,
                                 mozIStorageConnection::TRANSACTION_IMMEDIATE);
 
     nsresult rv = db::DeleteCacheId(aConn, mCacheId, mDeletedBodyIdList,
                                     &mDeletedPaddingSize);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     rv = trans.Commit();
@@ -462,24 +468,29 @@ public:
     return rv;
   }
 
   virtual void
   CompleteOnInitiatingThread(nsresult aRv) override
   {
     mManager->NoteOrphanedBodyIdList(mDeletedBodyIdList);
 
+    if (mDeletedPaddingSize > 0) {
+      DecreaseUsageForQuotaInfo(mQuotaInfo.ref(), mDeletedPaddingSize);
+    }
+
     // ensure we release the manager on the initiating thread
     mManager = nullptr;
   }
 
 private:
   RefPtr<Manager> mManager;
   const CacheId mCacheId;
   nsTArray<nsID> mDeletedBodyIdList;
+  Maybe<QuotaInfo> mQuotaInfo;
   // Track any pad amount associated with orphaned entries.
   int64_t mDeletedPaddingSize;
 };
 
 // ----------------------------------------------------------------------------
 
 class Manager::CacheMatchAction final : public Manager::BaseAction
 {
@@ -622,16 +633,17 @@ public:
     : DBAction(DBAction::Existing)
     , mManager(aManager)
     , mListenerId(aListenerId)
     , mCacheId(aCacheId)
     , mList(aPutList.Length())
     , mExpectedAsyncCopyCompletions(1)
     , mAsyncResult(NS_OK)
     , mMutex("cache::Manager::CachePutAllAction")
+    , mUpdatedPaddingSize(0)
     , mDeletedPaddingSize(0)
   {
     MOZ_DIAGNOSTIC_ASSERT(!aPutList.IsEmpty());
     MOZ_DIAGNOSTIC_ASSERT(aPutList.Length() == aRequestStreamList.Length());
     MOZ_DIAGNOSTIC_ASSERT(aPutList.Length() == aResponseStreamList.Length());
 
     for (uint32_t i = 0; i < aPutList.Length(); ++i) {
       Entry* entry = mList.AppendElement();
@@ -763,32 +775,53 @@ private:
       if (e.mRequestStream) {
         rv = BodyFinalizeWrite(mDBDir, e.mRequestBodyId);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           DoResolve(rv);
           return;
         }
       }
       if (e.mResponseStream) {
+        // Gerenate padding size for opaque response if needed.
+        if (e.mResponse.type() == ResponseType::Opaque) {
+          // It'll generate padding if we've not set it yet.
+          rv = BodyMaybeUpdatePaddingSize(mQuotaInfo.ref(), mDBDir,
+                                          e.mResponseBodyId,
+                                          &e.mResponse.paddingSize());
+          if (NS_WARN_IF(NS_FAILED(rv))) {
+            DoResolve(rv);
+            return;
+          }
+
+          MOZ_DIAGNOSTIC_ASSERT(INT64_MAX - e.mResponse.paddingSize() >=
+                                mUpdatedPaddingSize);
+          mUpdatedPaddingSize += e.mResponse.paddingSize();
+        }
+
         rv = BodyFinalizeWrite(mDBDir, e.mResponseBodyId);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           DoResolve(rv);
           return;
         }
       }
 
+      int64_t deletedPaddingSize = 0;
       rv = db::CachePut(mConn, mCacheId, e.mRequest,
                         e.mRequestStream ? &e.mRequestBodyId : nullptr,
                         e.mResponse,
                         e.mResponseStream ? &e.mResponseBodyId : nullptr,
-                        mDeletedBodyIdList, &mDeletedPaddingSize);
+                        mDeletedBodyIdList, &deletedPaddingSize);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         DoResolve(rv);
         return;
       }
+
+      MOZ_DIAGNOSTIC_ASSERT(INT64_MAX - mDeletedPaddingSize >=
+                            deletedPaddingSize);
+      mDeletedPaddingSize += deletedPaddingSize;
     }
 
     // XXXtt: Write .padding file to the cache directory
     // UpdateDirectoryFile(mDBDir);
 
     rv = trans.Commit();
     Unused << NS_WARN_IF(NS_FAILED(rv));
 
@@ -802,16 +835,20 @@ private:
 
     for (uint32_t i = 0; i < mList.Length(); ++i) {
       mList[i].mRequestStream = nullptr;
       mList[i].mResponseStream = nullptr;
     }
 
     mManager->NoteOrphanedBodyIdList(mDeletedBodyIdList);
 
+    if (mDeletedPaddingSize > 0) {
+      DecreaseUsageForQuotaInfo(mQuotaInfo.ref(), mDeletedPaddingSize);
+    }
+
     Listener* listener = mManager->GetListener(mListenerId);
     mManager = nullptr;
     if (listener) {
       listener->OnOpComplete(ErrorResult(aRv), CachePutAllResult());
     }
   }
 
   virtual void
@@ -941,16 +978,19 @@ private:
       MutexAutoLock lock(mMutex);
       MOZ_ASSERT(mCopyContextList.IsEmpty());
     }
 #endif
 
     // Clean up any files we might have written before hitting the error.
     if (NS_FAILED(aRv)) {
       BodyDeleteFiles(mQuotaInfo.ref(), mDBDir, mBodyIdWrittenList);
+      if (mUpdatedPaddingSize > 0) {
+        DecreaseUsageForQuotaInfo(mQuotaInfo.ref(), mUpdatedPaddingSize);
+      }
     }
 
     // Must be released on the target thread where it was opened.
     mConn = nullptr;
 
     // Drop our ref to the target thread as we are done with this thread.
     // Also makes our thread assertions catch any incorrect method calls
     // after resolve.
@@ -984,16 +1024,19 @@ private:
   // thread activity is guaranteed complete
   nsTArray<nsID> mDeletedBodyIdList;
 
   // accessed from any thread while mMutex locked
   Mutex mMutex;
   nsTArray<nsCOMPtr<nsISupports>> mCopyContextList;
 
   Maybe<QuotaInfo> mQuotaInfo;
+  // Track how much pad amount has been added for new entries so that it can be
+  // removed if an error occurs.
+  int64_t mUpdatedPaddingSize;
   // Track any pad amount associated with overwritten entries.
   int64_t mDeletedPaddingSize;
 };
 
 // ----------------------------------------------------------------------------
 
 class Manager::CacheDeleteAction final : public Manager::BaseAction
 {
@@ -1006,16 +1049,18 @@ public:
     , mSuccess(false)
     , mDeletedPaddingSize(0)
   { }
 
   virtual nsresult
   RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
                         mozIStorageConnection* aConn) override
   {
+    mQuotaInfo.emplace(aQuotaInfo);
+
     mozStorageTransaction trans(aConn, false,
                                 mozIStorageConnection::TRANSACTION_IMMEDIATE);
 
     nsresult rv = db::CacheDelete(aConn, mCacheId, mArgs.request(),
                                   mArgs.params(), mDeletedBodyIdList,
                                   &mDeletedPaddingSize, &mSuccess);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
@@ -1040,16 +1085,17 @@ public:
     return aCacheId == mCacheId;
   }
 
 private:
   const CacheId mCacheId;
   const CacheDeleteArgs mArgs;
   bool mSuccess;
   nsTArray<nsID> mDeletedBodyIdList;
+  Maybe<QuotaInfo> mQuotaInfo;
   // Track any pad amount associated with deleted entries.
   int64_t mDeletedPaddingSize;
 };
 
 // ----------------------------------------------------------------------------
 
 class Manager::CacheKeysAction final : public Manager::BaseAction
 {
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -2924,16 +2924,65 @@ QuotaObject::Release()
 bool
 QuotaObject::MaybeUpdateSize(int64_t aSize, bool aTruncate)
 {
   QuotaManager* quotaManager = QuotaManager::Get();
   MOZ_ASSERT(quotaManager);
 
   MutexAutoLock lock(quotaManager->mQuotaMutex);
 
+  return LockedMaybeUpdateSize(aSize, aTruncate);
+}
+
+bool
+QuotaObject::IncreaseSize(int64_t aDelta)
+{
+  MOZ_ASSERT(aDelta >= 0);
+
+  QuotaManager* quotaManager = QuotaManager::Get();
+  MOZ_ASSERT(quotaManager);
+
+  MutexAutoLock lock(quotaManager->mQuotaMutex);
+
+  AssertNoOverflow(mSize, aDelta);
+  int64_t size = mSize + aDelta;
+
+  return LockedMaybeUpdateSize(size, /* aTruncate */ false);
+}
+
+void
+QuotaObject::DisableQuotaCheck()
+{
+  QuotaManager* quotaManager = QuotaManager::Get();
+  MOZ_ASSERT(quotaManager);
+
+  MutexAutoLock lock(quotaManager->mQuotaMutex);
+
+  mQuotaCheckDisabled = true;
+}
+
+void
+QuotaObject::EnableQuotaCheck()
+{
+  QuotaManager* quotaManager = QuotaManager::Get();
+  MOZ_ASSERT(quotaManager);
+
+  MutexAutoLock lock(quotaManager->mQuotaMutex);
+
+  mQuotaCheckDisabled = false;
+}
+
+bool
+QuotaObject::LockedMaybeUpdateSize(int64_t aSize, bool aTruncate)
+{
+  QuotaManager* quotaManager = QuotaManager::Get();
+  MOZ_ASSERT(quotaManager);
+
+  quotaManager->mQuotaMutex.AssertCurrentThreadOwns();
+
   if (mQuotaCheckDisabled) {
     return true;
   }
 
   if (mSize == aSize) {
     return true;
   }
 
@@ -3122,38 +3171,16 @@ QuotaObject::MaybeUpdateSize(int64_t aSi
   }
   quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;
 
   mSize = aSize;
 
   return true;
 }
 
-void
-QuotaObject::DisableQuotaCheck()
-{
-  QuotaManager* quotaManager = QuotaManager::Get();
-  MOZ_ASSERT(quotaManager);
-
-  MutexAutoLock lock(quotaManager->mQuotaMutex);
-
-  mQuotaCheckDisabled = true;
-}
-
-void
-QuotaObject::EnableQuotaCheck()
-{
-  QuotaManager* quotaManager = QuotaManager::Get();
-  MOZ_ASSERT(quotaManager);
-
-  MutexAutoLock lock(quotaManager->mQuotaMutex);
-
-  mQuotaCheckDisabled = false;
-}
-
 /*******************************************************************************
  * Quota manager
  ******************************************************************************/
 
 QuotaManager::QuotaManager()
 : mQuotaMutex("QuotaManager.mQuotaMutex"),
   mTemporaryStorageLimit(0),
   mTemporaryStorageUsage(0),
@@ -3769,20 +3796,25 @@ QuotaManager::RemoveQuota()
 
   NS_ASSERTION(mTemporaryStorageUsage == 0, "Should be zero!");
 }
 
 already_AddRefed<QuotaObject>
 QuotaManager::GetQuotaObject(PersistenceType aPersistenceType,
                              const nsACString& aGroup,
                              const nsACString& aOrigin,
-                             nsIFile* aFile)
+                             nsIFile* aFile,
+                             int64_t* aFileSizeOut /* = nullptr */)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
+  if (aFileSizeOut) {
+    *aFileSizeOut = 0;
+  }
+
   if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
     return nullptr;
   }
 
   nsString path;
   nsresult rv = aFile->GetPath(path);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
@@ -3844,35 +3876,46 @@ QuotaManager::GetQuotaObject(Persistence
       originInfo->mQuotaObjects.Put(path, quotaObject);
     }
 
     // Addref the QuotaObject and move the ownership to the result. This must
     // happen before we unlock!
     result = quotaObject->LockedAddRef();
   }
 
+  if (aFileSizeOut) {
+    *aFileSizeOut = fileSize;
+  }
+
   // The caller becomes the owner of the QuotaObject, that is, the caller is
   // is responsible to delete it when the last reference is removed.
   return result.forget();
 }
 
 already_AddRefed<QuotaObject>
 QuotaManager::GetQuotaObject(PersistenceType aPersistenceType,
                              const nsACString& aGroup,
                              const nsACString& aOrigin,
-                             const nsAString& aPath)
-{
+                             const nsAString& aPath,
+                             int64_t* aFileSizeOut /* = nullptr */)
+{
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+
+  if (aFileSizeOut) {
+    *aFileSizeOut = 0;
+  }
+
   nsresult rv;
   nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   rv = file->InitWithPath(aPath);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
-  return GetQuotaObject(aPersistenceType, aGroup, aOrigin, file);
+  return GetQuotaObject(aPersistenceType, aGroup, aOrigin, file, aFileSizeOut);
 }
 
 Nullable<bool>
 QuotaManager::OriginPersisted(const nsACString& aGroup,
                               const nsACString& aOrigin)
 {
   AssertIsOnIOThread();
 
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -172,23 +172,25 @@ public:
     MutexAutoLock lock(mQuotaMutex);
     LockedRemoveQuotaForOrigin(aPersistenceType, aGroup, aOrigin);
   }
 
   already_AddRefed<QuotaObject>
   GetQuotaObject(PersistenceType aPersistenceType,
                  const nsACString& aGroup,
                  const nsACString& aOrigin,
-                 nsIFile* aFile);
+                 nsIFile* aFile,
+                 int64_t* aFileSizeOut = nullptr);
 
   already_AddRefed<QuotaObject>
   GetQuotaObject(PersistenceType aPersistenceType,
                  const nsACString& aGroup,
                  const nsACString& aOrigin,
-                 const nsAString& aPath);
+                 const nsAString& aPath,
+                 int64_t* aFileSizeOut = nullptr);
 
   Nullable<bool>
   OriginPersisted(const nsACString& aGroup,
                   const nsACString& aOrigin);
 
   void
   PersistOrigin(const nsACString& aGroup,
                 const nsACString& aOrigin);
--- a/dom/quota/QuotaObject.h
+++ b/dom/quota/QuotaObject.h
@@ -36,16 +36,19 @@ public:
   Path() const
   {
     return mPath;
   }
 
   bool
   MaybeUpdateSize(int64_t aSize, bool aTruncate);
 
+  bool
+  IncreaseSize(int64_t aDelta);
+
   void
   DisableQuotaCheck();
 
   void
   EnableQuotaCheck();
 
 private:
   QuotaObject(OriginInfo* aOriginInfo, const nsAString& aPath, int64_t aSize)
@@ -68,16 +71,19 @@ private:
     AssertCurrentThreadOwnsQuotaMutex();
 
     ++mRefCnt;
 
     RefPtr<QuotaObject> result = dont_AddRef(this);
     return result.forget();
   }
 
+  bool
+  LockedMaybeUpdateSize(int64_t aSize, bool aTruncate);
+
   mozilla::ThreadSafeAutoRefCnt mRefCnt;
 
   OriginInfo* mOriginInfo;
   nsString mPath;
   int64_t mSize;
 
   bool mQuotaCheckDisabled;
 };