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
38namespace storage {
39
40namespace {
41
42const int64 kMBytes = 1024 * 1024;
43const int kMinutesInMilliSeconds = 60 * 1000;
44
45const int64 kReportHistogramInterval = 60 * 60 * 1000;  // 1 hour
46const 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.
53const int64 QuotaManager::kIncognitoDefaultQuotaLimit = 100 * kMBytes;
54
55const int64 QuotaManager::kNoLimit = kint64max;
56
57const 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.
63const int64 QuotaManager::kPerHostPersistentQuotaLimit = 10 * 1024 * kMBytes;
64
65const char QuotaManager::kDatabaseName[] = "QuotaManager";
66
67const 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)
74int64 QuotaManager::kMinimumPreserveForSystem = 1024 * kMBytes;
75
76const 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.
82int64 QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes;
83
84namespace {
85
86void 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
106bool 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
117bool 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
125bool 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
135bool 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
146bool 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
156bool DeleteOriginInfoOnDBThread(const GURL& origin,
157                                StorageType type,
158                                QuotaDatabase* database) {
159  DCHECK(database);
160  return database->DeleteOriginInfo(origin, type);
161}
162
163bool 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
177bool 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
185bool 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
193int64 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
202int64 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
215void 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
229int64 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
250int64 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
260void 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
305UsageAndQuota::UsageAndQuota()
306    : usage(0),
307      global_limited_usage(0),
308      quota(0),
309      available_disk_space(0) {
310}
311
312UsageAndQuota::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
323class 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
466class 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
534class 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
614class 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
713class 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
739class 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
768class 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
800QuotaManager::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
822void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) {
823  LazyInitialize();
824  GetUsageInfoTask* get_usage_info = new GetUsageInfoTask(this, callback);
825  get_usage_info->Start();
826}
827
828void 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
877void 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
890void 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
897void 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
905void QuotaManager::NotifyOriginInUse(const GURL& origin) {
906  DCHECK(io_thread_->BelongsToCurrentThread());
907  origins_in_use_[origin]++;
908}
909
910void 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
918void 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
927void 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
943void 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
959void 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
970void 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
993void 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
1020void 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
1046void 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
1084void QuotaManager::GetGlobalUsage(StorageType type,
1085                                  const GlobalUsageCallback& callback) {
1086  LazyInitialize();
1087  DCHECK(GetUsageTracker(type));
1088  GetUsageTracker(type)->GetGlobalUsage(callback);
1089}
1090
1091void 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
1099void 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
1114bool QuotaManager::IsTrackingHostUsage(StorageType type,
1115                                       QuotaClient::ID client_id) const {
1116  UsageTracker* tracker = GetUsageTracker(type);
1117  return tracker && tracker->GetClientTracker(client_id);
1118}
1119
1120void 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
1133bool 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
1145void 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
1163bool 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
1189void QuotaManager::AddStorageObserver(
1190    StorageObserver* observer, const StorageObserver::MonitorParams& params) {
1191  DCHECK(observer);
1192  storage_monitor_->AddObserver(observer, params);
1193}
1194
1195void QuotaManager::RemoveStorageObserver(StorageObserver* observer) {
1196  DCHECK(observer);
1197  storage_monitor_->RemoveObserver(observer);
1198}
1199
1200void QuotaManager::RemoveStorageObserverForFilter(
1201    StorageObserver* observer, const StorageObserver::Filter& filter) {
1202  DCHECK(observer);
1203  storage_monitor_->RemoveObserverForFilter(observer, filter);
1204}
1205
1206QuotaManager::~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
1214QuotaManager::EvictionContext::EvictionContext()
1215    : evicted_type(kStorageTypeUnknown) {
1216}
1217
1218QuotaManager::EvictionContext::~EvictionContext() {
1219}
1220
1221void 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
1255void QuotaManager::RegisterClient(QuotaClient* client) {
1256  DCHECK(!database_.get());
1257  clients_.push_back(client);
1258}
1259
1260UsageTracker* 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
1276void 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
1284void 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
1304void 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
1321void 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
1333void 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
1346void 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
1356void 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
1369void 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
1383void 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
1394void 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
1418void 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
1442void 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
1482void 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
1498void 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
1512void 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
1529void 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
1537void 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
1545void 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
1564void 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
1578void 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
1595void QuotaManager::DidInitializeTemporaryOriginsInfo(bool success) {
1596  DidDatabaseWork(success);
1597  if (success)
1598    StartEviction();
1599}
1600
1601void QuotaManager::DidGetAvailableSpace(int64 space) {
1602  available_space_callbacks_.Run(MakeTuple(kQuotaStatusOk, space));
1603}
1604
1605void QuotaManager::DidDatabaseWork(bool success) {
1606  db_disabled_ = !success;
1607}
1608
1609void QuotaManager::DeleteOnCorrectThread() const {
1610  if (!io_thread_->BelongsToCurrentThread() &&
1611      io_thread_->DeleteSoon(FROM_HERE, this)) {
1612    return;
1613  }
1614  delete this;
1615}
1616
1617void QuotaManager::PostTaskAndReplyWithResultForDBThread(
1618    const tracked_objects::Location& from_here,
1619    const base::Callback<bool(QuotaDatabase*)>& task,
1620    const base::Callback<void(bool)>& reply) {
1621  // Deleting manager will post another task to DB thread to delete
1622  // |database_|, therefore we can be sure that database_ is alive when this
1623  // task runs.
1624  base::PostTaskAndReplyWithResult(
1625      db_thread_.get(),
1626      from_here,
1627      base::Bind(task, base::Unretained(database_.get())),
1628      reply);
1629}
1630
1631}  // namespace storage
1632