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

Unified 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, 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/history/expire_history_backend.cc
===================================================================
--- chrome/browser/history/expire_history_backend.cc (revision 19822)
+++ chrome/browser/history/expire_history_backend.cc (working copy)
@@ -24,6 +24,62 @@
namespace {
+// The number of days by which the expiration threshold is advanced for items
+// that we want to expire early, such as those of AUTO_SUBFRAME transition type.
+const int kEarlyExpirationAdvanceDays = 30;
+
+// Reads all types of visits starting from beginning of time to the given end
+// time. This is the most general reader.
+class AllVisitsReader : public ExpiringVisitsReader {
+ public:
+ virtual bool Read(Time end_time, HistoryDatabase* db,
+ VisitVector* visits, int max_visits) const {
+ DCHECK(db) << "must have a database to operate upon";
+ DCHECK(visits) << "visit vector has to exist in order to populate it";
+
+ db->GetAllVisitsInRange(Time(), end_time, max_visits, visits);
+ // When we got the maximum number of visits we asked for, we say there could
+ // be additional things to expire now.
+ return static_cast<int>(visits->size()) == max_visits;
+ }
+};
+
+// Reads only AUTO_SUBFRAME visits, within a computed range. The range is
+// computed as follows:
+// * |begin_time| is read from the meta table. This value is updated whenever
+// there are no more additional visits to expire by this reader.
+// * |end_time| is advanced forward by a constant (kEarlyExpirationAdvanceDay),
+// but not past the current time.
+class AutoSubframeVisitsReader : public ExpiringVisitsReader {
+ public:
+ virtual bool Read(Time end_time, HistoryDatabase* db,
+ VisitVector* visits, int max_visits) const {
+ DCHECK(db) << "must have a database to operate upon";
+ DCHECK(visits) << "visit vector has to exist in order to populate it";
+
+ Time begin_time = db->GetEarlyExpirationThreshold();
+ // Advance |end_time| to expire early.
+ Time early_end_time = end_time +
+ TimeDelta::FromDays(kEarlyExpirationAdvanceDays);
+
+ // We don't want to set the early expiration threshold to a time in the
+ // future.
+ Time now = Time::Now();
+ if (early_end_time > now)
+ early_end_time = now;
+
+ db->GetVisitsInRangeForTransition(begin_time, early_end_time,
+ max_visits,
+ PageTransition::AUTO_SUBFRAME,
+ visits);
+ bool more = static_cast<int>(visits->size()) == max_visits;
+ if (!more)
+ db->UpdateEarlyExpirationThreshold(early_end_time);
+
+ return more;
+ }
+};
+
// Returns true if this visit is worth archiving. Otherwise, this visit is not
// worth saving (for example, subframe navigations and redirects) and we can
// just delete it when it gets old.
@@ -58,7 +114,7 @@
// we think there might be more items to expire. This timeout is used when the
// last expiration found at least kNumExpirePerIteration and we want to check
// again "soon."
-const int kExpirationDelaySec = 60;
+const int kExpirationDelaySec = 30;
// The number of minutes between checking, as with kExpirationDelaySec, but
// when we didn't find enough things to expire last time. If there was no
@@ -166,14 +222,47 @@
return;
// Archive as much history as possible before the given date.
- ArchiveSomeOldHistory(end_time, std::numeric_limits<size_t>::max());
+ ArchiveSomeOldHistory(end_time, GetAllVisitsReader(),
+ std::numeric_limits<size_t>::max());
ParanoidExpireHistory();
}
+void ExpireHistoryBackend::InitWorkQueue() {
+ DCHECK(work_queue_.empty()) << "queue has to be empty prior to init";
+
+ for (size_t i = 0; i < readers_.size(); i++)
+ work_queue_.push(readers_[i]);
+}
+
+const ExpiringVisitsReader* ExpireHistoryBackend::GetAllVisitsReader() {
+ if (!all_visits_reader_.get())
+ all_visits_reader_.reset(new AllVisitsReader());
+ return all_visits_reader_.get();
+}
+
+const ExpiringVisitsReader*
+ ExpireHistoryBackend::GetAutoSubframeVisitsReader() {
+ if (!auto_subframe_visits_reader_.get())
+ auto_subframe_visits_reader_.reset(new AutoSubframeVisitsReader());
+ return auto_subframe_visits_reader_.get();
+}
+
void ExpireHistoryBackend::StartArchivingOldStuff(
TimeDelta expiration_threshold) {
expiration_threshold_ = expiration_threshold;
- ScheduleArchive(TimeDelta::FromSeconds(kExpirationDelaySec));
+
+ // Remove all readers, just in case this was method was called before.
+ readers_.clear();
+ // For now, we explicitly add all known readers. If we come up with more
+ // reader types (in case we want to expire different types of visits in
+ // different ways), we can make it be populated by creator/owner of
+ // ExpireHistoryBackend.
+ readers_.push_back(GetAllVisitsReader());
+ readers_.push_back(GetAutoSubframeVisitsReader());
+
+ // Initialize the queue with all tasks for the first set of iterations.
+ InitWorkQueue();
+ ScheduleArchive();
}
void ExpireHistoryBackend::DeleteFaviconsIfPossible(
@@ -413,40 +502,53 @@
}
}
-void ExpireHistoryBackend::ScheduleArchive(TimeDelta delay) {
+void ExpireHistoryBackend::ScheduleArchive() {
+ TimeDelta delay;
+ if (work_queue_.empty()) {
+ // If work queue is empty, reset the work queue to contain all tasks and
+ // schedule next iteration after a longer delay.
+ InitWorkQueue();
+ delay = TimeDelta::FromMinutes(kExpirationEmptyDelayMin);
+ } else {
+ delay = TimeDelta::FromSeconds(kExpirationDelaySec);
+ }
+
factory_.RevokeAll();
MessageLoop::current()->PostDelayedTask(FROM_HERE, factory_.NewRunnableMethod(
&ExpireHistoryBackend::DoArchiveIteration), delay.InMilliseconds());
}
void ExpireHistoryBackend::DoArchiveIteration() {
- DCHECK(expiration_threshold_ != TimeDelta()) << "threshold should be set";
- Time threshold = Time::Now() - expiration_threshold_;
+ DCHECK(!work_queue_.empty()) << "queue has to be non-empty";
- if (ArchiveSomeOldHistory(threshold, kNumExpirePerIteration)) {
- // Possibly more items to delete now, schedule it sooner to happen again.
- ScheduleArchive(TimeDelta::FromSeconds(kExpirationDelaySec));
- } else {
- // If we didn't find the maximum number of items to delete, wait longer
- // before trying to delete more later.
- ScheduleArchive(TimeDelta::FromMinutes(kExpirationEmptyDelayMin));
- }
+ const ExpiringVisitsReader* reader = work_queue_.front();
+ bool more_to_expire = ArchiveSomeOldHistory(GetCurrentArchiveTime(), reader,
+ kNumExpirePerIteration);
+
+ work_queue_.pop();
+ // If there are more items to expire, add the reader back to the queue, thus
+ // creating a new task for future iterations.
+ if (more_to_expire)
+ work_queue_.push(reader);
+
+ ScheduleArchive();
}
-bool ExpireHistoryBackend::ArchiveSomeOldHistory(Time time_threshold,
- int max_visits) {
+bool ExpireHistoryBackend::ArchiveSomeOldHistory(
+ base::Time end_time,
+ const ExpiringVisitsReader* reader,
+ int max_visits) {
if (!main_db_)
return false;
- // Get all visits up to and including the threshold. This is a little tricky
- // because GetAllVisitsInRange's end value is non-inclusive, so we have to
- // increment the time by one unit to get the input value to be inclusive.
- DCHECK(!time_threshold.is_null());
- Time effective_threshold =
- Time::FromInternalValue(time_threshold.ToInternalValue() + 1);
+ // Add an extra time unit to given end time, because
+ // GetAllVisitsInRange, et al. queries' end value is non-inclusive.
+ Time effective_end_time =
+ Time::FromInternalValue(end_time.ToInternalValue() + 1);
+
VisitVector affected_visits;
- main_db_->GetAllVisitsInRange(Time(), effective_threshold, max_visits,
- &affected_visits);
+ bool more_to_expire = reader->Read(effective_end_time, main_db_,
+ &affected_visits, max_visits);
// Some visits we'll delete while others we'll archive.
VisitVector deleted_visits, archived_visits;
@@ -489,9 +591,7 @@
// to not do anything if nothing was deleted.
BroadcastDeleteNotifications(&deleted_dependencies);
- // When we got the maximum number of visits we asked for, we say there could
- // be additional things to expire now.
- return static_cast<int>(affected_visits.size()) == max_visits;
+ return more_to_expire;
}
void ExpireHistoryBackend::ParanoidExpireHistory() {
« 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