Bug 968272 - Use less conservative temporary storage policy in QuotaManager. r=janv, a=lsblakk
authorLuke Wagner <luke@mozilla.com>
Tue, 20 May 2014 17:19:59 -0500
changeset 199336 72fc3c8e822088e2b60c1087dc87d1865a699aa4
parent 199335 15ec20e99da2f1ddbbf8d4ce504527586b15c224
child 199337 8852081d200428b55b96360fedfe6090308eceb2
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjanv, lsblakk
bugs968272
milestone31.0a2
Bug 968272 - Use less conservative temporary storage policy in QuotaManager. r=janv, a=lsblakk
dom/quota/QuotaManager.cpp
dom/quota/QuotaManager.h
--- a/dom/quota/QuotaManager.cpp
+++ b/dom/quota/QuotaManager.cpp
@@ -62,36 +62,34 @@
 #define DEFAULT_SHUTDOWN_TIMER_MS 30000
 
 // Preference that users can set to override DEFAULT_QUOTA_MB
 #define PREF_STORAGE_QUOTA "dom.indexedDB.warningQuota"
 
 // Preference that users can set to override temporary storage smart limit
 // calculation.
 #define PREF_FIXED_LIMIT "dom.quotaManager.temporaryStorage.fixedLimit"
-
-// Preferences that are used during temporary storage smart limit calculation
-#define PREF_SMART_LIMIT_PREFIX "dom.quotaManager.temporaryStorage.smartLimit."
-#define PREF_SMART_LIMIT_MIN PREF_SMART_LIMIT_PREFIX "min"
-#define PREF_SMART_LIMIT_MAX PREF_SMART_LIMIT_PREFIX "max"
-#define PREF_SMART_LIMIT_CHUNK PREF_SMART_LIMIT_PREFIX "chunk"
-#define PREF_SMART_LIMIT_RATIO PREF_SMART_LIMIT_PREFIX "ratio"
+#define PREF_CHUNK_SIZE "dom.quotaManager.temporaryStorage.chunkSize"
 
 // Preference that is used to enable testing features
 #define PREF_TESTING_FEATURES "dom.quotaManager.testing"
 
 // profile-before-change, when we need to shut down quota manager
 #define PROFILE_BEFORE_CHANGE_OBSERVER_ID "profile-before-change"
 
 // The name of the file that we use to load/save the last access time of an
 // origin.
 #define METADATA_FILE_NAME ".metadata"
 
 #define PERMISSION_DEFAUT_PERSISTENT_STORAGE "default-persistent-storage"
 
+#define KB * 1024ULL
+#define MB * 1024ULL KB
+#define GB * 1024ULL MB
+
 USING_QUOTA_NAMESPACE
 using namespace mozilla::dom;
 using mozilla::dom::file::FileService;
 
 static_assert(
   static_cast<uint32_t>(StorageType::Persistent) ==
   static_cast<uint32_t>(PERSISTENCE_TYPE_PERSISTENT),
   "Enum values should match.");
