Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(247)

Side by Side Diff: webkit/browser/quota/quota_manager.cc

Issue 539143002: Migrate webkit/browser/ to storage/browser/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix android build Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webkit/browser/quota/quota_manager.h ('k') | webkit/browser/quota/quota_manager_proxy.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "webkit/browser/quota/quota_manager.h"
6
7 #include <algorithm>
8 #include <deque>
9 #include <functional>
10 #include <set>
11
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/command_line.h"
16 #include "base/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 "webkit/browser/quota/quota_database.h"
27 #include "webkit/browser/quota/quota_manager_proxy.h"
28 #include "webkit/browser/quota/quota_temporary_storage_evictor.h"
29 #include "webkit/browser/quota/storage_monitor.h"
30 #include "webkit/browser/quota/usage_tracker.h"
31 #include "webkit/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
OLDNEW
« no previous file with comments | « webkit/browser/quota/quota_manager.h ('k') | webkit/browser/quota/quota_manager_proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698