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