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