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