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