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

Side by Side Diff: chrome/browser/history/expire_history_backend.cc

Issue 113591: Fix Acid3 Test 48: LINKTEST, Chromium side.... (Closed) Base URL: svn://chrome-svn.corp.google.com/chrome/trunk/src/
Patch Set: Made waiting more bearable. Created 11 years, 5 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
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/history/expire_history_backend.h" 5 #include "chrome/browser/history/expire_history_backend.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 9
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/file_util.h" 11 #include "base/file_util.h"
12 #include "chrome/browser/bookmarks/bookmark_service.h" 12 #include "chrome/browser/bookmarks/bookmark_service.h"
13 #include "chrome/browser/history/archived_database.h" 13 #include "chrome/browser/history/archived_database.h"
14 #include "chrome/browser/history/history_database.h" 14 #include "chrome/browser/history/history_database.h"
15 #include "chrome/browser/history/history_notifications.h" 15 #include "chrome/browser/history/history_notifications.h"
16 #include "chrome/browser/history/text_database_manager.h" 16 #include "chrome/browser/history/text_database_manager.h"
17 #include "chrome/browser/history/thumbnail_database.h" 17 #include "chrome/browser/history/thumbnail_database.h"
18 #include "chrome/common/notification_type.h" 18 #include "chrome/common/notification_type.h"
19 19
20 using base::Time; 20 using base::Time;
21 using base::TimeDelta; 21 using base::TimeDelta;
22 22
23 namespace history { 23 namespace history {
24 24
25 namespace { 25 namespace {
26 26
27 // The number of days by which the expiration threshold is advanced for items
28 // that we want to expire early, such as those of AUTO_SUBFRAME transition type.
29 const int kEarlyExpirationAdvanceDays = 30;
30
31 // Reads all types of visits starting from beginning of time to the given end
32 // time. This is the most general reader.
33 class AllVisitsReader : public ExpiringVisitsReader {
34 public:
35 virtual bool Read(Time end_time, HistoryDatabase* db,
36 VisitVector* visits, int max_visits) const {
37 DCHECK(db) << "must have a database to operate upon";
38 DCHECK(visits) << "visit vector has to exist in order to populate it";
39
40 db->GetAllVisitsInRange(Time(), end_time, max_visits, visits);
41 // When we got the maximum number of visits we asked for, we say there could
42 // be additional things to expire now.
43 return static_cast<int>(visits->size()) == max_visits;
44 }
45 };
46
47 // Reads only AUTO_SUBFRAME visits, within a computed range. The range is
48 // computed as follows:
49 // * |begin_time| is read from the meta table. This value is updated whenever
50 // there are no more additional visits to expire by this reader.
51 // * |end_time| is advanced forward by a constant (kEarlyExpirationAdvanceDay),
52 // but not past the current time.
53 class AutoSubframeVisitsReader : public ExpiringVisitsReader {
54 public:
55 virtual bool Read(Time end_time, HistoryDatabase* db,
56 VisitVector* visits, int max_visits) const {
57 DCHECK(db) << "must have a database to operate upon";
58 DCHECK(visits) << "visit vector has to exist in order to populate it";
59
60 Time begin_time = db->GetEarlyExpirationThreshold();
61 // Advance |end_time| to expire early.
62 Time early_end_time = end_time +
63 TimeDelta::FromDays(kEarlyExpirationAdvanceDays);
64
65 // We don't want to set the early expiration threshold to a time in the
66 // future.
67 Time now = Time::Now();
68 if (early_end_time > now)
69 early_end_time = now;
70
71 db->GetVisitsInRangeForTransition(begin_time, early_end_time,
72 max_visits,
73 PageTransition::AUTO_SUBFRAME,
74 visits);
75 bool more = static_cast<int>(visits->size()) == max_visits;
76 if (!more)
77 db->UpdateEarlyExpirationThreshold(early_end_time);
78
79 return more;
80 }
81 };
82
27 // Returns true if this visit is worth archiving. Otherwise, this visit is not 83 // Returns true if this visit is worth archiving. Otherwise, this visit is not
28 // worth saving (for example, subframe navigations and redirects) and we can 84 // worth saving (for example, subframe navigations and redirects) and we can
29 // just delete it when it gets old. 85 // just delete it when it gets old.
30 bool ShouldArchiveVisit(const VisitRow& visit) { 86 bool ShouldArchiveVisit(const VisitRow& visit) {
31 int no_qualifier = PageTransition::StripQualifier(visit.transition); 87 int no_qualifier = PageTransition::StripQualifier(visit.transition);
32 88
33 // These types of transitions are always "important" and the user will want 89 // These types of transitions are always "important" and the user will want
34 // to see them. 90 // to see them.
35 if (no_qualifier == PageTransition::TYPED || 91 if (no_qualifier == PageTransition::TYPED ||
36 no_qualifier == PageTransition::AUTO_BOOKMARK || 92 no_qualifier == PageTransition::AUTO_BOOKMARK ||
(...skipping 14 matching lines...) Expand all
51 } 107 }
52 108
53 // The number of visits we will expire very time we check for old items. This 109 // The number of visits we will expire very time we check for old items. This
54 // Prevents us from doing too much work any given time. 110 // Prevents us from doing too much work any given time.
55 const int kNumExpirePerIteration = 10; 111 const int kNumExpirePerIteration = 10;
56 112
57 // The number of seconds between checking for items that should be expired when 113 // The number of seconds between checking for items that should be expired when
58 // we think there might be more items to expire. This timeout is used when the 114 // we think there might be more items to expire. This timeout is used when the
59 // last expiration found at least kNumExpirePerIteration and we want to check 115 // last expiration found at least kNumExpirePerIteration and we want to check
60 // again "soon." 116 // again "soon."
61 const int kExpirationDelaySec = 60; 117 const int kExpirationDelaySec = 30;
62 118
63 // The number of minutes between checking, as with kExpirationDelaySec, but 119 // The number of minutes between checking, as with kExpirationDelaySec, but
64 // when we didn't find enough things to expire last time. If there was no 120 // when we didn't find enough things to expire last time. If there was no
65 // history to expire last iteration, it's likely there is nothing next 121 // history to expire last iteration, it's likely there is nothing next
66 // iteration, so we want to wait longer before checking to avoid wasting CPU. 122 // iteration, so we want to wait longer before checking to avoid wasting CPU.
67 const int kExpirationEmptyDelayMin = 5; 123 const int kExpirationEmptyDelayMin = 5;
68 124
69 } // namespace 125 } // namespace
70 126
71 ExpireHistoryBackend::ExpireHistoryBackend( 127 ExpireHistoryBackend::ExpireHistoryBackend(
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 215
160 // Pick up any bits possibly left over. 216 // Pick up any bits possibly left over.
161 ParanoidExpireHistory(); 217 ParanoidExpireHistory();
162 } 218 }
163 219
164 void ExpireHistoryBackend::ArchiveHistoryBefore(Time end_time) { 220 void ExpireHistoryBackend::ArchiveHistoryBefore(Time end_time) {
165 if (!main_db_) 221 if (!main_db_)
166 return; 222 return;
167 223
168 // Archive as much history as possible before the given date. 224 // Archive as much history as possible before the given date.
169 ArchiveSomeOldHistory(end_time, std::numeric_limits<size_t>::max()); 225 ArchiveSomeOldHistory(end_time, GetAllVisitsReader(),
226 std::numeric_limits<size_t>::max());
170 ParanoidExpireHistory(); 227 ParanoidExpireHistory();
171 } 228 }
172 229
230 void ExpireHistoryBackend::InitWorkQueue() {
231 DCHECK(work_queue_.empty()) << "queue has to be empty prior to init";
232
233 for (size_t i = 0; i < readers_.size(); i++)
234 work_queue_.push(readers_[i]);
235 }
236
237 const ExpiringVisitsReader* ExpireHistoryBackend::GetAllVisitsReader() {
238 if (!all_visits_reader_.get())
239 all_visits_reader_.reset(new AllVisitsReader());
240 return all_visits_reader_.get();
241 }
242
243 const ExpiringVisitsReader*
244 ExpireHistoryBackend::GetAutoSubframeVisitsReader() {
245 if (!auto_subframe_visits_reader_.get())
246 auto_subframe_visits_reader_.reset(new AutoSubframeVisitsReader());
247 return auto_subframe_visits_reader_.get();
248 }
249
173 void ExpireHistoryBackend::StartArchivingOldStuff( 250 void ExpireHistoryBackend::StartArchivingOldStuff(
174 TimeDelta expiration_threshold) { 251 TimeDelta expiration_threshold) {
175 expiration_threshold_ = expiration_threshold; 252 expiration_threshold_ = expiration_threshold;
176 ScheduleArchive(TimeDelta::FromSeconds(kExpirationDelaySec)); 253
254 // Remove all readers, just in case this was method was called before.
255 readers_.clear();
256 // For now, we explicitly add all known readers. If we come up with more
257 // reader types (in case we want to expire different types of visits in
258 // different ways), we can make it be populated by creator/owner of
259 // ExpireHistoryBackend.
260 readers_.push_back(GetAllVisitsReader());
261 readers_.push_back(GetAutoSubframeVisitsReader());
262
263 // Initialize the queue with all tasks for the first set of iterations.
264 InitWorkQueue();
265 ScheduleArchive();
177 } 266 }
178 267
179 void ExpireHistoryBackend::DeleteFaviconsIfPossible( 268 void ExpireHistoryBackend::DeleteFaviconsIfPossible(
180 const std::set<FavIconID>& favicon_set) { 269 const std::set<FavIconID>& favicon_set) {
181 if (!main_db_ || !thumb_db_) 270 if (!main_db_ || !thumb_db_)
182 return; 271 return;
183 272
184 for (std::set<FavIconID>::const_iterator i = favicon_set.begin(); 273 for (std::set<FavIconID>::const_iterator i = favicon_set.begin();
185 i != favicon_set.end(); ++i) { 274 i != favicon_set.end(); ++i) {
186 if (!main_db_->IsFavIconUsed(*i)) 275 if (!main_db_->IsFavIconUsed(*i))
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 // not store referring visits since we delete many of the visits when 495 // not store referring visits since we delete many of the visits when
407 // archiving. 496 // archiving.
408 VisitRow cur_visit(visits[i]); 497 VisitRow cur_visit(visits[i]);
409 cur_visit.url_id = main_id_to_archived_id[cur_visit.url_id]; 498 cur_visit.url_id = main_id_to_archived_id[cur_visit.url_id];
410 cur_visit.referring_visit = 0; 499 cur_visit.referring_visit = 0;
411 archived_db_->AddVisit(&cur_visit); 500 archived_db_->AddVisit(&cur_visit);
412 // Ignore failures, we will delete it from the main DB no matter what. 501 // Ignore failures, we will delete it from the main DB no matter what.
413 } 502 }
414 } 503 }
415 504
416 void ExpireHistoryBackend::ScheduleArchive(TimeDelta delay) { 505 void ExpireHistoryBackend::ScheduleArchive() {
506 TimeDelta delay;
507 if (work_queue_.empty()) {
508 // If work queue is empty, reset the work queue to contain all tasks and
509 // schedule next iteration after a longer delay.
510 InitWorkQueue();
511 delay = TimeDelta::FromMinutes(kExpirationEmptyDelayMin);
512 } else {
513 delay = TimeDelta::FromSeconds(kExpirationDelaySec);
514 }
515
417 factory_.RevokeAll(); 516 factory_.RevokeAll();
418 MessageLoop::current()->PostDelayedTask(FROM_HERE, factory_.NewRunnableMethod( 517 MessageLoop::current()->PostDelayedTask(FROM_HERE, factory_.NewRunnableMethod(
419 &ExpireHistoryBackend::DoArchiveIteration), delay.InMilliseconds()); 518 &ExpireHistoryBackend::DoArchiveIteration), delay.InMilliseconds());
420 } 519 }
421 520
422 void ExpireHistoryBackend::DoArchiveIteration() { 521 void ExpireHistoryBackend::DoArchiveIteration() {
423 DCHECK(expiration_threshold_ != TimeDelta()) << "threshold should be set"; 522 DCHECK(!work_queue_.empty()) << "queue has to be non-empty";
424 Time threshold = Time::Now() - expiration_threshold_;
425 523
426 if (ArchiveSomeOldHistory(threshold, kNumExpirePerIteration)) { 524 const ExpiringVisitsReader* reader = work_queue_.front();
427 // Possibly more items to delete now, schedule it sooner to happen again. 525 bool more_to_expire = ArchiveSomeOldHistory(GetCurrentArchiveTime(), reader,
428 ScheduleArchive(TimeDelta::FromSeconds(kExpirationDelaySec)); 526 kNumExpirePerIteration);
429 } else { 527
430 // If we didn't find the maximum number of items to delete, wait longer 528 work_queue_.pop();
431 // before trying to delete more later. 529 // If there are more items to expire, add the reader back to the queue, thus
432 ScheduleArchive(TimeDelta::FromMinutes(kExpirationEmptyDelayMin)); 530 // creating a new task for future iterations.
433 } 531 if (more_to_expire)
532 work_queue_.push(reader);
533
534 ScheduleArchive();
434 } 535 }
435 536
436 bool ExpireHistoryBackend::ArchiveSomeOldHistory(Time time_threshold, 537 bool ExpireHistoryBackend::ArchiveSomeOldHistory(
437 int max_visits) { 538 base::Time end_time,
539 const ExpiringVisitsReader* reader,
540 int max_visits) {
438 if (!main_db_) 541 if (!main_db_)
439 return false; 542 return false;
440 543
441 // Get all visits up to and including the threshold. This is a little tricky 544 // Add an extra time unit to given end time, because
442 // because GetAllVisitsInRange's end value is non-inclusive, so we have to 545 // GetAllVisitsInRange, et al. queries' end value is non-inclusive.
443 // increment the time by one unit to get the input value to be inclusive. 546 Time effective_end_time =
444 DCHECK(!time_threshold.is_null()); 547 Time::FromInternalValue(end_time.ToInternalValue() + 1);
445 Time effective_threshold = 548
446 Time::FromInternalValue(time_threshold.ToInternalValue() + 1);
447 VisitVector affected_visits; 549 VisitVector affected_visits;
448 main_db_->GetAllVisitsInRange(Time(), effective_threshold, max_visits, 550 bool more_to_expire = reader->Read(effective_end_time, main_db_,
449 &affected_visits); 551 &affected_visits, max_visits);
450 552
451 // Some visits we'll delete while others we'll archive. 553 // Some visits we'll delete while others we'll archive.
452 VisitVector deleted_visits, archived_visits; 554 VisitVector deleted_visits, archived_visits;
453 for (size_t i = 0; i < affected_visits.size(); i++) { 555 for (size_t i = 0; i < affected_visits.size(); i++) {
454 if (ShouldArchiveVisit(affected_visits[i])) 556 if (ShouldArchiveVisit(affected_visits[i]))
455 archived_visits.push_back(affected_visits[i]); 557 archived_visits.push_back(affected_visits[i]);
456 else 558 else
457 deleted_visits.push_back(affected_visits[i]); 559 deleted_visits.push_back(affected_visits[i]);
458 } 560 }
459 561
(...skipping 22 matching lines...) Expand all
482 affected_favicons.insert(*i); 584 affected_favicons.insert(*i);
483 } 585 }
484 DeleteFaviconsIfPossible(affected_favicons); 586 DeleteFaviconsIfPossible(affected_favicons);
485 587
486 // Send notifications for the stuff that was deleted. These won't normally be 588 // Send notifications for the stuff that was deleted. These won't normally be
487 // in history views since they were subframes, but they will be in the visited 589 // in history views since they were subframes, but they will be in the visited
488 // link system, which needs to be updated now. This function is smart enough 590 // link system, which needs to be updated now. This function is smart enough
489 // to not do anything if nothing was deleted. 591 // to not do anything if nothing was deleted.
490 BroadcastDeleteNotifications(&deleted_dependencies); 592 BroadcastDeleteNotifications(&deleted_dependencies);
491 593
492 // When we got the maximum number of visits we asked for, we say there could 594 return more_to_expire;
493 // be additional things to expire now.
494 return static_cast<int>(affected_visits.size()) == max_visits;
495 } 595 }
496 596
497 void ExpireHistoryBackend::ParanoidExpireHistory() { 597 void ExpireHistoryBackend::ParanoidExpireHistory() {
498 // FIXME(brettw): Bug 1067331: write this to clean up any errors. 598 // FIXME(brettw): Bug 1067331: write this to clean up any errors.
499 } 599 }
500 600
501 BookmarkService* ExpireHistoryBackend::GetBookmarkService() { 601 BookmarkService* ExpireHistoryBackend::GetBookmarkService() {
502 // We use the bookmark service to determine if a URL is bookmarked. The 602 // We use the bookmark service to determine if a URL is bookmarked. The
503 // bookmark service is loaded on a separate thread and may not be done by the 603 // bookmark service is loaded on a separate thread and may not be done by the
504 // time we get here. We therefor block until the bookmarks have finished 604 // time we get here. We therefor block until the bookmarks have finished
505 // loading. 605 // loading.
506 if (bookmark_service_) 606 if (bookmark_service_)
507 bookmark_service_->BlockTillLoaded(); 607 bookmark_service_->BlockTillLoaded();
508 return bookmark_service_; 608 return bookmark_service_;
509 } 609 }
510 610
511 } // namespace history 611 } // namespace history
OLDNEW
« no previous file with comments | « chrome/browser/history/expire_history_backend.h ('k') | chrome/browser/history/expire_history_backend_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698