Home | History | Annotate | Download | only in quota
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "webkit/browser/quota/quota_manager.h"
      6 
      7 #include <algorithm>
      8 #include <deque>
      9 #include <functional>
     10 #include <set>
     11 
     12 #include "base/bind.h"
     13 #include "base/bind_helpers.h"
     14 #include "base/callback.h"
     15 #include "base/command_line.h"
     16 #include "base/file_util.h"
     17 #include "base/files/file_path.h"
     18 #include "base/metrics/histogram.h"
     19 #include "base/sequenced_task_runner.h"
     20 #include "base/single_thread_task_runner.h"
     21 #include "base/strings/string_number_conversions.h"
     22 #include "base/sys_info.h"
     23 #include "base/task_runner_util.h"
     24 #include "base/time/time.h"
     25 #include "net/base/net_util.h"
     26 #include "webkit/browser/quota/quota_database.h"
     27 #include "webkit/browser/quota/quota_temporary_storage_evictor.h"
     28 #include "webkit/browser/quota/usage_tracker.h"
     29 #include "webkit/common/quota/quota_types.h"
     30 
     31 #define UMA_HISTOGRAM_MBYTES(name, sample)          \
     32   UMA_HISTOGRAM_CUSTOM_COUNTS(                      \
     33       (name), static_cast<int>((sample) / kMBytes), \
     34       1, 10 * 1024 * 1024 /* 10TB */, 100)
     35 
     36 namespace quota {
     37 
     38 namespace {
     39 
     40 const int64 kMBytes = 1024 * 1024;
     41 const int kMinutesInMilliSeconds = 60 * 1000;
     42 
     43 const int64 kReportHistogramInterval = 60 * 60 * 1000;  // 1 hour
     44 const double kTemporaryQuotaRatioToAvail = 0.5;  // 50%
     45 
     46 }  // namespace
     47 
     48 // Arbitrary for now, but must be reasonably small so that
     49 // in-memory databases can fit.
     50 // TODO(kinuko): Refer SysInfo::AmountOfPhysicalMemory() to determine this.
     51 const int64 QuotaManager::kIncognitoDefaultQuotaLimit = 100 * kMBytes;
     52 
     53 const int64 QuotaManager::kNoLimit = kint64max;
     54 
     55 const int QuotaManager::kPerHostTemporaryPortion = 5;  // 20%
     56 
     57 const char QuotaManager::kDatabaseName[] = "QuotaManager";
     58 
     59 // Preserve kMinimumPreserveForSystem disk space for system book-keeping
     60 // when returning the quota to unlimited apps/extensions.
     61 // TODO(kinuko): This should be like 10% of the actual disk space.
     62 // For now we simply use a constant as getting the disk size needs
     63 // platform-dependent code. (http://crbug.com/178976)
     64 const int64 QuotaManager::kMinimumPreserveForSystem = 1024 * kMBytes;
     65 
     66 const int QuotaManager::kThresholdOfErrorsToBeBlacklisted = 3;
     67 
     68 const int QuotaManager::kEvictionIntervalInMilliSeconds =
     69     30 * kMinutesInMilliSeconds;
     70 
     71 // Heuristics: assuming average cloud server allows a few Gigs storage
     72 // on the server side and the storage needs to be shared for user data
     73 // and by multiple apps.
     74 int64 QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes;
     75 
     76 namespace {
     77 
     78 void CountOriginType(const std::set<GURL>& origins,
     79                      SpecialStoragePolicy* policy,
     80                      size_t* protected_origins,
     81                      size_t* unlimited_origins) {
     82   DCHECK(protected_origins);
     83   DCHECK(unlimited_origins);
     84   *protected_origins = 0;
     85   *unlimited_origins = 0;
     86   if (!policy)
     87     return;
     88   for (std::set<GURL>::const_iterator itr = origins.begin();
     89        itr != origins.end();
     90        ++itr) {
     91     if (policy->IsStorageProtected(*itr))
     92       ++*protected_origins;
     93     if (policy->IsStorageUnlimited(*itr))
     94       ++*unlimited_origins;
     95   }
     96 }
     97 
     98 bool SetTemporaryGlobalOverrideQuotaOnDBThread(int64* new_quota,
     99                                                QuotaDatabase* database) {
    100   DCHECK(database);
    101   if (!database->SetQuotaConfigValue(
    102           QuotaDatabase::kTemporaryQuotaOverrideKey, *new_quota)) {
    103     *new_quota = -1;
    104     return false;
    105   }
    106   return true;
    107 }
    108 
    109 bool GetPersistentHostQuotaOnDBThread(const std::string& host,
    110                                       int64* quota,
    111                                       QuotaDatabase* database) {
    112   DCHECK(database);
    113   database->GetHostQuota(host, kStorageTypePersistent, quota);
    114   return true;
    115 }
    116 
    117 bool SetPersistentHostQuotaOnDBThread(const std::string& host,
    118                                       int64* new_quota,
    119                                       QuotaDatabase* database) {
    120   DCHECK(database);
    121   if (database->SetHostQuota(host, kStorageTypePersistent, *new_quota))
    122     return true;
    123   *new_quota = 0;
    124   return false;
    125 }
    126 
    127 bool InitializeOnDBThread(int64* temporary_quota_override,
    128                           int64* desired_available_space,
    129                           QuotaDatabase* database) {
    130   DCHECK(database);
    131   database->GetQuotaConfigValue(QuotaDatabase::kTemporaryQuotaOverrideKey,
    132                                 temporary_quota_override);
    133   database->GetQuotaConfigValue(QuotaDatabase::kDesiredAvailableSpaceKey,
    134                                 desired_available_space);
    135   return true;
    136 }
    137 
    138 bool GetLRUOriginOnDBThread(StorageType type,
    139                             std::set<GURL>* exceptions,
    140                             SpecialStoragePolicy* policy,
    141                             GURL* url,
    142                             QuotaDatabase* database) {
    143   DCHECK(database);
    144   database->GetLRUOrigin(type, *exceptions, policy, url);
    145   return true;
    146 }
    147 
    148 bool DeleteOriginInfoOnDBThread(const GURL& origin,
    149                                 StorageType type,
    150                                 QuotaDatabase* database) {
    151   DCHECK(database);
    152   return database->DeleteOriginInfo(origin, type);
    153 }
    154 
    155 bool InitializeTemporaryOriginsInfoOnDBThread(const std::set<GURL>* origins,
    156                                               QuotaDatabase* database) {
    157   DCHECK(database);
    158   if (database->IsOriginDatabaseBootstrapped())
    159     return true;
    160 
    161   // Register existing origins with 0 last time access.
    162   if (database->RegisterInitialOriginInfo(*origins, kStorageTypeTemporary)) {
    163     database->SetOriginDatabaseBootstrapped(true);
    164     return true;
    165   }
    166   return false;
    167 }
    168 
    169 bool UpdateAccessTimeOnDBThread(const GURL& origin,
    170                                 StorageType type,
    171                                 base::Time accessed_time,
    172                                 QuotaDatabase* database) {
    173   DCHECK(database);
    174   return database->SetOriginLastAccessTime(origin, type, accessed_time);
    175 }
    176 
    177 bool UpdateModifiedTimeOnDBThread(const GURL& origin,
    178                                   StorageType type,
    179                                   base::Time modified_time,
    180                                   QuotaDatabase* database) {
    181   DCHECK(database);
    182   return database->SetOriginLastModifiedTime(origin, type, modified_time);
    183 }
    184 
    185 int64 CallSystemGetAmountOfFreeDiskSpace(const base::FilePath& profile_path) {
    186   // Ensure the profile path exists.
    187   if(!file_util::CreateDirectory(profile_path)) {
    188     LOG(WARNING) << "Create directory failed for path" << profile_path.value();
    189     return 0;
    190   }
    191   return base::SysInfo::AmountOfFreeDiskSpace(profile_path);
    192 }
    193 
    194 int64 CalculateTemporaryGlobalQuota(int64 global_limited_usage,
    195                                     int64 available_space) {
    196   DCHECK_GE(global_limited_usage, 0);
    197   int64 avail_space = available_space;
    198   if (avail_space < kint64max - global_limited_usage) {
    199     // We basically calculate the temporary quota by
    200     // [available_space + space_used_for_temp] * kTempQuotaRatio,
    201     // but make sure we'll have no overflow.
    202     avail_space += global_limited_usage;
    203   }
    204   return avail_space * kTemporaryQuotaRatioToAvail;
    205 }
    206 
    207 void DispatchTemporaryGlobalQuotaCallback(
    208     const QuotaCallback& callback,
    209     QuotaStatusCode status,
    210     const UsageAndQuota& usage_and_quota) {
    211   if (status != kQuotaStatusOk) {
    212     callback.Run(status, 0);
    213     return;
    214   }
    215 
    216   callback.Run(status, CalculateTemporaryGlobalQuota(
    217       usage_and_quota.global_limited_usage,
    218       usage_and_quota.available_disk_space));
    219 }
    220 
    221 int64 CalculateQuotaWithDiskSpace(
    222     int64 available_disk_space, int64 usage, int64 quota) {
    223   if (available_disk_space < QuotaManager::kMinimumPreserveForSystem ||
    224       quota < usage) {
    225     // No more space; cap the quota to the current usage.
    226     return usage;
    227   }
    228 
    229   available_disk_space -= QuotaManager::kMinimumPreserveForSystem;
    230   if (available_disk_space < quota - usage)
    231     return available_disk_space + usage;
    232 
    233   return quota;
    234 }
    235 
    236 int64 CalculateTemporaryHostQuota(int64 host_usage,
    237                                   int64 global_quota,
    238                                   int64 global_limited_usage) {
    239   DCHECK_GE(global_limited_usage, 0);
    240   int64 host_quota = global_quota / QuotaManager::kPerHostTemporaryPortion;
    241   if (global_limited_usage > global_quota)
    242     host_quota = std::min(host_quota, host_usage);
    243   return host_quota;
    244 }
    245 
    246 void DispatchUsageAndQuotaForWebApps(
    247     StorageType type,
    248     bool is_incognito,
    249     bool is_unlimited,
    250     bool can_query_disk_size,
    251     const QuotaManager::GetUsageAndQuotaCallback& callback,
    252     QuotaStatusCode status,
    253     const UsageAndQuota& usage_and_quota) {
    254   if (status != kQuotaStatusOk) {
    255     callback.Run(status, 0, 0);
    256     return;
    257   }
    258 
    259   int64 usage = usage_and_quota.usage;
    260   int64 quota = usage_and_quota.quota;
    261 
    262   if (type == kStorageTypeTemporary && !is_unlimited) {
    263     quota = CalculateTemporaryHostQuota(
    264         usage, quota, usage_and_quota.global_limited_usage);
    265   }
    266 
    267   if (is_incognito) {
    268     quota = std::min(quota, QuotaManager::kIncognitoDefaultQuotaLimit);
    269     callback.Run(status, usage, quota);
    270     return;
    271   }
    272 
    273   // For apps with unlimited permission or can_query_disk_size is true (and not
    274   // in incognito mode).
    275   // We assume we can expose the actual disk size for them and cap the quota by
    276   // the available disk space.
    277   if (is_unlimited || can_query_disk_size) {
    278     callback.Run(
    279         status, usage,
    280         CalculateQuotaWithDiskSpace(
    281             usage_and_quota.available_disk_space,
    282             usage, quota));
    283     return;
    284   }
    285 
    286   callback.Run(status, usage, quota);
    287 }
    288 
    289 }  // namespace
    290 
    291 UsageAndQuota::UsageAndQuota()
    292     : usage(0),
    293       global_limited_usage(0),
    294       quota(0),
    295       available_disk_space(0) {
    296 }
    297 
    298 UsageAndQuota::UsageAndQuota(
    299     int64 usage,
    300     int64 global_limited_usage,
    301     int64 quota,
    302     int64 available_disk_space)
    303     : usage(usage),
    304       global_limited_usage(global_limited_usage),
    305       quota(quota),
    306       available_disk_space(available_disk_space) {
    307 }
    308 
    309 class UsageAndQuotaCallbackDispatcher
    310     : public QuotaTask,
    311       public base::SupportsWeakPtr<UsageAndQuotaCallbackDispatcher> {
    312  public:
    313   UsageAndQuotaCallbackDispatcher(QuotaManager* manager)
    314       : QuotaTask(manager),
    315         has_usage_(false),
    316         has_global_limited_usage_(false),
    317         has_quota_(false),
    318         has_available_disk_space_(false),
    319         status_(kQuotaStatusUnknown),
    320         usage_and_quota_(-1, -1, -1, -1),
    321         waiting_callbacks_(1) {}
    322 
    323   virtual ~UsageAndQuotaCallbackDispatcher() {}
    324 
    325   void WaitForResults(const QuotaManager::UsageAndQuotaCallback& callback) {
    326     callback_ = callback;
    327     Start();
    328   }
    329 
    330   void set_usage(int64 usage) {
    331     usage_and_quota_.usage = usage;
    332     has_usage_ = true;
    333   }
    334 
    335   void set_global_limited_usage(int64 global_limited_usage) {
    336     usage_and_quota_.global_limited_usage = global_limited_usage;
    337     has_global_limited_usage_ = true;
    338   }
    339 
    340   void set_quota(int64 quota) {
    341     usage_and_quota_.quota = quota;
    342     has_quota_ = true;
    343   }
    344 
    345   void set_available_disk_space(int64 available_disk_space) {
    346     usage_and_quota_.available_disk_space = available_disk_space;
    347     has_available_disk_space_ = true;
    348   }
    349 
    350   UsageCallback GetHostUsageCallback() {
    351     ++waiting_callbacks_;
    352     has_usage_ = true;
    353     return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetHostUsage,
    354                       AsWeakPtr());
    355   }
    356 
    357   UsageCallback GetGlobalLimitedUsageCallback() {
    358     ++waiting_callbacks_;
    359     has_global_limited_usage_ = true;
    360     return base::Bind(
    361         &UsageAndQuotaCallbackDispatcher::DidGetGlobalLimitedUsage,
    362         AsWeakPtr());
    363   }
    364 
    365   QuotaCallback GetQuotaCallback() {
    366     ++waiting_callbacks_;
    367     has_quota_ = true;
    368     return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetQuota,
    369                       AsWeakPtr());
    370   }
    371 
    372   QuotaCallback GetAvailableSpaceCallback() {
    373     ++waiting_callbacks_;
    374     has_available_disk_space_ = true;
    375     return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace,
    376                       AsWeakPtr());
    377   }
    378 
    379  private:
    380   void DidGetHostUsage(int64 usage) {
    381     if (status_ == kQuotaStatusUnknown)
    382       status_ = kQuotaStatusOk;
    383     usage_and_quota_.usage = usage;
    384     CheckCompleted();
    385   }
    386 
    387   void DidGetGlobalLimitedUsage(int64 limited_usage) {
    388     if (status_ == kQuotaStatusUnknown)
    389       status_ = kQuotaStatusOk;
    390     usage_and_quota_.global_limited_usage = limited_usage;
    391     CheckCompleted();
    392   }
    393 
    394   void DidGetQuota(QuotaStatusCode status, int64 quota) {
    395     if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk)
    396       status_ = status;
    397     usage_and_quota_.quota = quota;
    398     CheckCompleted();
    399   }
    400 
    401   void DidGetAvailableSpace(QuotaStatusCode status, int64 space) {
    402     DCHECK_GE(space, 0);
    403     if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk)
    404       status_ = status;
    405     usage_and_quota_.available_disk_space = space;
    406     CheckCompleted();
    407   }
    408 
    409   virtual void Run() OVERRIDE {
    410     // We initialize waiting_callbacks to 1 so that we won't run
    411     // the completion callback until here even some of the callbacks
    412     // are dispatched synchronously.
    413     CheckCompleted();
    414   }
    415 
    416   virtual void Aborted() OVERRIDE {
    417     callback_.Run(kQuotaErrorAbort, UsageAndQuota());
    418     DeleteSoon();
    419   }
    420 
    421   virtual void Completed() OVERRIDE {
    422     DCHECK(!has_usage_ || usage_and_quota_.usage >= 0);
    423     DCHECK(!has_global_limited_usage_ ||
    424            usage_and_quota_.global_limited_usage >= 0);
    425     DCHECK(!has_quota_ || usage_and_quota_.quota >= 0);
    426     DCHECK(!has_available_disk_space_ ||
    427            usage_and_quota_.available_disk_space >= 0);
    428 
    429     callback_.Run(status_, usage_and_quota_);
    430     DeleteSoon();
    431   }
    432 
    433   void CheckCompleted() {
    434     if (--waiting_callbacks_ <= 0)
    435       CallCompleted();
    436   }
    437 
    438   // For sanity checks, they're checked only when DCHECK is on.
    439   bool has_usage_;
    440   bool has_global_limited_usage_;
    441   bool has_quota_;
    442   bool has_available_disk_space_;
    443 
    444   QuotaStatusCode status_;
    445   UsageAndQuota usage_and_quota_;
    446   QuotaManager::UsageAndQuotaCallback callback_;
    447   int waiting_callbacks_;
    448 
    449   DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaCallbackDispatcher);
    450 };
    451 
    452 class QuotaManager::GetUsageInfoTask : public QuotaTask {
    453  private:
    454   typedef QuotaManager::GetUsageInfoTask self_type;
    455 
    456  public:
    457   GetUsageInfoTask(
    458       QuotaManager* manager,
    459       const GetUsageInfoCallback& callback)
    460       : QuotaTask(manager),
    461         callback_(callback),
    462         weak_factory_(this) {
    463   }
    464 
    465  protected:
    466   virtual void Run() OVERRIDE {
    467     remaining_trackers_ = 3;
    468     // This will populate cached hosts and usage info.
    469     manager()->GetUsageTracker(kStorageTypeTemporary)->GetGlobalUsage(
    470         base::Bind(&GetUsageInfoTask::DidGetGlobalUsage,
    471                    weak_factory_.GetWeakPtr(),
    472                    kStorageTypeTemporary));
    473     manager()->GetUsageTracker(kStorageTypePersistent)->GetGlobalUsage(
    474         base::Bind(&GetUsageInfoTask::DidGetGlobalUsage,
    475                    weak_factory_.GetWeakPtr(),
    476                    kStorageTypePersistent));
    477     manager()->GetUsageTracker(kStorageTypeSyncable)->GetGlobalUsage(
    478         base::Bind(&GetUsageInfoTask::DidGetGlobalUsage,
    479                    weak_factory_.GetWeakPtr(),
    480                    kStorageTypeSyncable));
    481   }
    482 
    483   virtual void Completed() OVERRIDE {
    484     callback_.Run(entries_);
    485     DeleteSoon();
    486   }
    487 
    488   virtual void Aborted() OVERRIDE {
    489     callback_.Run(UsageInfoEntries());
    490     DeleteSoon();
    491   }
    492 
    493  private:
    494   void AddEntries(StorageType type, UsageTracker* tracker) {
    495     std::map<std::string, int64> host_usage;
    496     tracker->GetCachedHostsUsage(&host_usage);
    497     for (std::map<std::string, int64>::const_iterator iter = host_usage.begin();
    498          iter != host_usage.end();
    499          ++iter) {
    500       entries_.push_back(UsageInfo(iter->first, type, iter->second));
    501     }
    502     if (--remaining_trackers_ == 0)
    503       CallCompleted();
    504   }
    505 
    506   void DidGetGlobalUsage(StorageType type, int64, int64) {
    507     AddEntries(type, manager()->GetUsageTracker(type));
    508   }
    509 
    510   QuotaManager* manager() const {
    511     return static_cast<QuotaManager*>(observer());
    512   }
    513 
    514   GetUsageInfoCallback callback_;
    515   UsageInfoEntries entries_;
    516   base::WeakPtrFactory<GetUsageInfoTask> weak_factory_;
    517   int remaining_trackers_;
    518 
    519   DISALLOW_COPY_AND_ASSIGN(GetUsageInfoTask);
    520 };
    521 
    522 class QuotaManager::OriginDataDeleter : public QuotaTask {
    523  public:
    524   OriginDataDeleter(QuotaManager* manager,
    525                     const GURL& origin,
    526                     StorageType type,
    527                     int quota_client_mask,
    528                     const StatusCallback& callback)
    529       : QuotaTask(manager),
    530         origin_(origin),
    531         type_(type),
    532         quota_client_mask_(quota_client_mask),
    533         error_count_(0),
    534         remaining_clients_(-1),
    535         skipped_clients_(0),
    536         callback_(callback),
    537         weak_factory_(this) {}
    538 
    539  protected:
    540   virtual void Run() OVERRIDE {
    541     error_count_ = 0;
    542     remaining_clients_ = manager()->clients_.size();
    543     for (QuotaClientList::iterator iter = manager()->clients_.begin();
    544          iter != manager()->clients_.end(); ++iter) {
    545       if (quota_client_mask_ & (*iter)->id()) {
    546         (*iter)->DeleteOriginData(
    547             origin_, type_,
    548             base::Bind(&OriginDataDeleter::DidDeleteOriginData,
    549                        weak_factory_.GetWeakPtr()));
    550       } else {
    551         ++skipped_clients_;
    552         if (--remaining_clients_ == 0)
    553           CallCompleted();
    554       }
    555     }
    556   }
    557 
    558   virtual void Completed() OVERRIDE {
    559     if (error_count_ == 0) {
    560       // Only remove the entire origin if we didn't skip any client types.
    561       if (skipped_clients_ == 0)
    562         manager()->DeleteOriginFromDatabase(origin_, type_);
    563       callback_.Run(kQuotaStatusOk);
    564     } else {
    565       callback_.Run(kQuotaErrorInvalidModification);
    566     }
    567     DeleteSoon();
    568   }
    569 
    570   virtual void Aborted() OVERRIDE {
    571     callback_.Run(kQuotaErrorAbort);
    572     DeleteSoon();
    573   }
    574 
    575   void DidDeleteOriginData(QuotaStatusCode status) {
    576     DCHECK_GT(remaining_clients_, 0);
    577 
    578     if (status != kQuotaStatusOk)
    579       ++error_count_;
    580 
    581     if (--remaining_clients_ == 0)
    582       CallCompleted();
    583   }
    584 
    585   QuotaManager* manager() const {
    586     return static_cast<QuotaManager*>(observer());
    587   }
    588 
    589   GURL origin_;
    590   StorageType type_;
    591   int quota_client_mask_;
    592   int error_count_;
    593   int remaining_clients_;
    594   int skipped_clients_;
    595   StatusCallback callback_;
    596 
    597   base::WeakPtrFactory<OriginDataDeleter> weak_factory_;
    598   DISALLOW_COPY_AND_ASSIGN(OriginDataDeleter);
    599 };
    600 
    601 class QuotaManager::HostDataDeleter : public QuotaTask {
    602  public:
    603   HostDataDeleter(QuotaManager* manager,
    604                   const std::string& host,
    605                   StorageType type,
    606                   int quota_client_mask,
    607                   const StatusCallback& callback)
    608       : QuotaTask(manager),
    609         host_(host),
    610         type_(type),
    611         quota_client_mask_(quota_client_mask),
    612         error_count_(0),
    613         remaining_clients_(-1),
    614         remaining_deleters_(-1),
    615         callback_(callback),
    616         weak_factory_(this) {}
    617 
    618  protected:
    619   virtual void Run() OVERRIDE {
    620     error_count_ = 0;
    621     remaining_clients_ = manager()->clients_.size();
    622     for (QuotaClientList::iterator iter = manager()->clients_.begin();
    623          iter != manager()->clients_.end(); ++iter) {
    624       (*iter)->GetOriginsForHost(
    625           type_, host_,
    626           base::Bind(&HostDataDeleter::DidGetOriginsForHost,
    627                      weak_factory_.GetWeakPtr()));
    628     }
    629   }
    630 
    631   virtual void Completed() OVERRIDE {
    632     if (error_count_ == 0) {
    633       callback_.Run(kQuotaStatusOk);
    634     } else {
    635       callback_.Run(kQuotaErrorInvalidModification);
    636     }
    637     DeleteSoon();
    638   }
    639 
    640   virtual void Aborted() OVERRIDE {
    641     callback_.Run(kQuotaErrorAbort);
    642     DeleteSoon();
    643   }
    644 
    645   void DidGetOriginsForHost(const std::set<GURL>& origins) {
    646     DCHECK_GT(remaining_clients_, 0);
    647 
    648     origins_.insert(origins.begin(), origins.end());
    649 
    650     if (--remaining_clients_ == 0) {
    651       if (!origins_.empty())
    652         ScheduleOriginsDeletion();
    653       else
    654         CallCompleted();
    655     }
    656   }
    657 
    658   void ScheduleOriginsDeletion() {
    659     remaining_deleters_ = origins_.size();
    660     for (std::set<GURL>::const_iterator p = origins_.begin();
    661          p != origins_.end();
    662          ++p) {
    663       OriginDataDeleter* deleter =
    664           new OriginDataDeleter(
    665               manager(), *p, type_, quota_client_mask_,
    666               base::Bind(&HostDataDeleter::DidDeleteOriginData,
    667                          weak_factory_.GetWeakPtr()));
    668       deleter->Start();
    669     }
    670   }
    671 
    672   void DidDeleteOriginData(QuotaStatusCode status) {
    673     DCHECK_GT(remaining_deleters_, 0);
    674 
    675     if (status != kQuotaStatusOk)
    676       ++error_count_;
    677 
    678     if (--remaining_deleters_ == 0)
    679       CallCompleted();
    680   }
    681 
    682   QuotaManager* manager() const {
    683     return static_cast<QuotaManager*>(observer());
    684   }
    685 
    686   std::string host_;
    687   StorageType type_;
    688   int quota_client_mask_;
    689   std::set<GURL> origins_;
    690   int error_count_;
    691   int remaining_clients_;
    692   int remaining_deleters_;
    693   StatusCallback callback_;
    694 
    695   base::WeakPtrFactory<HostDataDeleter> weak_factory_;
    696   DISALLOW_COPY_AND_ASSIGN(HostDataDeleter);
    697 };
    698 
    699 class QuotaManager::GetModifiedSinceHelper {
    700  public:
    701   bool GetModifiedSinceOnDBThread(StorageType type,
    702                                   base::Time modified_since,
    703                                   QuotaDatabase* database) {
    704     DCHECK(database);
    705     return database->GetOriginsModifiedSince(type, &origins_, modified_since);
    706   }
    707 
    708   void DidGetModifiedSince(const base::WeakPtr<QuotaManager>& manager,
    709                            const GetOriginsCallback& callback,
    710                            StorageType type,
    711                            bool success) {
    712     if (!manager) {
    713       // The operation was aborted.
    714       callback.Run(std::set<GURL>(), type);
    715       return;
    716     }
    717     manager->DidDatabaseWork(success);
    718     callback.Run(origins_, type);
    719   }
    720 
    721  private:
    722   std::set<GURL> origins_;
    723 };
    724 
    725 class QuotaManager::DumpQuotaTableHelper {
    726  public:
    727   bool DumpQuotaTableOnDBThread(QuotaDatabase* database) {
    728     DCHECK(database);
    729     return database->DumpQuotaTable(
    730         new TableCallback(base::Bind(&DumpQuotaTableHelper::AppendEntry,
    731                                      base::Unretained(this))));
    732   }
    733 
    734   void DidDumpQuotaTable(const base::WeakPtr<QuotaManager>& manager,
    735                          const DumpQuotaTableCallback& callback,
    736                          bool success) {
    737     if (!manager) {
    738       // The operation was aborted.
    739       callback.Run(QuotaTableEntries());
    740       return;
    741     }
    742     manager->DidDatabaseWork(success);
    743     callback.Run(entries_);
    744   }
    745 
    746  private:
    747   typedef QuotaDatabase::QuotaTableCallback TableCallback;
    748 
    749   bool AppendEntry(const QuotaTableEntry& entry) {
    750     entries_.push_back(entry);
    751     return true;
    752   }
    753 
    754   QuotaTableEntries entries_;
    755 };
    756 
    757 class QuotaManager::DumpOriginInfoTableHelper {
    758  public:
    759   bool DumpOriginInfoTableOnDBThread(QuotaDatabase* database) {
    760     DCHECK(database);
    761     return database->DumpOriginInfoTable(
    762         new TableCallback(base::Bind(&DumpOriginInfoTableHelper::AppendEntry,
    763                                      base::Unretained(this))));
    764   }
    765 
    766   void DidDumpOriginInfoTable(const base::WeakPtr<QuotaManager>& manager,
    767                               const DumpOriginInfoTableCallback& callback,
    768                               bool success) {
    769     if (!manager) {
    770       // The operation was aborted.
    771       callback.Run(OriginInfoTableEntries());
    772       return;
    773     }
    774     manager->DidDatabaseWork(success);
    775     callback.Run(entries_);
    776   }
    777 
    778  private:
    779   typedef QuotaDatabase::OriginInfoTableCallback TableCallback;
    780 
    781   bool AppendEntry(const OriginInfoTableEntry& entry) {
    782     entries_.push_back(entry);
    783     return true;
    784   }
    785 
    786   OriginInfoTableEntries entries_;
    787 };
    788 
    789 // QuotaManager ---------------------------------------------------------------
    790 
    791 QuotaManager::QuotaManager(bool is_incognito,
    792                            const base::FilePath& profile_path,
    793                            base::SingleThreadTaskRunner* io_thread,
    794                            base::SequencedTaskRunner* db_thread,
    795                            SpecialStoragePolicy* special_storage_policy)
    796   : is_incognito_(is_incognito),
    797     profile_path_(profile_path),
    798     proxy_(new QuotaManagerProxy(
    799         this, io_thread)),
    800     db_disabled_(false),
    801     eviction_disabled_(false),
    802     io_thread_(io_thread),
    803     db_thread_(db_thread),
    804     temporary_quota_initialized_(false),
    805     temporary_quota_override_(-1),
    806     desired_available_space_(-1),
    807     special_storage_policy_(special_storage_policy),
    808     weak_factory_(this),
    809     get_disk_space_fn_(&CallSystemGetAmountOfFreeDiskSpace) {
    810 }
    811 
    812 void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) {
    813   LazyInitialize();
    814   GetUsageInfoTask* get_usage_info = new GetUsageInfoTask(this, callback);
    815   get_usage_info->Start();
    816 }
    817 
    818 void QuotaManager::GetUsageAndQuotaForWebApps(
    819     const GURL& origin,
    820     StorageType type,
    821     const GetUsageAndQuotaCallback& callback) {
    822   if (type != kStorageTypeTemporary &&
    823       type != kStorageTypePersistent &&
    824       type != kStorageTypeSyncable) {
    825     callback.Run(kQuotaErrorNotSupported, 0, 0);
    826     return;
    827   }
    828 
    829   DCHECK(origin == origin.GetOrigin());
    830   LazyInitialize();
    831 
    832   bool unlimited = IsStorageUnlimited(origin, type);
    833   bool can_query_disk_size = CanQueryDiskSize(origin);
    834 
    835   UsageAndQuotaCallbackDispatcher* dispatcher =
    836       new UsageAndQuotaCallbackDispatcher(this);
    837 
    838   UsageAndQuota usage_and_quota;
    839   if (unlimited) {
    840     dispatcher->set_quota(kNoLimit);
    841   } else {
    842     if (type == kStorageTypeTemporary) {
    843       GetUsageTracker(type)->GetGlobalLimitedUsage(
    844           dispatcher->GetGlobalLimitedUsageCallback());
    845       GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback());
    846     } else if (type == kStorageTypePersistent) {
    847       GetPersistentHostQuota(net::GetHostOrSpecFromURL(origin),
    848                              dispatcher->GetQuotaCallback());
    849     } else {
    850       dispatcher->set_quota(kSyncableStorageDefaultHostQuota);
    851     }
    852   }
    853 
    854   GetUsageTracker(type)->GetHostUsage(net::GetHostOrSpecFromURL(origin),
    855                                       dispatcher->GetHostUsageCallback());
    856 
    857   if (!is_incognito_ && (unlimited || can_query_disk_size))
    858     GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
    859 
    860   dispatcher->WaitForResults(base::Bind(
    861       &DispatchUsageAndQuotaForWebApps,
    862       type, is_incognito_, unlimited, can_query_disk_size,
    863       callback));
    864 }
    865 
    866 void QuotaManager::GetUsageAndQuota(
    867     const GURL& origin, StorageType type,
    868     const GetUsageAndQuotaCallback& callback) {
    869   DCHECK(origin == origin.GetOrigin());
    870 
    871   if (IsStorageUnlimited(origin, type)) {
    872     callback.Run(kQuotaStatusOk, 0, kNoLimit);
    873     return;
    874   }
    875 
    876   GetUsageAndQuotaForWebApps(origin, type, callback);
    877 }
    878 
    879 void QuotaManager::NotifyStorageAccessed(
    880     QuotaClient::ID client_id,
    881     const GURL& origin, StorageType type) {
    882   DCHECK(origin == origin.GetOrigin());
    883   NotifyStorageAccessedInternal(client_id, origin, type, base::Time::Now());
    884 }
    885 
    886 void QuotaManager::NotifyStorageModified(
    887     QuotaClient::ID client_id,
    888     const GURL& origin, StorageType type, int64 delta) {
    889   DCHECK(origin == origin.GetOrigin());
    890   NotifyStorageModifiedInternal(client_id, origin, type, delta,
    891                                 base::Time::Now());
    892 }
    893 
    894 void QuotaManager::NotifyOriginInUse(const GURL& origin) {
    895   DCHECK(io_thread_->BelongsToCurrentThread());
    896   origins_in_use_[origin]++;
    897 }
    898 
    899 void QuotaManager::NotifyOriginNoLongerInUse(const GURL& origin) {
    900   DCHECK(io_thread_->BelongsToCurrentThread());
    901   DCHECK(IsOriginInUse(origin));
    902   int& count = origins_in_use_[origin];
    903   if (--count == 0)
    904     origins_in_use_.erase(origin);
    905 }
    906 
    907 void QuotaManager::SetUsageCacheEnabled(QuotaClient::ID client_id,
    908                                         const GURL& origin,
    909                                         StorageType type,
    910                                         bool enabled) {
    911   LazyInitialize();
    912   GetUsageTracker(type)->SetUsageCacheEnabled(client_id, origin, enabled);
    913 }
    914 
    915 void QuotaManager::DeleteOriginData(
    916     const GURL& origin, StorageType type, int quota_client_mask,
    917     const StatusCallback& callback) {
    918   LazyInitialize();
    919 
    920   if (origin.is_empty() || clients_.empty()) {
    921     callback.Run(kQuotaStatusOk);
    922     return;
    923   }
    924 
    925   DCHECK(origin == origin.GetOrigin());
    926   OriginDataDeleter* deleter =
    927       new OriginDataDeleter(this, origin, type, quota_client_mask, callback);
    928   deleter->Start();
    929 }
    930 
    931 void QuotaManager::DeleteHostData(const std::string& host,
    932                                   StorageType type,
    933                                   int quota_client_mask,
    934                                   const StatusCallback& callback) {
    935   LazyInitialize();
    936 
    937   if (host.empty() || clients_.empty()) {
    938     callback.Run(kQuotaStatusOk);
    939     return;
    940   }
    941 
    942   HostDataDeleter* deleter =
    943       new HostDataDeleter(this, host, type, quota_client_mask, callback);
    944   deleter->Start();
    945 }
    946 
    947 void QuotaManager::GetAvailableSpace(const AvailableSpaceCallback& callback) {
    948   if (!available_space_callbacks_.Add(callback))
    949     return;
    950 
    951   PostTaskAndReplyWithResult(db_thread_.get(),
    952                              FROM_HERE,
    953                              base::Bind(get_disk_space_fn_, profile_path_),
    954                              base::Bind(&QuotaManager::DidGetAvailableSpace,
    955                                         weak_factory_.GetWeakPtr()));
    956 }
    957 
    958 void QuotaManager::GetTemporaryGlobalQuota(const QuotaCallback& callback) {
    959   LazyInitialize();
    960   if (!temporary_quota_initialized_) {
    961     db_initialization_callbacks_.Add(base::Bind(
    962         &QuotaManager::GetTemporaryGlobalQuota,
    963         weak_factory_.GetWeakPtr(), callback));
    964     return;
    965   }
    966 
    967   if (temporary_quota_override_ > 0) {
    968     callback.Run(kQuotaStatusOk, temporary_quota_override_);
    969     return;
    970   }
    971 
    972   UsageAndQuotaCallbackDispatcher* dispatcher =
    973       new UsageAndQuotaCallbackDispatcher(this);
    974   GetUsageTracker(kStorageTypeTemporary)->
    975       GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback());
    976   GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
    977   dispatcher->WaitForResults(
    978       base::Bind(&DispatchTemporaryGlobalQuotaCallback, callback));
    979 }
    980 
    981 void QuotaManager::SetTemporaryGlobalOverrideQuota(
    982     int64 new_quota, const QuotaCallback& callback) {
    983   LazyInitialize();
    984 
    985   if (new_quota < 0) {
    986     if (!callback.is_null())
    987       callback.Run(kQuotaErrorInvalidModification, -1);
    988     return;
    989   }
    990 
    991   if (db_disabled_) {
    992     if (callback.is_null())
    993       callback.Run(kQuotaErrorInvalidAccess, -1);
    994     return;
    995   }
    996 
    997   int64* new_quota_ptr = new int64(new_quota);
    998   PostTaskAndReplyWithResultForDBThread(
    999       FROM_HERE,
   1000       base::Bind(&SetTemporaryGlobalOverrideQuotaOnDBThread,
   1001                  base::Unretained(new_quota_ptr)),
   1002       base::Bind(&QuotaManager::DidSetTemporaryGlobalOverrideQuota,
   1003                  weak_factory_.GetWeakPtr(),
   1004                  callback,
   1005                  base::Owned(new_quota_ptr)));
   1006 }
   1007 
   1008 void QuotaManager::GetPersistentHostQuota(const std::string& host,
   1009                                           const QuotaCallback& callback) {
   1010   LazyInitialize();
   1011   if (host.empty()) {
   1012     // This could happen if we are called on file:///.
   1013     // TODO(kinuko) We may want to respect --allow-file-access-from-files
   1014     // command line switch.
   1015     callback.Run(kQuotaStatusOk, 0);
   1016     return;
   1017   }
   1018 
   1019   if (!persistent_host_quota_callbacks_.Add(host, callback))
   1020     return;
   1021 
   1022   int64* quota_ptr = new int64(0);
   1023   PostTaskAndReplyWithResultForDBThread(
   1024       FROM_HERE,
   1025       base::Bind(&GetPersistentHostQuotaOnDBThread,
   1026                  host,
   1027                  base::Unretained(quota_ptr)),
   1028       base::Bind(&QuotaManager::DidGetPersistentHostQuota,
   1029                  weak_factory_.GetWeakPtr(),
   1030                  host,
   1031                  base::Owned(quota_ptr)));
   1032 }
   1033 
   1034 void QuotaManager::SetPersistentHostQuota(const std::string& host,
   1035                                           int64 new_quota,
   1036                                           const QuotaCallback& callback) {
   1037   LazyInitialize();
   1038   if (host.empty()) {
   1039     // This could happen if we are called on file:///.
   1040     callback.Run(kQuotaErrorNotSupported, 0);
   1041     return;
   1042   }
   1043   if (new_quota < 0) {
   1044     callback.Run(kQuotaErrorInvalidModification, -1);
   1045     return;
   1046   }
   1047 
   1048   if (db_disabled_) {
   1049     callback.Run(kQuotaErrorInvalidAccess, -1);
   1050     return;
   1051   }
   1052 
   1053   int64* new_quota_ptr = new int64(new_quota);
   1054   PostTaskAndReplyWithResultForDBThread(
   1055       FROM_HERE,
   1056       base::Bind(&SetPersistentHostQuotaOnDBThread,
   1057                  host,
   1058                  base::Unretained(new_quota_ptr)),
   1059       base::Bind(&QuotaManager::DidSetPersistentHostQuota,
   1060                  weak_factory_.GetWeakPtr(),
   1061                  host,
   1062                  callback,
   1063                  base::Owned(new_quota_ptr)));
   1064 }
   1065 
   1066 void QuotaManager::GetGlobalUsage(StorageType type,
   1067                                   const GlobalUsageCallback& callback) {
   1068   LazyInitialize();
   1069   GetUsageTracker(type)->GetGlobalUsage(callback);
   1070 }
   1071 
   1072 void QuotaManager::GetHostUsage(const std::string& host,
   1073                                 StorageType type,
   1074                                 const UsageCallback& callback) {
   1075   LazyInitialize();
   1076   GetUsageTracker(type)->GetHostUsage(host, callback);
   1077 }
   1078 
   1079 void QuotaManager::GetStatistics(
   1080     std::map<std::string, std::string>* statistics) {
   1081   DCHECK(statistics);
   1082   if (temporary_storage_evictor_) {
   1083     std::map<std::string, int64> stats;
   1084     temporary_storage_evictor_->GetStatistics(&stats);
   1085     for (std::map<std::string, int64>::iterator p = stats.begin();
   1086          p != stats.end();
   1087          ++p)
   1088       (*statistics)[p->first] = base::Int64ToString(p->second);
   1089   }
   1090 }
   1091 
   1092 bool QuotaManager::IsStorageUnlimited(const GURL& origin,
   1093                                       StorageType type) const {
   1094   // For syncable storage we should always enforce quota (since the
   1095   // quota must be capped by the server limit).
   1096   if (type == kStorageTypeSyncable)
   1097     return false;
   1098   return special_storage_policy_.get() &&
   1099           special_storage_policy_->IsStorageUnlimited(origin);
   1100 }
   1101 
   1102 void QuotaManager::GetOriginsModifiedSince(StorageType type,
   1103                                            base::Time modified_since,
   1104                                            const GetOriginsCallback& callback) {
   1105   LazyInitialize();
   1106   GetModifiedSinceHelper* helper = new GetModifiedSinceHelper;
   1107   PostTaskAndReplyWithResultForDBThread(
   1108       FROM_HERE,
   1109       base::Bind(&GetModifiedSinceHelper::GetModifiedSinceOnDBThread,
   1110                  base::Unretained(helper),
   1111                  type,
   1112                  modified_since),
   1113       base::Bind(&GetModifiedSinceHelper::DidGetModifiedSince,
   1114                  base::Owned(helper),
   1115                  weak_factory_.GetWeakPtr(),
   1116                  callback,
   1117                  type));
   1118 }
   1119 
   1120 bool QuotaManager::ResetUsageTracker(StorageType type) {
   1121   DCHECK(GetUsageTracker(type));
   1122   if (GetUsageTracker(type)->IsWorking())
   1123     return false;
   1124   switch (type) {
   1125     case kStorageTypeTemporary:
   1126       temporary_usage_tracker_.reset(new UsageTracker(
   1127           clients_, kStorageTypeTemporary, special_storage_policy_.get()));
   1128       return true;
   1129     case kStorageTypePersistent:
   1130       persistent_usage_tracker_.reset(new UsageTracker(
   1131           clients_, kStorageTypePersistent, special_storage_policy_.get()));
   1132       return true;
   1133     case kStorageTypeSyncable:
   1134       syncable_usage_tracker_.reset(new UsageTracker(
   1135           clients_, kStorageTypeSyncable, special_storage_policy_.get()));
   1136       return true;
   1137     default:
   1138       NOTREACHED();
   1139   }
   1140   return true;
   1141 }
   1142 
   1143 QuotaManager::~QuotaManager() {
   1144   proxy_->manager_ = NULL;
   1145   std::for_each(clients_.begin(), clients_.end(),
   1146                 std::mem_fun(&QuotaClient::OnQuotaManagerDestroyed));
   1147   if (database_)
   1148     db_thread_->DeleteSoon(FROM_HERE, database_.release());
   1149 }
   1150 
   1151 QuotaManager::EvictionContext::EvictionContext()
   1152     : evicted_type(kStorageTypeUnknown) {
   1153 }
   1154 
   1155 QuotaManager::EvictionContext::~EvictionContext() {
   1156 }
   1157 
   1158 void QuotaManager::LazyInitialize() {
   1159   DCHECK(io_thread_->BelongsToCurrentThread());
   1160   if (database_) {
   1161     // Initialization seems to be done already.
   1162     return;
   1163   }
   1164 
   1165   // Use an empty path to open an in-memory only databse for incognito.
   1166   database_.reset(new QuotaDatabase(is_incognito_ ? base::FilePath() :
   1167       profile_path_.AppendASCII(kDatabaseName)));
   1168 
   1169   temporary_usage_tracker_.reset(new UsageTracker(
   1170       clients_, kStorageTypeTemporary, special_storage_policy_.get()));
   1171   persistent_usage_tracker_.reset(new UsageTracker(
   1172       clients_, kStorageTypePersistent, special_storage_policy_.get()));
   1173   syncable_usage_tracker_.reset(new UsageTracker(
   1174       clients_, kStorageTypeSyncable, special_storage_policy_.get()));
   1175 
   1176   int64* temporary_quota_override = new int64(-1);
   1177   int64* desired_available_space = new int64(-1);
   1178   PostTaskAndReplyWithResultForDBThread(
   1179       FROM_HERE,
   1180       base::Bind(&InitializeOnDBThread,
   1181                  base::Unretained(temporary_quota_override),
   1182                  base::Unretained(desired_available_space)),
   1183       base::Bind(&QuotaManager::DidInitialize,
   1184                  weak_factory_.GetWeakPtr(),
   1185                  base::Owned(temporary_quota_override),
   1186                  base::Owned(desired_available_space)));
   1187 }
   1188 
   1189 void QuotaManager::RegisterClient(QuotaClient* client) {
   1190   DCHECK(!database_.get());
   1191   clients_.push_back(client);
   1192 }
   1193 
   1194 UsageTracker* QuotaManager::GetUsageTracker(StorageType type) const {
   1195   switch (type) {
   1196     case kStorageTypeTemporary:
   1197       return temporary_usage_tracker_.get();
   1198     case kStorageTypePersistent:
   1199       return persistent_usage_tracker_.get();
   1200     case kStorageTypeSyncable:
   1201       return syncable_usage_tracker_.get();
   1202     default:
   1203       NOTREACHED();
   1204   }
   1205   return NULL;
   1206 }
   1207 
   1208 void QuotaManager::GetCachedOrigins(
   1209     StorageType type, std::set<GURL>* origins) {
   1210   DCHECK(origins);
   1211   LazyInitialize();
   1212   DCHECK(GetUsageTracker(type));
   1213   GetUsageTracker(type)->GetCachedOrigins(origins);
   1214 }
   1215 
   1216 void QuotaManager::NotifyStorageAccessedInternal(
   1217     QuotaClient::ID client_id,
   1218     const GURL& origin, StorageType type,
   1219     base::Time accessed_time) {
   1220   LazyInitialize();
   1221   if (type == kStorageTypeTemporary && !lru_origin_callback_.is_null()) {
   1222     // Record the accessed origins while GetLRUOrigin task is runing
   1223     // to filter out them from eviction.
   1224     access_notified_origins_.insert(origin);
   1225   }
   1226 
   1227   if (db_disabled_)
   1228     return;
   1229   PostTaskAndReplyWithResultForDBThread(
   1230       FROM_HERE,
   1231       base::Bind(&UpdateAccessTimeOnDBThread, origin, type, accessed_time),
   1232       base::Bind(&QuotaManager::DidDatabaseWork,
   1233                  weak_factory_.GetWeakPtr()));
   1234 }
   1235 
   1236 void QuotaManager::NotifyStorageModifiedInternal(
   1237     QuotaClient::ID client_id,
   1238     const GURL& origin,
   1239     StorageType type,
   1240     int64 delta,
   1241     base::Time modified_time) {
   1242   LazyInitialize();
   1243   GetUsageTracker(type)->UpdateUsageCache(client_id, origin, delta);
   1244 
   1245   PostTaskAndReplyWithResultForDBThread(
   1246       FROM_HERE,
   1247       base::Bind(&UpdateModifiedTimeOnDBThread, origin, type, modified_time),
   1248       base::Bind(&QuotaManager::DidDatabaseWork,
   1249                  weak_factory_.GetWeakPtr()));
   1250 }
   1251 
   1252 void QuotaManager::DumpQuotaTable(const DumpQuotaTableCallback& callback) {
   1253   DumpQuotaTableHelper* helper = new DumpQuotaTableHelper;
   1254   PostTaskAndReplyWithResultForDBThread(
   1255       FROM_HERE,
   1256       base::Bind(&DumpQuotaTableHelper::DumpQuotaTableOnDBThread,
   1257                  base::Unretained(helper)),
   1258       base::Bind(&DumpQuotaTableHelper::DidDumpQuotaTable,
   1259                  base::Owned(helper),
   1260                  weak_factory_.GetWeakPtr(),
   1261                  callback));
   1262 }
   1263 
   1264 void QuotaManager::DumpOriginInfoTable(
   1265     const DumpOriginInfoTableCallback& callback) {
   1266   DumpOriginInfoTableHelper* helper = new DumpOriginInfoTableHelper;
   1267   PostTaskAndReplyWithResultForDBThread(
   1268       FROM_HERE,
   1269       base::Bind(&DumpOriginInfoTableHelper::DumpOriginInfoTableOnDBThread,
   1270                  base::Unretained(helper)),
   1271       base::Bind(&DumpOriginInfoTableHelper::DidDumpOriginInfoTable,
   1272                  base::Owned(helper),
   1273                  weak_factory_.GetWeakPtr(),
   1274                  callback));
   1275 }
   1276 
   1277 void QuotaManager::StartEviction() {
   1278   DCHECK(!temporary_storage_evictor_.get());
   1279   temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor(
   1280       this, kEvictionIntervalInMilliSeconds));
   1281   if (desired_available_space_ >= 0)
   1282     temporary_storage_evictor_->set_min_available_disk_space_to_start_eviction(
   1283         desired_available_space_);
   1284   temporary_storage_evictor_->Start();
   1285 }
   1286 
   1287 void QuotaManager::DeleteOriginFromDatabase(
   1288     const GURL& origin, StorageType type) {
   1289   LazyInitialize();
   1290   if (db_disabled_)
   1291     return;
   1292 
   1293   PostTaskAndReplyWithResultForDBThread(
   1294       FROM_HERE,
   1295       base::Bind(&DeleteOriginInfoOnDBThread, origin, type),
   1296       base::Bind(&QuotaManager::DidDatabaseWork,
   1297                  weak_factory_.GetWeakPtr()));
   1298 }
   1299 
   1300 void QuotaManager::DidOriginDataEvicted(QuotaStatusCode status) {
   1301   DCHECK(io_thread_->BelongsToCurrentThread());
   1302 
   1303   // We only try evict origins that are not in use, so basically
   1304   // deletion attempt for eviction should not fail.  Let's record
   1305   // the origin if we get error and exclude it from future eviction
   1306   // if the error happens consistently (> kThresholdOfErrorsToBeBlacklisted).
   1307   if (status != kQuotaStatusOk)
   1308     origins_in_error_[eviction_context_.evicted_origin]++;
   1309 
   1310   eviction_context_.evict_origin_data_callback.Run(status);
   1311   eviction_context_.evict_origin_data_callback.Reset();
   1312 }
   1313 
   1314 void QuotaManager::ReportHistogram() {
   1315   GetGlobalUsage(kStorageTypeTemporary,
   1316                  base::Bind(
   1317                      &QuotaManager::DidGetTemporaryGlobalUsageForHistogram,
   1318                      weak_factory_.GetWeakPtr()));
   1319   GetGlobalUsage(kStorageTypePersistent,
   1320                  base::Bind(
   1321                      &QuotaManager::DidGetPersistentGlobalUsageForHistogram,
   1322                      weak_factory_.GetWeakPtr()));
   1323 }
   1324 
   1325 void QuotaManager::DidGetTemporaryGlobalUsageForHistogram(
   1326     int64 usage,
   1327     int64 unlimited_usage) {
   1328   UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfTemporaryStorage", usage);
   1329 
   1330   std::set<GURL> origins;
   1331   GetCachedOrigins(kStorageTypeTemporary, &origins);
   1332 
   1333   size_t num_origins = origins.size();
   1334   size_t protected_origins = 0;
   1335   size_t unlimited_origins = 0;
   1336   CountOriginType(origins,
   1337                   special_storage_policy_.get(),
   1338                   &protected_origins,
   1339                   &unlimited_origins);
   1340 
   1341   UMA_HISTOGRAM_COUNTS("Quota.NumberOfTemporaryStorageOrigins",
   1342                        num_origins);
   1343   UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedTemporaryStorageOrigins",
   1344                        protected_origins);
   1345   UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedTemporaryStorageOrigins",
   1346                        unlimited_origins);
   1347 }
   1348 
   1349 void QuotaManager::DidGetPersistentGlobalUsageForHistogram(
   1350     int64 usage,
   1351     int64 unlimited_usage) {
   1352   UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfPersistentStorage", usage);
   1353 
   1354   std::set<GURL> origins;
   1355   GetCachedOrigins(kStorageTypePersistent, &origins);
   1356 
   1357   size_t num_origins = origins.size();
   1358   size_t protected_origins = 0;
   1359   size_t unlimited_origins = 0;
   1360   CountOriginType(origins,
   1361                   special_storage_policy_.get(),
   1362                   &protected_origins,
   1363                   &unlimited_origins);
   1364 
   1365   UMA_HISTOGRAM_COUNTS("Quota.NumberOfPersistentStorageOrigins",
   1366                        num_origins);
   1367   UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedPersistentStorageOrigins",
   1368                        protected_origins);
   1369   UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedPersistentStorageOrigins",
   1370                        unlimited_origins);
   1371 }
   1372 
   1373 void QuotaManager::GetLRUOrigin(
   1374     StorageType type,
   1375     const GetLRUOriginCallback& callback) {
   1376   LazyInitialize();
   1377   // This must not be called while there's an in-flight task.
   1378   DCHECK(lru_origin_callback_.is_null());
   1379   lru_origin_callback_ = callback;
   1380   if (db_disabled_) {
   1381     lru_origin_callback_.Run(GURL());
   1382     lru_origin_callback_.Reset();
   1383     return;
   1384   }
   1385 
   1386   std::set<GURL>* exceptions = new std::set<GURL>;
   1387   for (std::map<GURL, int>::const_iterator p = origins_in_use_.begin();
   1388        p != origins_in_use_.end();
   1389        ++p) {
   1390     if (p->second > 0)
   1391       exceptions->insert(p->first);
   1392   }
   1393   for (std::map<GURL, int>::const_iterator p = origins_in_error_.begin();
   1394        p != origins_in_error_.end();
   1395        ++p) {
   1396     if (p->second > QuotaManager::kThresholdOfErrorsToBeBlacklisted)
   1397       exceptions->insert(p->first);
   1398   }
   1399 
   1400   GURL* url = new GURL;
   1401   PostTaskAndReplyWithResultForDBThread(
   1402       FROM_HERE,
   1403       base::Bind(&GetLRUOriginOnDBThread,
   1404                  type,
   1405                  base::Owned(exceptions),
   1406                  special_storage_policy_,
   1407                  base::Unretained(url)),
   1408       base::Bind(&QuotaManager::DidGetLRUOrigin,
   1409                  weak_factory_.GetWeakPtr(),
   1410                  base::Owned(url)));
   1411 }
   1412 
   1413 void QuotaManager::EvictOriginData(
   1414     const GURL& origin,
   1415     StorageType type,
   1416     const EvictOriginDataCallback& callback) {
   1417   DCHECK(io_thread_->BelongsToCurrentThread());
   1418   DCHECK_EQ(type, kStorageTypeTemporary);
   1419 
   1420   eviction_context_.evicted_origin = origin;
   1421   eviction_context_.evicted_type = type;
   1422   eviction_context_.evict_origin_data_callback = callback;
   1423 
   1424   DeleteOriginData(origin, type, QuotaClient::kAllClientsMask,
   1425       base::Bind(&QuotaManager::DidOriginDataEvicted,
   1426                  weak_factory_.GetWeakPtr()));
   1427 }
   1428 
   1429 void QuotaManager::GetUsageAndQuotaForEviction(
   1430     const UsageAndQuotaCallback& callback) {
   1431   DCHECK(io_thread_->BelongsToCurrentThread());
   1432   LazyInitialize();
   1433 
   1434   UsageAndQuotaCallbackDispatcher* dispatcher =
   1435       new UsageAndQuotaCallbackDispatcher(this);
   1436   GetUsageTracker(kStorageTypeTemporary)->
   1437       GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback());
   1438   GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback());
   1439   GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
   1440   dispatcher->WaitForResults(callback);
   1441 }
   1442 
   1443 void QuotaManager::DidSetTemporaryGlobalOverrideQuota(
   1444     const QuotaCallback& callback,
   1445     const int64* new_quota,
   1446     bool success) {
   1447   QuotaStatusCode status = kQuotaErrorInvalidAccess;
   1448   DidDatabaseWork(success);
   1449   if (success) {
   1450     temporary_quota_override_ = *new_quota;
   1451     status = kQuotaStatusOk;
   1452   }
   1453 
   1454   if (callback.is_null())
   1455     return;
   1456 
   1457   callback.Run(status, *new_quota);
   1458 }
   1459 
   1460 void QuotaManager::DidGetPersistentHostQuota(const std::string& host,
   1461                                              const int64* quota,
   1462                                              bool success) {
   1463   DidDatabaseWork(success);
   1464   persistent_host_quota_callbacks_.Run(
   1465       host, MakeTuple(kQuotaStatusOk, *quota));
   1466 }
   1467 
   1468 void QuotaManager::DidSetPersistentHostQuota(const std::string& host,
   1469                                              const QuotaCallback& callback,
   1470                                              const int64* new_quota,
   1471                                              bool success) {
   1472   DidDatabaseWork(success);
   1473   callback.Run(success ? kQuotaStatusOk : kQuotaErrorInvalidAccess, *new_quota);
   1474 }
   1475 
   1476 void QuotaManager::DidInitialize(int64* temporary_quota_override,
   1477                                  int64* desired_available_space,
   1478                                  bool success) {
   1479   temporary_quota_override_ = *temporary_quota_override;
   1480   desired_available_space_ = *desired_available_space;
   1481   temporary_quota_initialized_ = true;
   1482   DidDatabaseWork(success);
   1483 
   1484   histogram_timer_.Start(FROM_HERE,
   1485                          base::TimeDelta::FromMilliseconds(
   1486                              kReportHistogramInterval),
   1487                          this, &QuotaManager::ReportHistogram);
   1488 
   1489   db_initialization_callbacks_.Run(MakeTuple());
   1490   GetTemporaryGlobalQuota(
   1491       base::Bind(&QuotaManager::DidGetInitialTemporaryGlobalQuota,
   1492                  weak_factory_.GetWeakPtr()));
   1493 }
   1494 
   1495 void QuotaManager::DidGetLRUOrigin(const GURL* origin,
   1496                                    bool success) {
   1497   DidDatabaseWork(success);
   1498   // Make sure the returned origin is (still) not in the origin_in_use_ set
   1499   // and has not been accessed since we posted the task.
   1500   if (origins_in_use_.find(*origin) != origins_in_use_.end() ||
   1501       access_notified_origins_.find(*origin) != access_notified_origins_.end())
   1502     lru_origin_callback_.Run(GURL());
   1503   else
   1504     lru_origin_callback_.Run(*origin);
   1505   access_notified_origins_.clear();
   1506   lru_origin_callback_.Reset();
   1507 }
   1508 
   1509 void QuotaManager::DidGetInitialTemporaryGlobalQuota(
   1510     QuotaStatusCode status, int64 quota_unused) {
   1511   if (eviction_disabled_)
   1512     return;
   1513 
   1514   std::set<GURL>* origins = new std::set<GURL>;
   1515   temporary_usage_tracker_->GetCachedOrigins(origins);
   1516   // This will call the StartEviction() when initial origin registration
   1517   // is completed.
   1518   PostTaskAndReplyWithResultForDBThread(
   1519       FROM_HERE,
   1520       base::Bind(&InitializeTemporaryOriginsInfoOnDBThread,
   1521                  base::Owned(origins)),
   1522       base::Bind(&QuotaManager::DidInitializeTemporaryOriginsInfo,
   1523                  weak_factory_.GetWeakPtr()));
   1524 }
   1525 
   1526 void QuotaManager::DidInitializeTemporaryOriginsInfo(bool success) {
   1527   DidDatabaseWork(success);
   1528   if (success)
   1529     StartEviction();
   1530 }
   1531 
   1532 void QuotaManager::DidGetAvailableSpace(int64 space) {
   1533   available_space_callbacks_.Run(MakeTuple(kQuotaStatusOk, space));
   1534 }
   1535 
   1536 void QuotaManager::DidDatabaseWork(bool success) {
   1537   db_disabled_ = !success;
   1538 }
   1539 
   1540 void QuotaManager::DeleteOnCorrectThread() const {
   1541   if (!io_thread_->BelongsToCurrentThread() &&
   1542       io_thread_->DeleteSoon(FROM_HERE, this)) {
   1543     return;
   1544   }
   1545   delete this;
   1546 }
   1547 
   1548 void QuotaManager::PostTaskAndReplyWithResultForDBThread(
   1549     const tracked_objects::Location& from_here,
   1550     const base::Callback<bool(QuotaDatabase*)>& task,
   1551     const base::Callback<void(bool)>& reply) {
   1552   // Deleting manager will post another task to DB thread to delete
   1553   // |database_|, therefore we can be sure that database_ is alive when this
   1554   // task runs.
   1555   base::PostTaskAndReplyWithResult(
   1556       db_thread_.get(),
   1557       from_here,
   1558       base::Bind(task, base::Unretained(database_.get())),
   1559       reply);
   1560 }
   1561 
   1562 // QuotaManagerProxy ----------------------------------------------------------
   1563 
   1564 void QuotaManagerProxy::RegisterClient(QuotaClient* client) {
   1565   if (!io_thread_->BelongsToCurrentThread() &&
   1566       io_thread_->PostTask(
   1567           FROM_HERE,
   1568           base::Bind(&QuotaManagerProxy::RegisterClient, this, client))) {
   1569     return;
   1570   }
   1571 
   1572   if (manager_)
   1573     manager_->RegisterClient(client);
   1574   else
   1575     client->OnQuotaManagerDestroyed();
   1576 }
   1577 
   1578 void QuotaManagerProxy::NotifyStorageAccessed(
   1579     QuotaClient::ID client_id,
   1580     const GURL& origin,
   1581     StorageType type) {
   1582   if (!io_thread_->BelongsToCurrentThread()) {
   1583     io_thread_->PostTask(
   1584         FROM_HERE,
   1585         base::Bind(&QuotaManagerProxy::NotifyStorageAccessed, this, client_id,
   1586                    origin, type));
   1587     return;
   1588   }
   1589 
   1590   if (manager_)
   1591     manager_->NotifyStorageAccessed(client_id, origin, type);
   1592 }
   1593 
   1594 void QuotaManagerProxy::NotifyStorageModified(
   1595     QuotaClient::ID client_id,
   1596     const GURL& origin,
   1597     StorageType type,
   1598     int64 delta) {
   1599   if (!io_thread_->BelongsToCurrentThread()) {
   1600     io_thread_->PostTask(
   1601         FROM_HERE,
   1602         base::Bind(&QuotaManagerProxy::NotifyStorageModified, this, client_id,
   1603                    origin, type, delta));
   1604     return;
   1605   }
   1606 
   1607   if (manager_)
   1608     manager_->NotifyStorageModified(client_id, origin, type, delta);
   1609 }
   1610 
   1611 void QuotaManagerProxy::NotifyOriginInUse(
   1612     const GURL& origin) {
   1613   if (!io_thread_->BelongsToCurrentThread()) {
   1614     io_thread_->PostTask(
   1615         FROM_HERE,
   1616         base::Bind(&QuotaManagerProxy::NotifyOriginInUse, this, origin));
   1617     return;
   1618   }
   1619 
   1620   if (manager_)
   1621     manager_->NotifyOriginInUse(origin);
   1622 }
   1623 
   1624 void QuotaManagerProxy::NotifyOriginNoLongerInUse(
   1625     const GURL& origin) {
   1626   if (!io_thread_->BelongsToCurrentThread()) {
   1627     io_thread_->PostTask(
   1628         FROM_HERE,
   1629         base::Bind(&QuotaManagerProxy::NotifyOriginNoLongerInUse, this,
   1630                    origin));
   1631     return;
   1632   }
   1633   if (manager_)
   1634     manager_->NotifyOriginNoLongerInUse(origin);
   1635 }
   1636 
   1637 void QuotaManagerProxy::SetUsageCacheEnabled(QuotaClient::ID client_id,
   1638                                              const GURL& origin,
   1639                                              StorageType type,
   1640                                              bool enabled) {
   1641   if (!io_thread_->BelongsToCurrentThread()) {
   1642     io_thread_->PostTask(
   1643         FROM_HERE,
   1644         base::Bind(&QuotaManagerProxy::SetUsageCacheEnabled, this,
   1645                    client_id, origin, type, enabled));
   1646     return;
   1647   }
   1648   if (manager_)
   1649     manager_->SetUsageCacheEnabled(client_id, origin, type, enabled);
   1650 }
   1651 
   1652 QuotaManager* QuotaManagerProxy::quota_manager() const {
   1653   DCHECK(!io_thread_.get() || io_thread_->BelongsToCurrentThread());
   1654   return manager_;
   1655 }
   1656 
   1657 QuotaManagerProxy::QuotaManagerProxy(
   1658     QuotaManager* manager, base::SingleThreadTaskRunner* io_thread)
   1659     : manager_(manager), io_thread_(io_thread) {
   1660 }
   1661 
   1662 QuotaManagerProxy::~QuotaManagerProxy() {
   1663 }
   1664 
   1665 }  // namespace quota
   1666