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

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

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

Powered by Google App Engine
This is Rietveld 408576698