@@ -474,43 +472,27 @@ AssertCurrentThreadOwnsQuotaMutex()
 
 END_QUOTA_NAMESPACE
 
 namespace {
 
 // Amount of space that storages may use by default in megabytes.
 static const int32_t  kDefaultQuotaMB =             50;
 
-// Constants for temporary storage limit computing.
-static const int32_t  kDefaultFixedLimitKB =        -1;
-#ifdef ANDROID
-// On Android, smaller/older devices may have very little storage and
-// device owners may be sensitive to storage footprint: Use a smaller
-// percentage of available space and a smaller minimum/maximum.
-static const uint32_t kDefaultSmartLimitMinKB =     10 * 1024;
-static const uint32_t kDefaultSmartLimitMaxKB =    200 * 1024;
-static const uint32_t kDefaultSmartLimitChunkKB =    2 * 1024;
-static const float    kDefaultSmartLimitRatio =     .2f;
-#else
-static const uint64_t kDefaultSmartLimitMinKB =     50 * 1024;
-static const uint64_t kDefaultSmartLimitMaxKB =   1024 * 1024;
-static const uint32_t kDefaultSmartLimitChunkKB =   10 * 1024;
-static const float    kDefaultSmartLimitRatio =     .4f;
-#endif
 
 QuotaManager* gInstance = nullptr;
 mozilla::Atomic<bool> gShutdown(false);
 
 int32_t gStorageQuotaMB = kDefaultQuotaMB;
 
+// Constants for temporary storage limit computing.
+static const int32_t kDefaultFixedLimitKB = -1;
+static const uint32_t kDefaultChunkSizeKB = 10 * 1024;
 int32_t gFixedLimitKB = kDefaultFixedLimitKB;
-uint32_t gSmartLimitMinKB = kDefaultSmartLimitMinKB;
-uint32_t gSmartLimitMaxKB = kDefaultSmartLimitMaxKB;
-uint32_t gSmartLimitChunkKB = kDefaultSmartLimitChunkKB;
-float gSmartLimitRatio = kDefaultSmartLimitRatio;
+uint32_t gChunkSizeKB = kDefaultChunkSizeKB;
 
 bool gTestingEnabled = false;
 
 // A callback runnable used by the TransactionPool when it's safe to proceed
 // with a SetVersion/DeleteDatabase/etc.
 class WaitForTransactionsToFinishRunnable MOZ_FINAL : public nsRunnable
 {
 public:
@@ -851,85 +833,40 @@ MaybeUpgradeOriginDirectory(nsIFile* aDi
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 // This method computes and returns our best guess for the temporary storage
 // limit (in bytes), based on the amount of space users have free on their hard
-// drive and on given temporary storage usage (also in bytes). We use a tiered
-// scheme: the more space available, the larger the temporary storage will be.
-// However, we do not want to enable the temporary storage to grow to an
-// unbounded size, so the larger the user's available space is, the smaller of
-// a percentage we take. We set a lower bound of gTemporaryStorageLimitMinKB
-// and an upper bound of gTemporaryStorageLimitMaxKB.
+// drive and on given temporary storage usage (also in bytes).
 nsresult
 GetTemporaryStorageLimit(nsIFile* aDirectory, uint64_t aCurrentUsage,
                          uint64_t* aLimit)
 {
   // Check for free space on device where temporary storage directory lives.
   int64_t bytesAvailable;
   nsresult rv = aDirectory->GetDiskSpaceAvailable(&bytesAvailable);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ASSERTION(bytesAvailable >= 0, "Negative bytes available?!");
 
   uint64_t availableKB =
     static_cast<uint64_t>((bytesAvailable + aCurrentUsage) / 1024);
 
-  // Grow/shrink in gTemporaryStorageLimitChunkKB units, deliberately, so that
-  // in the common case we don't shrink temporary storage and evict origin data
-  // every time we initialize.
-  availableKB = (availableKB / gSmartLimitChunkKB) * gSmartLimitChunkKB;
-
-  // The tier scheme:
-  // .5 % of space above 25 GB
-  // 1 % of space between 7GB -> 25 GB
-  // 5 % of space between 500 MB -> 7 GB
-  // gTemporaryStorageLimitRatio of space up to 500 MB
-
-  static const uint64_t _25GB = 25 * 1024 * 1024;
-  static const uint64_t _7GB = 7 * 1024 * 1024;
-  static const uint64_t _500MB = 500 * 1024;
-
-#define PERCENTAGE(a, b, c) ((a - b) * c)
-
-  uint64_t resultKB;
-  if (availableKB > _25GB) {
-    resultKB = static_cast<uint64_t>(
-      PERCENTAGE(availableKB, _25GB, .005) +
-      PERCENTAGE(_25GB, _7GB, .01) +
-      PERCENTAGE(_7GB, _500MB, .05) +
-      PERCENTAGE(_500MB, 0, gSmartLimitRatio)
-    );
-  }
-  else if (availableKB > _7GB) {
-    resultKB = static_cast<uint64_t>(
-      PERCENTAGE(availableKB, _7GB, .01) +
-      PERCENTAGE(_7GB, _500MB, .05) +
-      PERCENTAGE(_500MB, 0, gSmartLimitRatio)
-    );
-  }
-  else if (availableKB > _500MB) {
-    resultKB = static_cast<uint64_t>(
-      PERCENTAGE(availableKB, _500MB, .05) +
-      PERCENTAGE(_500MB, 0, gSmartLimitRatio)
-    );
-  }
-  else {
-    resultKB = static_cast<uint64_t>(
-      PERCENTAGE(availableKB, 0, gSmartLimitRatio)
-    );
-  }
-
-#undef PERCENTAGE
-
-  *aLimit = 1024 * mozilla::clamped<uint64_t>(resultKB, gSmartLimitMinKB,
-                                              gSmartLimitMaxKB);
+  // Grow/shrink in gChunkSizeKB units, deliberately, so that in the common case
+  // we don't shrink temporary storage and evict origin data every time we
+  // initialize.
+  availableKB = (availableKB / gChunkSizeKB) * gChunkSizeKB;
+
+  // Allow temporary storage to consume up to half the available space.
+  uint64_t resultKB = availableKB * .50;
+
+  *aLimit = resultKB * 1024;
   return NS_OK;
 }
 
 } // anonymous namespace
 
 QuotaManager::QuotaManager()
 : mCurrentWindowIndex(BAD_TLS_INDEX),
   mQuotaMutex("QuotaManager.mQuotaMutex"),
@@ -1076,29 +1013,20 @@ QuotaManager::Init()
 
   if (NS_FAILED(Preferences::AddIntVarCache(&gStorageQuotaMB,
                                             PREF_STORAGE_QUOTA,
                                             kDefaultQuotaMB))) {
     NS_WARNING("Unable to respond to quota pref changes!");
   }
 
   if (NS_FAILED(Preferences::AddIntVarCache(&gFixedLimitKB, PREF_FIXED_LIMIT,
-                                             kDefaultFixedLimitKB)) ||
-      NS_FAILED(Preferences::AddUintVarCache(&gSmartLimitMinKB,
-                                             PREF_SMART_LIMIT_MIN,
-                                             kDefaultSmartLimitMinKB)) ||
-      NS_FAILED(Preferences::AddUintVarCache(&gSmartLimitMaxKB,
-                                             PREF_SMART_LIMIT_MAX,
-                                             kDefaultSmartLimitMaxKB)) ||
-      NS_FAILED(Preferences::AddUintVarCache(&gSmartLimitChunkKB,
-                                             PREF_SMART_LIMIT_CHUNK,
-                                             kDefaultSmartLimitChunkKB)) ||
-      NS_FAILED(Preferences::AddFloatVarCache(&gSmartLimitRatio,
-                                              PREF_SMART_LIMIT_RATIO,
-                                              kDefaultSmartLimitRatio))) {
+                                            kDefaultFixedLimitKB)) ||
+      NS_FAILED(Preferences::AddUintVarCache(&gChunkSizeKB,
+                                             PREF_CHUNK_SIZE,
+                                             kDefaultChunkSizeKB))) {
     NS_WARNING("Unable to respond to temp storage pref changes!");
   }
 
   if (NS_FAILED(Preferences::AddBoolVarCache(&gTestingEnabled,
                                              PREF_TESTING_FEATURES, false))) {
     NS_WARNING("Unable to respond to testing pref changes!");
   }
 
