Index: storage/browser/quota/quota_manager.cc |
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc |
index 44ba5f1019d3833427b24a81568fddd3afe5ac0b..09f7ceab913532fe5a27ec57ecd17fe93f46daea 100644 |
--- a/storage/browser/quota/quota_manager.cc |
+++ b/storage/browser/quota/quota_manager.cc |
@@ -13,6 +13,7 @@ |
#include <memory> |
#include <utility> |
+#include "base/barrier_closure.h" |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
#include "base/command_line.h" |
@@ -26,6 +27,7 @@ |
#include "base/strings/string_number_conversions.h" |
#include "base/sys_info.h" |
#include "base/task_runner_util.h" |
+#include "base/threading/thread_task_runner_handle.h" |
#include "base/time/time.h" |
#include "base/trace_event/trace_event.h" |
#include "net/base/url_util.h" |
@@ -47,38 +49,26 @@ namespace { |
const int64_t kMBytes = 1024 * 1024; |
const int kMinutesInMilliSeconds = 60 * 1000; |
- |
const int64_t kReportHistogramInterval = 60 * 60 * 1000; // 1 hour |
-const double kTemporaryQuotaRatioToAvail = 1.0 / 3.0; // 33% |
} // namespace |
-// Arbitrary for now, but must be reasonably small so that |
-// in-memory databases can fit. |
-// TODO(kinuko): Refer SysInfo::AmountOfPhysicalMemory() to determine this. |
-const int64_t QuotaManager::kIncognitoDefaultQuotaLimit = 100 * kMBytes; |
- |
const int64_t QuotaManager::kNoLimit = INT64_MAX; |
-const int QuotaManager::kPerHostTemporaryPortion = 5; // 20% |
- |
// Cap size for per-host persistent quota determined by the histogram. |
// This is a bit lax value because the histogram says nothing about per-host |
// persistent storage usage and we determined by global persistent storage |
// usage that is less than 10GB for almost all users. |
const int64_t QuotaManager::kPerHostPersistentQuotaLimit = 10 * 1024 * kMBytes; |
+// Heuristics: assuming average cloud server allows a few Gigs storage |
+// on the server side and the storage needs to be shared for user data |
+// and by multiple apps. |
+int64_t QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes; |
+ |
const char QuotaManager::kDatabaseName[] = "QuotaManager"; |
const int QuotaManager::kThresholdOfErrorsToBeBlacklisted = 3; |
- |
-// Preserve kMinimumPreserveForSystem disk space for system book-keeping |
-// when returning the quota to unlimited apps/extensions. |
-// TODO(kinuko): This should be like 10% of the actual disk space. |
-// For now we simply use a constant as getting the disk size needs |
-// platform-dependent code. (http://crbug.com/178976) |
-int64_t QuotaManager::kMinimumPreserveForSystem = 1024 * kMBytes; |
- |
const int QuotaManager::kEvictionIntervalInMilliSeconds = |
30 * kMinutesInMilliSeconds; |
@@ -89,11 +79,6 @@ const char QuotaManager::kEvictedOriginAccessedCountHistogram[] = |
const char QuotaManager::kEvictedOriginTimeSinceAccessHistogram[] = |
"Quota.EvictedOriginTimeSinceAccess"; |
-// Heuristics: assuming average cloud server allows a few Gigs storage |
-// on the server side and the storage needs to be shared for user data |
-// and by multiple apps. |
-int64_t QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes; |
- |
namespace { |
void CountOriginType(const std::set<GURL>& origins, |
@@ -234,277 +219,230 @@ bool UpdateModifiedTimeOnDBThread(const GURL& origin, |
return database->SetOriginLastModifiedTime(origin, type, modified_time); |
} |
-int64_t CalculateTemporaryGlobalQuota(int64_t global_limited_usage, |
- int64_t available_space) { |
- DCHECK_GE(global_limited_usage, 0); |
- int64_t avail_space = available_space; |
- if (avail_space < |
- std::numeric_limits<int64_t>::max() - global_limited_usage) { |
- // We basically calculate the temporary quota by |
- // [available_space + space_used_for_temp] * kTempQuotaRatio, |
- // but make sure we'll have no overflow. |
- avail_space += global_limited_usage; |
- } |
- int64_t pool_size = avail_space * kTemporaryQuotaRatioToAvail; |
- UMA_HISTOGRAM_MBYTES("Quota.GlobalTemporaryPoolSize", pool_size); |
- return pool_size; |
-} |
- |
-void DispatchTemporaryGlobalQuotaCallback( |
- const QuotaCallback& callback, |
- QuotaStatusCode status, |
- const UsageAndQuota& usage_and_quota) { |
- if (status != kQuotaStatusOk) { |
- callback.Run(status, 0); |
- return; |
- } |
- |
- callback.Run(status, CalculateTemporaryGlobalQuota( |
- usage_and_quota.global_limited_usage, |
- usage_and_quota.available_disk_space)); |
-} |
- |
-int64_t CalculateQuotaWithDiskSpace(int64_t available_disk_space, |
- int64_t usage, |
- int64_t quota) { |
- if (available_disk_space < QuotaManager::kMinimumPreserveForSystem) { |
- LOG(WARNING) |
- << "Running out of disk space for profile." |
- << " QuotaManager starts forbidding further quota consumption."; |
- return usage; |
- } |
- |
- if (quota < usage) { |
- // No more space; cap the quota to the current usage. |
- return usage; |
- } |
- |
- available_disk_space -= QuotaManager::kMinimumPreserveForSystem; |
- if (available_disk_space < quota - usage) |
- return available_disk_space + usage; |
- |
- return quota; |
-} |
- |
-int64_t CalculateTemporaryHostQuota(int64_t host_usage, |
- int64_t global_quota, |
- int64_t global_limited_usage) { |
- DCHECK_GE(global_limited_usage, 0); |
- int64_t host_quota = global_quota / QuotaManager::kPerHostTemporaryPortion; |
- if (global_limited_usage > global_quota) |
- host_quota = std::min(host_quota, host_usage); |
- return host_quota; |
-} |
- |
-void DispatchUsageAndQuotaForWebApps( |
- StorageType type, |
- bool is_incognito, |
- bool is_unlimited, |
- bool can_query_disk_size, |
- const QuotaManager::GetUsageAndQuotaCallback& callback, |
- QuotaStatusCode status, |
- const UsageAndQuota& usage_and_quota) { |
- if (status != kQuotaStatusOk) { |
- callback.Run(status, 0, 0); |
- return; |
- } |
- |
- int64_t usage = usage_and_quota.usage; |
- int64_t quota = usage_and_quota.quota; |
- |
- if (type == kStorageTypeTemporary && !is_unlimited) { |
- quota = CalculateTemporaryHostQuota( |
- usage, quota, usage_and_quota.global_limited_usage); |
- } |
- |
- if (is_incognito) { |
- quota = std::min(quota, QuotaManager::kIncognitoDefaultQuotaLimit); |
- callback.Run(status, usage, quota); |
- return; |
- } |
- |
- // For apps with unlimited permission or can_query_disk_size is true (and not |
- // in incognito mode). |
- // We assume we can expose the actual disk size for them and cap the quota by |
- // the available disk space. |
- if (is_unlimited || can_query_disk_size) { |
- quota = CalculateQuotaWithDiskSpace( |
- usage_and_quota.available_disk_space, |
- usage, quota); |
- } |
- |
- callback.Run(status, usage, quota); |
- |
- if (type == kStorageTypeTemporary && !is_unlimited) |
- UMA_HISTOGRAM_MBYTES("Quota.QuotaForOrigin", quota); |
-} |
- |
} // namespace |
-UsageAndQuota::UsageAndQuota() |
- : usage(0), |
- global_limited_usage(0), |
- quota(0), |
- available_disk_space(0) { |
-} |
- |
-UsageAndQuota::UsageAndQuota(int64_t usage, |
- int64_t global_limited_usage, |
- int64_t quota, |
- int64_t available_disk_space) |
- : usage(usage), |
- global_limited_usage(global_limited_usage), |
- quota(quota), |
- available_disk_space(available_disk_space) {} |
- |
-class UsageAndQuotaCallbackDispatcher |
- : public QuotaTask, |
- public base::SupportsWeakPtr<UsageAndQuotaCallbackDispatcher> { |
+class QuotaManager::UsageAndQuotaHelper : public QuotaTask { |
public: |
- explicit UsageAndQuotaCallbackDispatcher(QuotaManager* manager) |
+ UsageAndQuotaHelper( |
+ QuotaManager* manager, |
+ const GURL& origin, |
+ StorageType type, |
+ bool is_unlimited, |
+ bool is_incognito, |
+ const UsageAndQuotaCallback& callback) |
: QuotaTask(manager), |
- has_usage_(false), |
- has_global_limited_usage_(false), |
- has_quota_(false), |
- has_available_disk_space_(false), |
- status_(kQuotaStatusUnknown), |
- usage_and_quota_(-1, -1, -1, -1), |
- waiting_callbacks_(1) {} |
- |
- ~UsageAndQuotaCallbackDispatcher() override {} |
- |
- void WaitForResults(const QuotaManager::UsageAndQuotaCallback& callback) { |
- callback_ = callback; |
- Start(); |
- } |
- |
- void set_usage(int64_t usage) { |
- usage_and_quota_.usage = usage; |
- has_usage_ = true; |
- } |
- |
- void set_global_limited_usage(int64_t global_limited_usage) { |
- usage_and_quota_.global_limited_usage = global_limited_usage; |
- has_global_limited_usage_ = true; |
- } |
+ origin_(origin), |
+ type_(type), |
+ is_unlimited_(is_unlimited), |
+ is_incognito_(is_incognito), |
+ callback_(callback), |
+ weak_factory_(this) {} |
- void set_quota(int64_t quota) { |
- usage_and_quota_.quota = quota; |
- has_quota_ = true; |
+ protected: |
+ // Start the async process of gathering the info we need. |
+ void Run() override { |
+ // Gather 4 pieces of info before computing an answer: |
+ // config, device_storage_capacity, host_usage, and host_quota. |
+ base::Closure barrier = base::BarrierClosure(4, |
+ base::Bind(&UsageAndQuotaHelper::OnBarrierComplete, |
+ weak_factory_.GetWeakPtr())); |
+ |
+ std::string host = net::GetHostOrSpecFromURL(origin_); |
+ |
+ manager()->GetTemporaryStorageConfig( |
+ base::Bind(&UsageAndQuotaHelper::OnGotConfigInfo, |
+ weak_factory_.GetWeakPtr(), barrier)); |
+ manager()->GetDeviceStorageCapacity( |
+ base::Bind(&UsageAndQuotaHelper::OnGotCapacity, |
+ weak_factory_.GetWeakPtr(), barrier)); |
+ manager()->GetHostUsage( |
+ host, type_, |
+ base::Bind(&UsageAndQuotaHelper::OnGotHostUsage, |
+ weak_factory_.GetWeakPtr(), barrier)); |
+ |
+ // Determine host_quota differently depending on type. |
+ if (is_unlimited_) { |
+ SetDesiredHostQuota(barrier, kQuotaStatusOk, |
+ kNoLimit); |
+ } else if (type_ == kStorageTypeSyncable) { |
+ SetDesiredHostQuota(barrier, kQuotaStatusOk, |
+ kSyncableStorageDefaultHostQuota); |
+ } else if (type_ == kStorageTypePersistent) { |
+ manager()->GetPersistentHostQuota( |
+ host, |
+ base::Bind(&UsageAndQuotaHelper::SetDesiredHostQuota, |
+ weak_factory_.GetWeakPtr(), barrier)); |
+ } else { |
+ DCHECK_EQ(kStorageTypeTemporary, type_); |
+ // For temporary storge, OnGetConfig will set the host quota. |
+ } |
} |
- void set_available_disk_space(int64_t available_disk_space) { |
- usage_and_quota_.available_disk_space = available_disk_space; |
- has_available_disk_space_ = true; |
+ void Aborted() override { |
+ weak_factory_.InvalidateWeakPtrs(); |
+ callback_.Run(kQuotaErrorAbort, 0, 0); |
+ DeleteSoon(); |
} |
- UsageCallback GetHostUsageCallback() { |
- ++waiting_callbacks_; |
- has_usage_ = true; |
- return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetHostUsage, |
- AsWeakPtr()); |
+ void Completed() override { |
+ weak_factory_.InvalidateWeakPtrs(); |
+ // Constrain the desired |host_quota| to something that fits. |
+ // If available space is too low, cap usage at current levels. |
+ // If it's close to being too low, cap growth to avoid it getting too low. |
+ int64_t host_quota = std::min( |
+ desired_host_quota_, |
+ host_usage_ + |
+ std::max(INT64_C(0), |
+ available_space_ - config_.must_remain_available)); |
+ callback_.Run(kQuotaStatusOk, host_usage_, host_quota); |
+ if (type_ == kStorageTypeTemporary && !is_incognito_ && !is_unlimited_) |
+ UMA_HISTOGRAM_MBYTES("Quota.QuotaForOrigin", host_quota); |
+ DeleteSoon(); |
} |
- UsageCallback GetGlobalLimitedUsageCallback() { |
- ++waiting_callbacks_; |
- has_global_limited_usage_ = true; |
- return base::Bind( |
- &UsageAndQuotaCallbackDispatcher::DidGetGlobalLimitedUsage, |
- AsWeakPtr()); |
+ private: |
+ QuotaManager* manager() const { |
+ return static_cast<QuotaManager*>(observer()); |
} |
- QuotaCallback GetQuotaCallback() { |
- ++waiting_callbacks_; |
- has_quota_ = true; |
- return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetQuota, |
- AsWeakPtr()); |
+ void OnGotConfigInfo(const base::Closure& barrier_closure, |
+ const TemporaryStorageConfiguration& config) { |
+ config_ = config; |
+ barrier_closure.Run(); |
+ if (type_ == kStorageTypeTemporary && !is_unlimited_) { |
+ SetDesiredHostQuota(barrier_closure, kQuotaStatusOk, |
+ config.per_host_quota); |
+ } |
} |
- QuotaCallback GetAvailableSpaceCallback() { |
- ++waiting_callbacks_; |
- has_available_disk_space_ = true; |
- return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace, |
- AsWeakPtr()); |
+ void OnGotCapacity(const base::Closure& barrier_closure, |
+ int64_t total_space, int64_t available_space) { |
+ total_space_ = total_space; |
+ available_space_ = available_space; |
+ barrier_closure.Run(); |
} |
- private: |
- void DidGetHostUsage(int64_t usage) { |
- if (status_ == kQuotaStatusUnknown) |
- status_ = kQuotaStatusOk; |
- usage_and_quota_.usage = usage; |
- CheckCompleted(); |
+ void OnGotHostUsage(const base::Closure& barrier_closure, int64_t usage) { |
+ host_usage_ = usage; |
+ barrier_closure.Run(); |
} |
- void DidGetGlobalLimitedUsage(int64_t limited_usage) { |
- if (status_ == kQuotaStatusUnknown) |
- status_ = kQuotaStatusOk; |
- usage_and_quota_.global_limited_usage = limited_usage; |
- CheckCompleted(); |
+ void SetDesiredHostQuota(const base::Closure& barrier_closure, |
+ QuotaStatusCode status, int64_t quota) { |
+ desired_host_quota_ = quota; |
+ barrier_closure.Run(); |
} |
- void DidGetQuota(QuotaStatusCode status, int64_t quota) { |
- if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk) |
- status_ = status; |
- usage_and_quota_.quota = quota; |
- CheckCompleted(); |
+ void OnBarrierComplete() { |
+ CallCompleted(); |
} |
- void DidGetAvailableSpace(QuotaStatusCode status, int64_t space) { |
- // crbug.com/349708 |
- TRACE_EVENT0( |
- "io", "UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace"); |
+ GURL origin_; |
+ QuotaManager::UsageAndQuotaCallback callback_; |
+ StorageType type_; |
+ bool is_unlimited_; |
+ bool is_incognito_; |
+ int64_t available_space_ = 0; |
+ int64_t total_space_ = 0; |
+ int64_t desired_host_quota_ = 0; |
+ int64_t host_usage_ = 0; |
+ TemporaryStorageConfiguration config_; |
+ base::WeakPtrFactory<UsageAndQuotaHelper> weak_factory_; |
+ DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaHelper); |
+}; |
- DCHECK_GE(space, 0); |
- if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk) |
- status_ = status; |
- usage_and_quota_.available_disk_space = space; |
- CheckCompleted(); |
- } |
+// Helper to asychronously gather information needed at the start of an |
+// eviction round. |
+class QuotaManager::EvictionRoundInfoHelper : public QuotaTask { |
+ public: |
+ EvictionRoundInfoHelper( |
+ QuotaManager* manager, |
+ const EvictionRoundInfoCallback& callback) |
+ : QuotaTask(manager), |
+ callback_(callback), |
+ weak_factory_(this) {} |
+ protected: |
void Run() override { |
- // We initialize waiting_callbacks to 1 so that we won't run |
- // the completion callback until here even some of the callbacks |
- // are dispatched synchronously. |
- CheckCompleted(); |
+ // Gather 2 pieces of info before deciding if we need to get GlobalUsage: |
+ // config, device_storage_capacity. |
+ base::Closure barrier = base::BarrierClosure(2, |
+ base::Bind(&EvictionRoundInfoHelper::OnBarrierComplete, |
+ weak_factory_.GetWeakPtr())); |
+ |
+ manager()->GetTemporaryStorageConfig( |
+ base::Bind(&EvictionRoundInfoHelper::OnGotConfigInfo, |
+ weak_factory_.GetWeakPtr(), barrier)); |
+ manager()->GetDeviceStorageCapacity( |
+ base::Bind(&EvictionRoundInfoHelper::OnGotCapacity, |
+ weak_factory_.GetWeakPtr(), barrier)); |
} |
void Aborted() override { |
- callback_.Run(kQuotaErrorAbort, UsageAndQuota()); |
+ weak_factory_.InvalidateWeakPtrs(); |
+ callback_.Run( |
+ kQuotaErrorAbort, TemporaryStorageConfiguration(), 0, 0, 0, false); |
DeleteSoon(); |
} |
void Completed() override { |
- // crbug.com/349708 |
- TRACE_EVENT0("io", "UsageAndQuotaCallbackDispatcher::Completed"); |
- |
- DCHECK(!has_usage_ || usage_and_quota_.usage >= 0); |
- DCHECK(!has_global_limited_usage_ || |
- usage_and_quota_.global_limited_usage >= 0); |
- DCHECK(!has_quota_ || usage_and_quota_.quota >= 0); |
- DCHECK(!has_available_disk_space_ || |
- usage_and_quota_.available_disk_space >= 0); |
- |
- callback_.Run(status_, usage_and_quota_); |
+ weak_factory_.InvalidateWeakPtrs(); |
+ callback_.Run( |
+ kQuotaStatusOk, config_, available_space_, total_space_, |
+ global_usage_, global_usage_is_complete_); |
DeleteSoon(); |
} |
- void CheckCompleted() { |
- if (--waiting_callbacks_ <= 0) |
- CallCompleted(); |
+ private: |
+ QuotaManager* manager() const { |
+ return static_cast<QuotaManager*>(observer()); |
} |
- // For sanity checks, they're checked only when DCHECK is on. |
- bool has_usage_; |
- bool has_global_limited_usage_; |
- bool has_quota_; |
- bool has_available_disk_space_; |
+ void OnGotConfigInfo(const base::Closure& barrier_closure, |
+ const TemporaryStorageConfiguration& config) { |
+ config_ = config; |
+ barrier_closure.Run(); |
+ } |
- QuotaStatusCode status_; |
- UsageAndQuota usage_and_quota_; |
- QuotaManager::UsageAndQuotaCallback callback_; |
- int waiting_callbacks_; |
+ void OnGotCapacity(const base::Closure& barrier_closure, |
+ int64_t total_space, int64_t available_space) { |
+ total_space_ = total_space; |
+ available_space_ = available_space; |
+ barrier_closure.Run(); |
+ } |
- DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaCallbackDispatcher); |
+ void OnBarrierComplete() { |
+ // Avoid computing the full current_usage when there's no pressure. |
+ int64_t consumed_space = total_space_ - available_space_; |
+ if (consumed_space < config_.pool_size && |
+ available_space_ > config_.must_remain_available) { |
+ DCHECK(!global_usage_is_complete_); |
+ global_usage_ = |
+ manager()->GetUsageTracker(kStorageTypeTemporary)->GetCachedUsage(); |
+ CallCompleted(); |
+ return; |
+ } |
+ manager()->GetGlobalUsage( |
+ kStorageTypeTemporary, |
+ base::Bind( |
+ &EvictionRoundInfoHelper::OnGotGlobalUsage, |
+ weak_factory_.GetWeakPtr())); |
+ } |
+ |
+ void OnGotGlobalUsage(int64_t usage, int64_t unlimited_usage) { |
+ global_usage_ = std::max(INT64_C(0), usage - unlimited_usage); |
+ global_usage_is_complete_ = true; |
+ CallCompleted(); |
+ } |
+ |
+ EvictionRoundInfoCallback callback_; |
+ TemporaryStorageConfiguration config_; |
+ int64_t available_space_ = 0; |
+ int64_t total_space_ = 0; |
+ int64_t global_usage_ = 0; |
+ bool global_usage_is_complete_ = false; |
+ base::WeakPtrFactory<EvictionRoundInfoHelper> weak_factory_; |
+ DISALLOW_COPY_AND_ASSIGN(EvictionRoundInfoHelper); |
}; |
class QuotaManager::GetUsageInfoTask : public QuotaTask { |
@@ -866,21 +804,35 @@ QuotaManager::QuotaManager( |
const base::FilePath& profile_path, |
const scoped_refptr<base::SingleThreadTaskRunner>& io_thread, |
const scoped_refptr<base::SequencedTaskRunner>& db_thread, |
- const scoped_refptr<SpecialStoragePolicy>& special_storage_policy) |
+ const scoped_refptr<SpecialStoragePolicy>& special_storage_policy, |
+ const GetTemporaryStorageConfigurationFunc& get_config_function) |
: is_incognito_(is_incognito), |
profile_path_(profile_path), |
proxy_(new QuotaManagerProxy(this, io_thread)), |
db_disabled_(false), |
eviction_disabled_(false), |
+ get_config_function_(get_config_function), |
io_thread_(io_thread), |
db_thread_(db_thread), |
is_getting_eviction_origin_(false), |
- temporary_quota_initialized_(false), |
- temporary_quota_override_(-1), |
special_storage_policy_(special_storage_policy), |
get_volume_info_fn_(&QuotaManager::GetVolumeInfo), |
storage_monitor_(new StorageMonitor(this)), |
- weak_factory_(this) {} |
+ weak_factory_(this) { |
+ DCHECK_EQ(storage_config_.refresh_interval, base::TimeDelta::Max()); |
+ if (!get_config_function.is_null()) { |
+ // Reset the interval to ensure we use the get_config_function |
+ // the first times storage_config_ is needed. |
+ storage_config_.refresh_interval = base::TimeDelta(); |
+ get_config_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
+ } |
+} |
+ |
+void QuotaManager::SetTemporaryStorageConfiguration( |
+ const TemporaryStorageConfiguration& config) { |
+ storage_config_ = config; |
+ storage_config_timestamp_ = base::TimeTicks::Now(); |
+} |
void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) { |
LazyInitialize(); |
@@ -891,61 +843,32 @@ void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) { |
void QuotaManager::GetUsageAndQuotaForWebApps( |
const GURL& origin, |
StorageType type, |
- const GetUsageAndQuotaCallback& callback) { |
- // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed. |
- tracked_objects::ScopedTracker tracking_profile( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "477117 QuotaManager::GetUsageAndQuotaForWebApps")); |
+ const UsageAndQuotaCallback& callback) { |
+ DCHECK(origin == origin.GetOrigin()); |
if (type != kStorageTypeTemporary && |
type != kStorageTypePersistent && |
type != kStorageTypeSyncable) { |
callback.Run(kQuotaErrorNotSupported, 0, 0); |
return; |
} |
- |
- DCHECK(origin == origin.GetOrigin()); |
- LazyInitialize(); |
- |
- bool unlimited = IsStorageUnlimited(origin, type); |
- bool can_query_disk_size = CanQueryDiskSize(origin); |
- |
- UsageAndQuotaCallbackDispatcher* dispatcher = |
- new UsageAndQuotaCallbackDispatcher(this); |
- |
- if (unlimited) { |
- dispatcher->set_quota(kNoLimit); |
- } else { |
- if (type == kStorageTypeTemporary) { |
- GetUsageTracker(type)->GetGlobalLimitedUsage( |
- dispatcher->GetGlobalLimitedUsageCallback()); |
- GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback()); |
- } else if (type == kStorageTypePersistent) { |
- GetPersistentHostQuota(net::GetHostOrSpecFromURL(origin), |
- dispatcher->GetQuotaCallback()); |
- } else { |
- dispatcher->set_quota(kSyncableStorageDefaultHostQuota); |
- } |
+ if (is_incognito_ && type != kStorageTypeTemporary) { |
+ callback.Run(kQuotaErrorNotSupported, 0, 0); |
+ return; |
} |
- |
- DCHECK(GetUsageTracker(type)); |
- GetUsageTracker(type)->GetHostUsage(net::GetHostOrSpecFromURL(origin), |
- dispatcher->GetHostUsageCallback()); |
- |
- if (!is_incognito_ && (unlimited || can_query_disk_size)) |
- GetAvailableSpace(dispatcher->GetAvailableSpaceCallback()); |
- |
- dispatcher->WaitForResults(base::Bind( |
- &DispatchUsageAndQuotaForWebApps, |
- type, is_incognito_, unlimited, can_query_disk_size, |
- callback)); |
+ LazyInitialize(); |
+ UsageAndQuotaHelper* helper = new UsageAndQuotaHelper( |
+ this, origin, type, IsStorageUnlimited(origin, type), |
+ is_incognito_, callback); |
+ helper->Start(); |
} |
void QuotaManager::GetUsageAndQuota( |
const GURL& origin, StorageType type, |
- const GetUsageAndQuotaCallback& callback) { |
+ const UsageAndQuotaCallback& callback) { |
DCHECK(origin == origin.GetOrigin()); |
if (IsStorageUnlimited(origin, type)) { |
+ // TODO: This seems like a non-obvious odd behavior. |
callback.Run(kQuotaStatusOk, 0, kNoLimit); |
return; |
} |
@@ -1019,72 +942,6 @@ void QuotaManager::DeleteHostData(const std::string& host, |
deleter->Start(); |
} |
-void QuotaManager::GetAvailableSpace(const AvailableSpaceCallback& callback) { |
- if (!available_space_callbacks_.Add(callback)) |
- return; |
- // crbug.com/349708 |
- TRACE_EVENT0("io", "QuotaManager::GetAvailableSpace"); |
- |
- PostTaskAndReplyWithResult( |
- db_thread_.get(), |
- FROM_HERE, |
- base::Bind(&QuotaManager::CallGetAmountOfFreeDiskSpace, |
- get_volume_info_fn_, profile_path_), |
- base::Bind(&QuotaManager::DidGetAvailableSpace, |
- weak_factory_.GetWeakPtr())); |
-} |
- |
-void QuotaManager::GetTemporaryGlobalQuota(const QuotaCallback& callback) { |
- LazyInitialize(); |
- if (!temporary_quota_initialized_) { |
- db_initialization_callbacks_.Add(base::Bind( |
- &QuotaManager::GetTemporaryGlobalQuota, |
- weak_factory_.GetWeakPtr(), callback)); |
- return; |
- } |
- |
- if (temporary_quota_override_ > 0) { |
- callback.Run(kQuotaStatusOk, temporary_quota_override_); |
- return; |
- } |
- |
- UsageAndQuotaCallbackDispatcher* dispatcher = |
- new UsageAndQuotaCallbackDispatcher(this); |
- GetUsageTracker(kStorageTypeTemporary)-> |
- GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback()); |
- GetAvailableSpace(dispatcher->GetAvailableSpaceCallback()); |
- dispatcher->WaitForResults( |
- base::Bind(&DispatchTemporaryGlobalQuotaCallback, callback)); |
-} |
- |
-void QuotaManager::SetTemporaryGlobalOverrideQuota( |
- int64_t new_quota, |
- const QuotaCallback& callback) { |
- LazyInitialize(); |
- |
- if (new_quota < 0) { |
- if (!callback.is_null()) |
- callback.Run(kQuotaErrorInvalidModification, -1); |
- return; |
- } |
- |
- if (db_disabled_) { |
- if (!callback.is_null()) |
- callback.Run(kQuotaErrorInvalidAccess, -1); |
- return; |
- } |
- |
- int64_t* new_quota_ptr = new int64_t(new_quota); |
- PostTaskAndReplyWithResultForDBThread( |
- FROM_HERE, |
- base::Bind(&SetTemporaryGlobalOverrideQuotaOnDBThread, |
- base::Unretained(new_quota_ptr)), |
- base::Bind(&QuotaManager::DidSetTemporaryGlobalOverrideQuota, |
- weak_factory_.GetWeakPtr(), |
- callback, |
- base::Owned(new_quota_ptr))); |
-} |
- |
void QuotaManager::GetPersistentHostQuota(const std::string& host, |
const QuotaCallback& callback) { |
LazyInitialize(); |
@@ -1126,10 +983,8 @@ void QuotaManager::SetPersistentHostQuota(const std::string& host, |
return; |
} |
- if (kPerHostPersistentQuotaLimit < new_quota) { |
- // Cap the requested size at the per-host quota limit. |
- new_quota = kPerHostPersistentQuotaLimit; |
- } |
+ // Cap the requested size at the per-host quota limit. |
+ new_quota = std::min(new_quota, kPerHostPersistentQuotaLimit); |
if (db_disabled_) { |
callback.Run(kQuotaErrorInvalidAccess, -1); |
@@ -1185,7 +1040,7 @@ bool QuotaManager::IsTrackingHostUsage(StorageType type, |
return tracker && tracker->GetClientTracker(client_id); |
} |
-void QuotaManager::GetStatistics( |
+void QuotaManager::GetStatistics( // GetEvictionStatistics |
std::map<std::string, std::string>* statistics) { |
DCHECK(statistics); |
if (temporary_storage_evictor_) { |
@@ -1289,7 +1144,7 @@ QuotaManager::EvictionContext::~EvictionContext() { |
void QuotaManager::LazyInitialize() { |
DCHECK(io_thread_->BelongsToCurrentThread()); |
if (database_) { |
- // Initialization seems to be done already. |
+ // Already initialized. |
return; |
} |
@@ -1307,17 +1162,24 @@ void QuotaManager::LazyInitialize() { |
clients_, kStorageTypeSyncable, special_storage_policy_.get(), |
storage_monitor_.get())); |
- int64_t* temporary_quota_override = new int64_t(-1); |
- int64_t* desired_available_space = new int64_t(-1); |
- PostTaskAndReplyWithResultForDBThread( |
- FROM_HERE, |
- base::Bind(&InitializeOnDBThread, |
- base::Unretained(temporary_quota_override), |
- base::Unretained(desired_available_space)), |
- base::Bind(&QuotaManager::DidInitialize, |
- weak_factory_.GetWeakPtr(), |
- base::Owned(temporary_quota_override), |
- base::Owned(desired_available_space))); |
+ if (!is_incognito_) { |
+ histogram_timer_.Start( |
+ FROM_HERE, |
+ base::TimeDelta::FromMilliseconds(kReportHistogramInterval), |
+ this, &QuotaManager::ReportHistogram); |
+ } |
+ |
+ //// TODO??? |
+ //std::set<GURL>* origins = new std::set<GURL>; |
+ //temporary_usage_tracker_->GetCachedOrigins(origins); |
+ //// This will call the StartEviction() when initial origin registration |
+ //// is completed. |
+ //PostTaskAndReplyWithResultForDBThread( |
+ // FROM_HERE, |
+ // base::Bind(&InitializeTemporaryOriginsInfoOnDBThread, |
+ // base::Owned(origins)), |
+ // base::Bind(&QuotaManager::DidInitializeTemporaryOriginsInfo, |
+ // weak_factory_.GetWeakPtr())); |
} |
void QuotaManager::RegisterClient(QuotaClient* client) { |
@@ -1414,9 +1276,6 @@ void QuotaManager::StartEviction() { |
DCHECK(!temporary_storage_evictor_.get()); |
temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor( |
this, kEvictionIntervalInMilliSeconds)); |
- if (desired_available_space_ >= 0) |
- temporary_storage_evictor_->set_min_available_disk_space_to_start_eviction( |
- desired_available_space_); |
temporary_storage_evictor_->Start(); |
} |
@@ -1621,7 +1480,7 @@ void QuotaManager::GetEvictionOrigin(StorageType type, |
void QuotaManager::EvictOriginData(const GURL& origin, |
StorageType type, |
- const EvictOriginDataCallback& callback) { |
+ const StatusCallback& callback) { |
DCHECK(io_thread_->BelongsToCurrentThread()); |
DCHECK_EQ(type, kStorageTypeTemporary); |
@@ -1634,47 +1493,13 @@ void QuotaManager::EvictOriginData(const GURL& origin, |
weak_factory_.GetWeakPtr())); |
} |
-void QuotaManager::GetUsageAndQuotaForEviction( |
- const UsageAndQuotaCallback& callback) { |
- // crbug.com/349708 |
- TRACE_EVENT0("io", "QuotaManager::GetUsageAndQuotaForEviction"); |
- |
+void QuotaManager::GetEvictionRoundInfo( |
+ const EvictionRoundInfoCallback& callback) { |
DCHECK(io_thread_->BelongsToCurrentThread()); |
LazyInitialize(); |
- |
- UsageAndQuotaCallbackDispatcher* dispatcher = |
- new UsageAndQuotaCallbackDispatcher(this); |
- GetUsageTracker(kStorageTypeTemporary) |
- ->GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback()); |
- GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback()); |
- GetAvailableSpace(dispatcher->GetAvailableSpaceCallback()); |
- dispatcher->WaitForResults(callback); |
-} |
- |
-void QuotaManager::AsyncGetVolumeInfo( |
- const VolumeInfoCallback& callback) { |
- DCHECK(io_thread_->BelongsToCurrentThread()); |
- uint64_t* available_space = new uint64_t(0); |
- uint64_t* total_space = new uint64_t(0); |
- PostTaskAndReplyWithResult( |
- db_thread_.get(), |
- FROM_HERE, |
- base::Bind(get_volume_info_fn_, |
- profile_path_, |
- base::Unretained(available_space), |
- base::Unretained(total_space)), |
- base::Bind(&QuotaManager::DidGetVolumeInfo, |
- weak_factory_.GetWeakPtr(), |
- callback, |
- base::Owned(available_space), |
- base::Owned(total_space))); |
-} |
- |
-void QuotaManager::DidGetVolumeInfo( |
- const VolumeInfoCallback& callback, |
- uint64_t* available_space, uint64_t* total_space, bool success) { |
- DCHECK(io_thread_->BelongsToCurrentThread()); |
- callback.Run(success, *available_space, *total_space); |
+ EvictionRoundInfoHelper* helper = |
+ new EvictionRoundInfoHelper(this, callback); |
+ helper->Start(); |
} |
void QuotaManager::GetLRUOrigin(StorageType type, |
@@ -1699,28 +1524,13 @@ void QuotaManager::GetLRUOrigin(StorageType type, |
base::Owned(url))); |
} |
-void QuotaManager::DidSetTemporaryGlobalOverrideQuota( |
- const QuotaCallback& callback, |
- const int64_t* new_quota, |
- bool success) { |
- QuotaStatusCode status = kQuotaErrorInvalidAccess; |
- DidDatabaseWork(success); |
- if (success) { |
- temporary_quota_override_ = *new_quota; |
- status = kQuotaStatusOk; |
- } |
- |
- if (callback.is_null()) |
- return; |
- |
- callback.Run(status, *new_quota); |
-} |
- |
void QuotaManager::DidGetPersistentHostQuota(const std::string& host, |
const int64_t* quota, |
bool success) { |
DidDatabaseWork(success); |
- persistent_host_quota_callbacks_.Run(host, kQuotaStatusOk, *quota); |
+ persistent_host_quota_callbacks_.Run( |
+ host, kQuotaStatusOk, |
+ std::min(*quota, kPerHostPersistentQuotaLimit)); |
} |
void QuotaManager::DidSetPersistentHostQuota(const std::string& host, |
@@ -1731,27 +1541,6 @@ void QuotaManager::DidSetPersistentHostQuota(const std::string& host, |
callback.Run(success ? kQuotaStatusOk : kQuotaErrorInvalidAccess, *new_quota); |
} |
-void QuotaManager::DidInitialize(int64_t* temporary_quota_override, |
- int64_t* desired_available_space, |
- bool success) { |
- temporary_quota_override_ = *temporary_quota_override; |
- desired_available_space_ = *desired_available_space; |
- temporary_quota_initialized_ = true; |
- DidDatabaseWork(success); |
- |
- if (!is_incognito_) { |
- histogram_timer_.Start(FROM_HERE, |
- base::TimeDelta::FromMilliseconds( |
- kReportHistogramInterval), |
- this, &QuotaManager::ReportHistogram); |
- } |
- |
- db_initialization_callbacks_.Run(); |
- GetTemporaryGlobalQuota( |
- base::Bind(&QuotaManager::DidGetInitialTemporaryGlobalQuota, |
- weak_factory_.GetWeakPtr(), base::TimeTicks::Now())); |
-} |
- |
void QuotaManager::DidGetLRUOrigin(const GURL* origin, |
bool success) { |
DidDatabaseWork(success); |
@@ -1760,41 +1549,88 @@ void QuotaManager::DidGetLRUOrigin(const GURL* origin, |
lru_origin_callback_.Reset(); |
} |
-void QuotaManager::DidGetInitialTemporaryGlobalQuota( |
- base::TimeTicks start_ticks, |
- QuotaStatusCode status, |
- int64_t quota_unused) { |
- UMA_HISTOGRAM_LONG_TIMES( |
- "Quota.TimeToInitializeGlobalQuota", |
- base::TimeTicks::Now() - start_ticks); |
+void QuotaManager::DidInitializeTemporaryOriginsInfo(bool success) { |
+ DidDatabaseWork(success); |
+ if (success) |
+ StartEviction(); |
+} |
- if (eviction_disabled_) |
+namespace { |
+void DidGetTempStorageConfigThreadAdapter( |
+ base::TaskRunner* task_runner, |
+ const TemporaryStorageConfigurationCallback& callback, |
+ const TemporaryStorageConfiguration& storage_config) { |
+ task_runner->PostTask(FROM_HERE, base::Bind(callback, storage_config)); |
+} |
+} // namespace |
+ |
+void QuotaManager::GetTemporaryStorageConfig( |
+ const TemporaryStorageConfigurationCallback& callback) { |
+ if (base::TimeTicks::Now() - storage_config_timestamp_ < |
+ storage_config_.refresh_interval) { |
+ callback.Run(storage_config_); |
return; |
+ } |
- std::set<GURL>* origins = new std::set<GURL>; |
- temporary_usage_tracker_->GetCachedOrigins(origins); |
- // This will call the StartEviction() when initial origin registration |
- // is completed. |
- PostTaskAndReplyWithResultForDBThread( |
+ if (!storage_config_callbacks_.Add(callback)) |
+ return; |
+ |
+ // We invoke our clients GetTemporaryPoolConfigurationFunc on the |
+ // UI thread and plumb the resulting value back to this thread. |
+ get_config_task_runner_->PostTask( |
FROM_HERE, |
- base::Bind(&InitializeTemporaryOriginsInfoOnDBThread, |
- base::Owned(origins)), |
- base::Bind(&QuotaManager::DidInitializeTemporaryOriginsInfo, |
- weak_factory_.GetWeakPtr())); |
+ base::Bind( |
+ get_config_function_, |
+ profile_path_, is_incognito_, |
+ base::Bind( |
+ &DidGetTempStorageConfigThreadAdapter, |
+ base::RetainedRef(base::ThreadTaskRunnerHandle::Get()), |
+ base::Bind( |
+ &QuotaManager::DidGetTemporaryStorageConfig, |
+ weak_factory_.GetWeakPtr())))); |
+} |
+ |
+void QuotaManager::DidGetTemporaryStorageConfig( |
+ const TemporaryStorageConfiguration& config) { |
+ SetTemporaryStorageConfiguration(config); |
+ storage_config_callbacks_.Run(config); |
+} |
+ |
+void QuotaManager::GetDeviceStorageCapacity( |
+ const StorageCapacityCallback& callback) { |
+ if (!storage_capacity_callbacks_.Add(callback)) |
+ return; |
+ if (is_incognito_) { |
+ GetTemporaryStorageConfig( |
+ base::Bind( |
+ &QuotaManager::ContinueIncognitoGetStorageCapacity, |
+ weak_factory_.GetWeakPtr())); |
+ return; |
+ } |
+ base::PostTaskAndReplyWithResult( |
+ db_thread_.get(), |
+ FROM_HERE, |
+ base::Bind( |
+ &QuotaManager::CallGetVolumeInfo, get_volume_info_fn_, profile_path_), |
+ base::Bind( |
+ &QuotaManager::DidGetDeviceStorageCapacity, |
+ weak_factory_.GetWeakPtr())); |
} |
-void QuotaManager::DidInitializeTemporaryOriginsInfo(bool success) { |
- DidDatabaseWork(success); |
- if (success) |
- StartEviction(); |
+void QuotaManager::ContinueIncognitoGetStorageCapacity( |
+ const TemporaryStorageConfiguration& config) { |
+ int64_t current_usage = |
+ GetUsageTracker(kStorageTypeTemporary)->GetCachedUsage(); |
+ int64_t available_space = std::max( |
+ INT64_C(0), config.pool_size - current_usage); |
+ DidGetDeviceStorageCapacity( |
+ std::make_pair(config.pool_size, available_space)); |
} |
-void QuotaManager::DidGetAvailableSpace(int64_t space) { |
- // crbug.com/349708 |
- TRACE_EVENT1("io", "QuotaManager::DidGetAvailableSpace", |
- "n_callbacks", available_space_callbacks_.size()); |
- |
- available_space_callbacks_.Run(kQuotaStatusOk, space); |
+void QuotaManager::DidGetDeviceStorageCapacity( |
+ const std::pair<int64_t, int64_t>& total_and_available) { |
+ storage_capacity_callbacks_.Run( |
+ total_and_available.first, total_and_available.second); |
} |
void QuotaManager::DidDatabaseWork(bool success) { |
@@ -1824,41 +1660,29 @@ void QuotaManager::PostTaskAndReplyWithResultForDBThread( |
} |
// static |
-int64_t QuotaManager::CallGetAmountOfFreeDiskSpace( |
+std::pair<int64_t, int64_t> QuotaManager::CallGetVolumeInfo( |
GetVolumeInfoFn get_volume_info_fn, |
- const base::FilePath& profile_path) { |
+ const base::FilePath& path) { |
// crbug.com/349708 |
- TRACE_EVENT0("io", "CallSystemGetAmountOfFreeDiskSpace"); |
- if (!base::CreateDirectory(profile_path)) { |
- LOG(WARNING) << "Create directory failed for path" << profile_path.value(); |
- return 0; |
- } |
- uint64_t available, total; |
- if (!get_volume_info_fn(profile_path, &available, &total)) { |
- return 0; |
+ TRACE_EVENT0("io", "CallGetVolumeInfo"); |
+ if (!base::CreateDirectory(path)) { |
+ LOG(WARNING) << "Create directory failed for path" << path.value(); |
+ return std::make_pair<int64_t, int64_t>(0, 0); |
} |
- UMA_HISTOGRAM_MBYTES("Quota.AvailableDiskSpace", available); |
- UMA_HISTOGRAM_MBYTES("Quota.TotalDiskSpace", total); |
- return static_cast<int64_t>(available); |
+ std::pair<int64_t, int64_t> total_and_available = get_volume_info_fn(path); |
+ UMA_HISTOGRAM_MBYTES("Quota.TotalDiskSpace", total_and_available.first); |
+ UMA_HISTOGRAM_MBYTES("Quota.AvailableDiskSpace", total_and_available.second); |
+ return total_and_available; |
} |
-//static |
-bool QuotaManager::GetVolumeInfo(const base::FilePath& path, |
- uint64_t* available_space, |
- uint64_t* total_size) { |
- // Inspired by similar code in the base::SysInfo class. |
- base::ThreadRestrictions::AssertIOAllowed(); |
- |
- int64_t available = base::SysInfo::AmountOfFreeDiskSpace(path); |
- if (available < 0) |
- return false; |
- int64_t total = base::SysInfo::AmountOfTotalDiskSpace(path); |
- if (total < 0) |
- return false; |
- *available_space = static_cast<uint64_t>(available); |
- *total_size = static_cast<uint64_t>(total); |
- return true; |
+//static |
+std::pair<int64_t,int64_t> |
+QuotaManager::GetVolumeInfo(const base::FilePath& path) { |
+ return std::make_pair( |
+ base::SysInfo::AmountOfTotalDiskSpace(path), |
+ base::SysInfo::AmountOfFreeDiskSpace(path)); |
} |
} // namespace storage |
+ |