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