@@ -1935,19 +1863,19 @@ QuotaManager::EnsureOriginIsInitialized(
       mTemporaryStorageLimit = gFixedLimitKB * 1024;
     }
     else {
       rv = GetTemporaryStorageLimit(parentDirectory, mTemporaryStorageUsage,
                                     &mTemporaryStorageLimit);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
+    mTemporaryStorageInitialized = true;
+
     CheckTemporaryStorageLimits();
-
-    mTemporaryStorageInitialized = true;
   }
 
   bool created;
   rv = EnsureDirectory(directory, &created);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (created) {
     int64_t timestamp = PR_Now();
@@ -2003,16 +1931,32 @@ QuotaManager::ResetOrClearCompleted()
 
 already_AddRefed<mozilla::dom::quota::Client>
 QuotaManager::GetClient(Client::Type aClientType)
 {
   nsRefPtr<Client> client = mClients.SafeElementAt(aClientType);
   return client.forget();
 }
 
+uint64_t
+QuotaManager::GetGroupLimit() const
+{
+  MOZ_ASSERT(mTemporaryStorageInitialized);
+
+  // To avoid one group evicting all the rest, limit the amount any one group
+  // can use to 20%. To prevent individual sites from using exorbitant amounts
+  // of storage where there is a lot of free space, cap the group limit to 2GB.
+  uint64_t x = std::min<uint64_t>(mTemporaryStorageLimit * .20, 2 GB);
+
+  // In low-storage situations, make an exception (while not exceeding the total
+  // storage limit).
+  return std::min<uint64_t>(mTemporaryStorageLimit,
+                            std::max<uint64_t>(x, 10 MB));
+}
+
 // static
 uint32_t
 QuotaManager::GetStorageQuotaMB()
 {
   return uint32_t(std::max(gStorageQuotaMB, 0));
 }
 
 // static
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -274,20 +274,17 @@ public:
     }
 
     NS_ASSERTION(aPersistenceType == PERSISTENCE_TYPE_TEMPORARY, "Huh?");
 
     return mTemporaryStoragePath;
   }
 
   uint64_t
-  GetGroupLimit() const
-  {
-    return mTemporaryStorageLimit / 5;
-  }
+  GetGroupLimit() const;
 
   static uint32_t
   GetStorageQuotaMB();
 
   static void
   GetStorageId(PersistenceType aPersistenceType,
                const nsACString& aOrigin,
                Client::Type aClientType,