| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 <functional> | 8 #include <functional> |
| 9 #include <limits> | 9 #include <limits> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
| 13 #include "base/file_util.h" | 13 #include "base/file_util.h" |
| 14 #include "base/files/file_enumerator.h" | 14 #include "base/files/file_enumerator.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
| 17 #include "chrome/browser/chrome_notification_types.h" | 17 #include "chrome/browser/chrome_notification_types.h" |
| 18 #include "chrome/browser/history/archived_database.h" | |
| 19 #include "chrome/browser/history/history_database.h" | 18 #include "chrome/browser/history/history_database.h" |
| 20 #include "chrome/browser/history/history_notifications.h" | 19 #include "chrome/browser/history/history_notifications.h" |
| 21 #include "chrome/browser/history/thumbnail_database.h" | 20 #include "chrome/browser/history/thumbnail_database.h" |
| 22 #include "components/bookmarks/browser/bookmark_service.h" | 21 #include "components/bookmarks/browser/bookmark_service.h" |
| 23 | 22 |
| 24 namespace history { | 23 namespace history { |
| 25 | 24 |
| 26 // Helpers -------------------------------------------------------------------- | 25 // Helpers -------------------------------------------------------------------- |
| 27 | 26 |
| 28 namespace { | 27 namespace { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 content::PAGE_TRANSITION_AUTO_SUBFRAME, | 89 content::PAGE_TRANSITION_AUTO_SUBFRAME, |
| 91 visits); | 90 visits); |
| 92 bool more = static_cast<int>(visits->size()) == max_visits; | 91 bool more = static_cast<int>(visits->size()) == max_visits; |
| 93 if (!more) | 92 if (!more) |
| 94 db->UpdateEarlyExpirationThreshold(early_end_time); | 93 db->UpdateEarlyExpirationThreshold(early_end_time); |
| 95 | 94 |
| 96 return more; | 95 return more; |
| 97 } | 96 } |
| 98 }; | 97 }; |
| 99 | 98 |
| 100 // Returns true if this visit is worth archiving. Otherwise, this visit is not | |
| 101 // worth saving (for example, subframe navigations and redirects) and we can | |
| 102 // just delete it when it gets old. | |
| 103 bool ShouldArchiveVisit(const VisitRow& visit) { | |
| 104 int no_qualifier = content::PageTransitionStripQualifier(visit.transition); | |
| 105 | |
| 106 // These types of transitions are always "important" and the user will want | |
| 107 // to see them. | |
| 108 if (no_qualifier == content::PAGE_TRANSITION_TYPED || | |
| 109 no_qualifier == content::PAGE_TRANSITION_AUTO_BOOKMARK || | |
| 110 no_qualifier == content::PAGE_TRANSITION_AUTO_TOPLEVEL) | |
| 111 return true; | |
| 112 | |
| 113 // Only archive these "less important" transitions when they were the final | |
| 114 // navigation and not part of a redirect chain. | |
| 115 if ((no_qualifier == content::PAGE_TRANSITION_LINK || | |
| 116 no_qualifier == content::PAGE_TRANSITION_FORM_SUBMIT || | |
| 117 no_qualifier == content::PAGE_TRANSITION_KEYWORD || | |
| 118 no_qualifier == content::PAGE_TRANSITION_GENERATED) && | |
| 119 visit.transition & content::PAGE_TRANSITION_CHAIN_END) | |
| 120 return true; | |
| 121 | |
| 122 // The transition types we ignore are AUTO_SUBFRAME and MANUAL_SUBFRAME. | |
| 123 return false; | |
| 124 } | |
| 125 | |
| 126 // The number of visits we will expire very time we check for old items. This | 99 // The number of visits we will expire very time we check for old items. This |
| 127 // Prevents us from doing too much work any given time. | 100 // Prevents us from doing too much work any given time. |
| 128 const int kNumExpirePerIteration = 32; | 101 const int kNumExpirePerIteration = 32; |
| 129 | 102 |
| 130 // The number of seconds between checking for items that should be expired when | 103 // The number of seconds between checking for items that should be expired when |
| 131 // we think there might be more items to expire. This timeout is used when the | 104 // we think there might be more items to expire. This timeout is used when the |
| 132 // last expiration found at least kNumExpirePerIteration and we want to check | 105 // last expiration found at least kNumExpirePerIteration and we want to check |
| 133 // again "soon." | 106 // again "soon." |
| 134 const int kExpirationDelaySec = 30; | 107 const int kExpirationDelaySec = 30; |
| 135 | 108 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 151 } | 124 } |
| 152 | 125 |
| 153 | 126 |
| 154 // ExpireHistoryBackend ------------------------------------------------------- | 127 // ExpireHistoryBackend ------------------------------------------------------- |
| 155 | 128 |
| 156 ExpireHistoryBackend::ExpireHistoryBackend( | 129 ExpireHistoryBackend::ExpireHistoryBackend( |
| 157 BroadcastNotificationDelegate* delegate, | 130 BroadcastNotificationDelegate* delegate, |
| 158 BookmarkService* bookmark_service) | 131 BookmarkService* bookmark_service) |
| 159 : delegate_(delegate), | 132 : delegate_(delegate), |
| 160 main_db_(NULL), | 133 main_db_(NULL), |
| 161 archived_db_(NULL), | |
| 162 thumb_db_(NULL), | 134 thumb_db_(NULL), |
| 163 weak_factory_(this), | 135 weak_factory_(this), |
| 164 bookmark_service_(bookmark_service) { | 136 bookmark_service_(bookmark_service) { |
| 165 } | 137 } |
| 166 | 138 |
| 167 ExpireHistoryBackend::~ExpireHistoryBackend() { | 139 ExpireHistoryBackend::~ExpireHistoryBackend() { |
| 168 } | 140 } |
| 169 | 141 |
| 170 void ExpireHistoryBackend::SetDatabases(HistoryDatabase* main_db, | 142 void ExpireHistoryBackend::SetDatabases(HistoryDatabase* main_db, |
| 171 ArchivedDatabase* archived_db, | |
| 172 ThumbnailDatabase* thumb_db) { | 143 ThumbnailDatabase* thumb_db) { |
| 173 main_db_ = main_db; | 144 main_db_ = main_db; |
| 174 archived_db_ = archived_db; | |
| 175 thumb_db_ = thumb_db; | 145 thumb_db_ = thumb_db; |
| 176 } | 146 } |
| 177 | 147 |
| 178 void ExpireHistoryBackend::DeleteURL(const GURL& url) { | 148 void ExpireHistoryBackend::DeleteURL(const GURL& url) { |
| 179 DeleteURLs(std::vector<GURL>(1, url)); | 149 DeleteURLs(std::vector<GURL>(1, url)); |
| 180 } | 150 } |
| 181 | 151 |
| 182 void ExpireHistoryBackend::DeleteURLs(const std::vector<GURL>& urls) { | 152 void ExpireHistoryBackend::DeleteURLs(const std::vector<GURL>& urls) { |
| 183 if (!main_db_) | 153 if (!main_db_) |
| 184 return; | 154 return; |
| 185 | 155 |
| 186 DeleteEffects effects; | 156 DeleteEffects effects; |
| 187 for (std::vector<GURL>::const_iterator url = urls.begin(); url != urls.end(); | 157 for (std::vector<GURL>::const_iterator url = urls.begin(); url != urls.end(); |
| 188 ++url) { | 158 ++url) { |
| 189 URLRow url_row; | 159 URLRow url_row; |
| 190 if (!main_db_->GetRowForURL(*url, &url_row)) | 160 if (!main_db_->GetRowForURL(*url, &url_row)) |
| 191 continue; // Nothing to delete. | 161 continue; // Nothing to delete. |
| 192 | 162 |
| 193 // Collect all the visits and delete them. Note that we don't give | 163 // Collect all the visits and delete them. Note that we don't give up if |
| 194 // up if there are no visits, since the URL could still have an | 164 // there are no visits, since the URL could still have an entry that we |
| 195 // entry that we should delete. TODO(brettw): bug 1171148: We | 165 // should delete. |
| 196 // should also delete from the archived DB. | |
| 197 VisitVector visits; | 166 VisitVector visits; |
| 198 main_db_->GetVisitsForURL(url_row.id(), &visits); | 167 main_db_->GetVisitsForURL(url_row.id(), &visits); |
| 199 | 168 |
| 200 DeleteVisitRelatedInfo(visits, &effects); | 169 DeleteVisitRelatedInfo(visits, &effects); |
| 201 | 170 |
| 202 // We skip ExpireURLsForVisits (since we are deleting from the | 171 // We skip ExpireURLsForVisits (since we are deleting from the |
| 203 // URL, and not starting with visits in a given time range). We | 172 // URL, and not starting with visits in a given time range). We |
| 204 // therefore need to call the deletion and favicon update | 173 // therefore need to call the deletion and favicon update |
| 205 // functions manually. | 174 // functions manually. |
| 206 BookmarkService* bookmark_service = GetBookmarkService(); | 175 BookmarkService* bookmark_service = GetBookmarkService(); |
| 207 DeleteOneURL(url_row, | 176 DeleteOneURL(url_row, |
| 208 bookmark_service && bookmark_service->IsBookmarked(*url), | 177 bookmark_service && bookmark_service->IsBookmarked(*url), |
| 209 &effects); | 178 &effects); |
| 210 } | 179 } |
| 211 | 180 |
| 212 DeleteFaviconsIfPossible(&effects); | 181 DeleteFaviconsIfPossible(&effects); |
| 213 | 182 |
| 214 BroadcastNotifications(&effects, DELETION_USER_INITIATED); | 183 BroadcastNotifications(&effects, DELETION_USER_INITIATED); |
| 215 } | 184 } |
| 216 | 185 |
| 217 void ExpireHistoryBackend::ExpireHistoryBetween( | 186 void ExpireHistoryBackend::ExpireHistoryBetween( |
| 218 const std::set<GURL>& restrict_urls, | 187 const std::set<GURL>& restrict_urls, |
| 219 base::Time begin_time, | 188 base::Time begin_time, |
| 220 base::Time end_time) { | 189 base::Time end_time) { |
| 221 if (!main_db_) | 190 if (!main_db_) |
| 222 return; | 191 return; |
| 223 | 192 |
| 224 // Find the affected visits and delete them. | 193 // Find the affected visits and delete them. |
| 225 // TODO(brettw): bug 1171164: We should query the archived database here, too. | |
| 226 VisitVector visits; | 194 VisitVector visits; |
| 227 main_db_->GetAllVisitsInRange(begin_time, end_time, 0, &visits); | 195 main_db_->GetAllVisitsInRange(begin_time, end_time, 0, &visits); |
| 228 if (!restrict_urls.empty()) { | 196 if (!restrict_urls.empty()) { |
| 229 std::set<URLID> url_ids; | 197 std::set<URLID> url_ids; |
| 230 for (std::set<GURL>::const_iterator url = restrict_urls.begin(); | 198 for (std::set<GURL>::const_iterator url = restrict_urls.begin(); |
| 231 url != restrict_urls.end(); ++url) | 199 url != restrict_urls.end(); ++url) |
| 232 url_ids.insert(main_db_->GetRowForURL(*url, NULL)); | 200 url_ids.insert(main_db_->GetRowForURL(*url, NULL)); |
| 233 VisitVector all_visits; | 201 VisitVector all_visits; |
| 234 all_visits.swap(visits); | 202 all_visits.swap(visits); |
| 235 for (VisitVector::iterator visit = all_visits.begin(); | 203 for (VisitVector::iterator visit = all_visits.begin(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 248 // it. | 216 // it. |
| 249 DCHECK( | 217 DCHECK( |
| 250 std::adjacent_find( | 218 std::adjacent_find( |
| 251 times.begin(), times.end(), std::less_equal<base::Time>()) == | 219 times.begin(), times.end(), std::less_equal<base::Time>()) == |
| 252 times.end()); | 220 times.end()); |
| 253 | 221 |
| 254 if (!main_db_) | 222 if (!main_db_) |
| 255 return; | 223 return; |
| 256 | 224 |
| 257 // Find the affected visits and delete them. | 225 // Find the affected visits and delete them. |
| 258 // TODO(brettw): bug 1171164: We should query the archived database here, too. | |
| 259 VisitVector visits; | 226 VisitVector visits; |
| 260 main_db_->GetVisitsForTimes(times, &visits); | 227 main_db_->GetVisitsForTimes(times, &visits); |
| 261 ExpireVisits(visits); | 228 ExpireVisits(visits); |
| 262 } | 229 } |
| 263 | 230 |
| 264 void ExpireHistoryBackend::ExpireVisits(const VisitVector& visits) { | 231 void ExpireHistoryBackend::ExpireVisits(const VisitVector& visits) { |
| 265 if (visits.empty()) | 232 if (visits.empty()) |
| 266 return; | 233 return; |
| 267 | 234 |
| 268 DeleteEffects effects; | 235 DeleteEffects effects; |
| 269 DeleteVisitRelatedInfo(visits, &effects); | 236 DeleteVisitRelatedInfo(visits, &effects); |
| 270 | 237 |
| 271 // Delete or update the URLs affected. We want to update the visit counts | 238 // Delete or update the URLs affected. We want to update the visit counts |
| 272 // since this is called by the user who wants to delete their recent history, | 239 // since this is called by the user who wants to delete their recent history, |
| 273 // and we don't want to leave any evidence. | 240 // and we don't want to leave any evidence. |
| 274 ExpireURLsForVisits(visits, &effects); | 241 ExpireURLsForVisits(visits, &effects); |
| 275 DeleteFaviconsIfPossible(&effects); | 242 DeleteFaviconsIfPossible(&effects); |
| 276 BroadcastNotifications(&effects, DELETION_USER_INITIATED); | 243 BroadcastNotifications(&effects, DELETION_USER_INITIATED); |
| 277 | 244 |
| 278 // Pick up any bits possibly left over. | 245 // Pick up any bits possibly left over. |
| 279 ParanoidExpireHistory(); | 246 ParanoidExpireHistory(); |
| 280 } | 247 } |
| 281 | 248 |
| 282 void ExpireHistoryBackend::ArchiveHistoryBefore(base::Time end_time) { | 249 void ExpireHistoryBackend::ExpireHistoryBefore(base::Time end_time) { |
| 283 if (!main_db_) | 250 if (!main_db_) |
| 284 return; | 251 return; |
| 285 | 252 |
| 286 // Archive as much history as possible before the given date. | 253 // Expire as much history as possible before the given date. |
| 287 ArchiveSomeOldHistory(end_time, GetAllVisitsReader(), | 254 ExpireSomeOldHistory(end_time, GetAllVisitsReader(), |
| 288 std::numeric_limits<int>::max()); | 255 std::numeric_limits<int>::max()); |
| 289 ParanoidExpireHistory(); | 256 ParanoidExpireHistory(); |
| 290 } | 257 } |
| 291 | 258 |
| 292 void ExpireHistoryBackend::InitWorkQueue() { | 259 void ExpireHistoryBackend::InitWorkQueue() { |
| 293 DCHECK(work_queue_.empty()) << "queue has to be empty prior to init"; | 260 DCHECK(work_queue_.empty()) << "queue has to be empty prior to init"; |
| 294 | 261 |
| 295 for (size_t i = 0; i < readers_.size(); i++) | 262 for (size_t i = 0; i < readers_.size(); i++) |
| 296 work_queue_.push(readers_[i]); | 263 work_queue_.push(readers_[i]); |
| 297 } | 264 } |
| 298 | 265 |
| 299 const ExpiringVisitsReader* ExpireHistoryBackend::GetAllVisitsReader() { | 266 const ExpiringVisitsReader* ExpireHistoryBackend::GetAllVisitsReader() { |
| 300 if (!all_visits_reader_) | 267 if (!all_visits_reader_) |
| 301 all_visits_reader_.reset(new AllVisitsReader()); | 268 all_visits_reader_.reset(new AllVisitsReader()); |
| 302 return all_visits_reader_.get(); | 269 return all_visits_reader_.get(); |
| 303 } | 270 } |
| 304 | 271 |
| 305 const ExpiringVisitsReader* | 272 const ExpiringVisitsReader* |
| 306 ExpireHistoryBackend::GetAutoSubframeVisitsReader() { | 273 ExpireHistoryBackend::GetAutoSubframeVisitsReader() { |
| 307 if (!auto_subframe_visits_reader_) | 274 if (!auto_subframe_visits_reader_) |
| 308 auto_subframe_visits_reader_.reset(new AutoSubframeVisitsReader()); | 275 auto_subframe_visits_reader_.reset(new AutoSubframeVisitsReader()); |
| 309 return auto_subframe_visits_reader_.get(); | 276 return auto_subframe_visits_reader_.get(); |
| 310 } | 277 } |
| 311 | 278 |
| 312 void ExpireHistoryBackend::StartArchivingOldStuff( | 279 void ExpireHistoryBackend::StartExpiringOldStuff( |
| 313 base::TimeDelta expiration_threshold) { | 280 base::TimeDelta expiration_threshold) { |
| 314 expiration_threshold_ = expiration_threshold; | 281 expiration_threshold_ = expiration_threshold; |
| 315 | 282 |
| 316 // Remove all readers, just in case this was method was called before. | 283 // Remove all readers, just in case this was method was called before. |
| 317 readers_.clear(); | 284 readers_.clear(); |
| 318 // For now, we explicitly add all known readers. If we come up with more | 285 // For now, we explicitly add all known readers. If we come up with more |
| 319 // reader types (in case we want to expire different types of visits in | 286 // reader types (in case we want to expire different types of visits in |
| 320 // different ways), we can make it be populated by creator/owner of | 287 // different ways), we can make it be populated by creator/owner of |
| 321 // ExpireHistoryBackend. | 288 // ExpireHistoryBackend. |
| 322 readers_.push_back(GetAllVisitsReader()); | 289 readers_.push_back(GetAllVisitsReader()); |
| 323 readers_.push_back(GetAutoSubframeVisitsReader()); | 290 readers_.push_back(GetAutoSubframeVisitsReader()); |
| 324 | 291 |
| 325 // Initialize the queue with all tasks for the first set of iterations. | 292 // Initialize the queue with all tasks for the first set of iterations. |
| 326 InitWorkQueue(); | 293 InitWorkQueue(); |
| 327 ScheduleArchive(); | 294 ScheduleExpire(); |
| 328 } | 295 } |
| 329 | 296 |
| 330 void ExpireHistoryBackend::DeleteFaviconsIfPossible(DeleteEffects* effects) { | 297 void ExpireHistoryBackend::DeleteFaviconsIfPossible(DeleteEffects* effects) { |
| 331 if (!thumb_db_) | 298 if (!thumb_db_) |
| 332 return; | 299 return; |
| 333 | 300 |
| 334 for (std::set<favicon_base::FaviconID>::const_iterator i = | 301 for (std::set<favicon_base::FaviconID>::const_iterator i = |
| 335 effects->affected_favicons.begin(); | 302 effects->affected_favicons.begin(); |
| 336 i != effects->affected_favicons.end(); ++i) { | 303 i != effects->affected_favicons.end(); ++i) { |
| 337 if (!thumb_db_->HasMappingFor(*i)) { | 304 if (!thumb_db_->HasMappingFor(*i)) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 353 scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails); | 320 scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails); |
| 354 details->changed_urls = effects->modified_urls; | 321 details->changed_urls = effects->modified_urls; |
| 355 delegate_->NotifySyncURLsModified(&details->changed_urls); | 322 delegate_->NotifySyncURLsModified(&details->changed_urls); |
| 356 delegate_->BroadcastNotifications( | 323 delegate_->BroadcastNotifications( |
| 357 chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, | 324 chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, |
| 358 details.PassAs<HistoryDetails>()); | 325 details.PassAs<HistoryDetails>()); |
| 359 } | 326 } |
| 360 if (!effects->deleted_urls.empty()) { | 327 if (!effects->deleted_urls.empty()) { |
| 361 scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails); | 328 scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails); |
| 362 details->all_history = false; | 329 details->all_history = false; |
| 363 details->archived = (type == DELETION_ARCHIVED); | 330 details->expired = (type == DELETION_EXPIRED); |
| 364 details->rows = effects->deleted_urls; | 331 details->rows = effects->deleted_urls; |
| 365 details->favicon_urls = effects->deleted_favicons; | 332 details->favicon_urls = effects->deleted_favicons; |
| 366 delegate_->NotifySyncURLsDeleted(details->all_history, details->archived, | 333 delegate_->NotifySyncURLsDeleted(details->all_history, details->expired, |
| 367 &details->rows); | 334 &details->rows); |
| 368 delegate_->BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, | 335 delegate_->BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, |
| 369 details.PassAs<HistoryDetails>()); | 336 details.PassAs<HistoryDetails>()); |
| 370 } | 337 } |
| 371 } | 338 } |
| 372 | 339 |
| 373 void ExpireHistoryBackend::DeleteVisitRelatedInfo(const VisitVector& visits, | 340 void ExpireHistoryBackend::DeleteVisitRelatedInfo(const VisitVector& visits, |
| 374 DeleteEffects* effects) { | 341 DeleteEffects* effects) { |
| 375 for (size_t i = 0; i < visits.size(); i++) { | 342 for (size_t i = 0; i < visits.size(); i++) { |
| 376 // Delete the visit itself. | 343 // Delete the visit itself. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 404 } | 371 } |
| 405 // Delete the mapping entries for the url. | 372 // Delete the mapping entries for the url. |
| 406 thumb_db_->DeleteIconMappings(url_row.url()); | 373 thumb_db_->DeleteIconMappings(url_row.url()); |
| 407 } | 374 } |
| 408 } | 375 } |
| 409 // Last, delete the URL entry. | 376 // Last, delete the URL entry. |
| 410 main_db_->DeleteURLRow(url_row.id()); | 377 main_db_->DeleteURLRow(url_row.id()); |
| 411 } | 378 } |
| 412 } | 379 } |
| 413 | 380 |
| 414 URLID ExpireHistoryBackend::ArchiveOneURL(const URLRow& url_row) { | |
| 415 if (!archived_db_) | |
| 416 return 0; | |
| 417 | |
| 418 // See if this URL is present in the archived database already. Note that | |
| 419 // we must look up by ID since the URL ID will be different. | |
| 420 URLRow archived_row; | |
| 421 if (archived_db_->GetRowForURL(url_row.url(), &archived_row)) { | |
| 422 // TODO(sky): bug 1168470, need to archive past search terms. | |
| 423 // TODO(brettw): should be copy the visit counts over? This will mean that | |
| 424 // the main DB's visit counts are only for the last 3 months rather than | |
| 425 // accumulative. | |
| 426 archived_row.set_last_visit(url_row.last_visit()); | |
| 427 archived_db_->UpdateURLRow(archived_row.id(), archived_row); | |
| 428 return archived_row.id(); | |
| 429 } | |
| 430 | |
| 431 // This row is not in the archived DB, add it. | |
| 432 return archived_db_->AddURL(url_row); | |
| 433 } | |
| 434 | |
| 435 namespace { | 381 namespace { |
| 436 | 382 |
| 437 struct ChangedURL { | 383 struct ChangedURL { |
| 438 ChangedURL() : visit_count(0), typed_count(0) {} | 384 ChangedURL() : visit_count(0), typed_count(0) {} |
| 439 int visit_count; | 385 int visit_count; |
| 440 int typed_count; | 386 int typed_count; |
| 441 }; | 387 }; |
| 442 | 388 |
| 443 } // namespace | 389 } // namespace |
| 444 | 390 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 496 std::max(0, url_row.typed_count() - i->second.typed_count)); | 442 std::max(0, url_row.typed_count() - i->second.typed_count)); |
| 497 | 443 |
| 498 // Update the db with the new details. | 444 // Update the db with the new details. |
| 499 main_db_->UpdateURLRow(url_row.id(), url_row); | 445 main_db_->UpdateURLRow(url_row.id(), url_row); |
| 500 | 446 |
| 501 effects->modified_urls.push_back(url_row); | 447 effects->modified_urls.push_back(url_row); |
| 502 } | 448 } |
| 503 } | 449 } |
| 504 } | 450 } |
| 505 | 451 |
| 506 void ExpireHistoryBackend::ArchiveURLsAndVisits(const VisitVector& visits) { | 452 void ExpireHistoryBackend::ScheduleExpire() { |
| 507 if (!archived_db_ || !main_db_) | |
| 508 return; | |
| 509 | |
| 510 // Make sure all unique URL rows are added to the dependency list and the | |
| 511 // archived database. We will also keep the mapping between the main DB URLID | |
| 512 // and the archived one. | |
| 513 std::map<URLID, URLID> main_id_to_archived_id; | |
| 514 for (size_t i = 0; i < visits.size(); i++) { | |
| 515 if (!main_id_to_archived_id.count(visits[i].url_id)) { | |
| 516 // Unique URL encountered, archive it. | |
| 517 // Only add URL to the dependency list once we know we successfully | |
| 518 // archived it. | |
| 519 URLRow row; | |
| 520 if (main_db_->GetURLRow(visits[i].url_id, &row)) { | |
| 521 URLID archived_id = ArchiveOneURL(row); | |
| 522 if (archived_id) | |
| 523 main_id_to_archived_id[row.id()] = archived_id; | |
| 524 } | |
| 525 } | |
| 526 } | |
| 527 | |
| 528 // Retrieve the sources for all the archived visits before archiving. | |
| 529 // The returned visit_sources vector should contain the source for each visit | |
| 530 // from visits at the same index. | |
| 531 VisitSourceMap visit_sources; | |
| 532 main_db_->GetVisitsSource(visits, &visit_sources); | |
| 533 | |
| 534 // Now archive the visits since we know the URL ID to make them reference. | |
| 535 // The source visit list should still reference the visits in the main DB, but | |
| 536 // we will update it to reflect only the visits that were successfully | |
| 537 // archived. | |
| 538 for (size_t i = 0; i < visits.size(); i++) { | |
| 539 // Construct the visit that we will add to the archived database. We do | |
| 540 // not store referring visits since we delete many of the visits when | |
| 541 // archiving. | |
| 542 VisitRow cur_visit(visits[i]); | |
| 543 cur_visit.url_id = main_id_to_archived_id[cur_visit.url_id]; | |
| 544 cur_visit.referring_visit = 0; | |
| 545 VisitSourceMap::iterator iter = visit_sources.find(visits[i].visit_id); | |
| 546 archived_db_->AddVisit( | |
| 547 &cur_visit, | |
| 548 iter == visit_sources.end() ? SOURCE_BROWSED : iter->second); | |
| 549 // Ignore failures, we will delete it from the main DB no matter what. | |
| 550 } | |
| 551 } | |
| 552 | |
| 553 void ExpireHistoryBackend::ScheduleArchive() { | |
| 554 base::TimeDelta delay; | 453 base::TimeDelta delay; |
| 555 if (work_queue_.empty()) { | 454 if (work_queue_.empty()) { |
| 556 // If work queue is empty, reset the work queue to contain all tasks and | 455 // If work queue is empty, reset the work queue to contain all tasks and |
| 557 // schedule next iteration after a longer delay. | 456 // schedule next iteration after a longer delay. |
| 558 InitWorkQueue(); | 457 InitWorkQueue(); |
| 559 delay = base::TimeDelta::FromMinutes(kExpirationEmptyDelayMin); | 458 delay = base::TimeDelta::FromMinutes(kExpirationEmptyDelayMin); |
| 560 } else { | 459 } else { |
| 561 delay = base::TimeDelta::FromSeconds(kExpirationDelaySec); | 460 delay = base::TimeDelta::FromSeconds(kExpirationDelaySec); |
| 562 } | 461 } |
| 563 | 462 |
| 564 base::MessageLoop::current()->PostDelayedTask( | 463 base::MessageLoop::current()->PostDelayedTask( |
| 565 FROM_HERE, | 464 FROM_HERE, |
| 566 base::Bind(&ExpireHistoryBackend::DoArchiveIteration, | 465 base::Bind(&ExpireHistoryBackend::DoExpireIteration, |
| 567 weak_factory_.GetWeakPtr()), | 466 weak_factory_.GetWeakPtr()), |
| 568 delay); | 467 delay); |
| 569 } | 468 } |
| 570 | 469 |
| 571 void ExpireHistoryBackend::DoArchiveIteration() { | 470 void ExpireHistoryBackend::DoExpireIteration() { |
| 572 DCHECK(!work_queue_.empty()) << "queue has to be non-empty"; | 471 DCHECK(!work_queue_.empty()) << "queue has to be non-empty"; |
| 573 | 472 |
| 574 const ExpiringVisitsReader* reader = work_queue_.front(); | 473 const ExpiringVisitsReader* reader = work_queue_.front(); |
| 575 bool more_to_expire = ArchiveSomeOldHistory(GetCurrentArchiveTime(), reader, | 474 bool more_to_expire = ExpireSomeOldHistory( |
| 576 kNumExpirePerIteration); | 475 GetCurrentExpirationTime(), reader, kNumExpirePerIteration); |
| 577 | 476 |
| 578 work_queue_.pop(); | 477 work_queue_.pop(); |
| 579 // If there are more items to expire, add the reader back to the queue, thus | 478 // If there are more items to expire, add the reader back to the queue, thus |
| 580 // creating a new task for future iterations. | 479 // creating a new task for future iterations. |
| 581 if (more_to_expire) | 480 if (more_to_expire) |
| 582 work_queue_.push(reader); | 481 work_queue_.push(reader); |
| 583 | 482 |
| 584 ScheduleArchive(); | 483 ScheduleExpire(); |
| 585 } | 484 } |
| 586 | 485 |
| 587 bool ExpireHistoryBackend::ArchiveSomeOldHistory( | 486 bool ExpireHistoryBackend::ExpireSomeOldHistory( |
| 588 base::Time end_time, | 487 base::Time end_time, |
| 589 const ExpiringVisitsReader* reader, | 488 const ExpiringVisitsReader* reader, |
| 590 int max_visits) { | 489 int max_visits) { |
| 591 if (!main_db_) | 490 if (!main_db_) |
| 592 return false; | 491 return false; |
| 593 | 492 |
| 594 // Add an extra time unit to given end time, because | 493 // Add an extra time unit to given end time, because |
| 595 // GetAllVisitsInRange, et al. queries' end value is non-inclusive. | 494 // GetAllVisitsInRange, et al. queries' end value is non-inclusive. |
| 596 base::Time effective_end_time = | 495 base::Time effective_end_time = |
| 597 base::Time::FromInternalValue(end_time.ToInternalValue() + 1); | 496 base::Time::FromInternalValue(end_time.ToInternalValue() + 1); |
| 598 | 497 |
| 599 VisitVector affected_visits; | 498 VisitVector deleted_visits; |
| 600 bool more_to_expire = reader->Read(effective_end_time, main_db_, | 499 bool more_to_expire = reader->Read(effective_end_time, main_db_, |
| 601 &affected_visits, max_visits); | 500 &deleted_visits, max_visits); |
| 602 | 501 |
| 603 // Some visits we'll delete while others we'll archive. | |
| 604 VisitVector deleted_visits, archived_visits; | |
| 605 for (size_t i = 0; i < affected_visits.size(); i++) { | |
| 606 if (ShouldArchiveVisit(affected_visits[i])) | |
| 607 archived_visits.push_back(affected_visits[i]); | |
| 608 else | |
| 609 deleted_visits.push_back(affected_visits[i]); | |
| 610 } | |
| 611 | |
| 612 // Do the actual archiving. | |
| 613 ArchiveURLsAndVisits(archived_visits); | |
| 614 | |
| 615 // Delete all the visits. | |
| 616 deleted_visits.insert(deleted_visits.end(), archived_visits.begin(), | |
| 617 archived_visits.end()); | |
| 618 DeleteEffects deleted_effects; | 502 DeleteEffects deleted_effects; |
| 619 DeleteVisitRelatedInfo(deleted_visits, &deleted_effects); | 503 DeleteVisitRelatedInfo(deleted_visits, &deleted_effects); |
| 620 ExpireURLsForVisits(deleted_visits, &deleted_effects); | 504 ExpireURLsForVisits(deleted_visits, &deleted_effects); |
| 621 DeleteFaviconsIfPossible(&deleted_effects); | 505 DeleteFaviconsIfPossible(&deleted_effects); |
| 622 BroadcastNotifications(&deleted_effects, DELETION_ARCHIVED); | 506 |
| 507 BroadcastNotifications(&deleted_effects, DELETION_EXPIRED); |
| 623 | 508 |
| 624 return more_to_expire; | 509 return more_to_expire; |
| 625 } | 510 } |
| 626 | 511 |
| 627 void ExpireHistoryBackend::ParanoidExpireHistory() { | 512 void ExpireHistoryBackend::ParanoidExpireHistory() { |
| 628 // TODO(brettw): Bug 1067331: write this to clean up any errors. | 513 // TODO(brettw): Bug 1067331: write this to clean up any errors. |
| 629 } | 514 } |
| 630 | 515 |
| 631 BookmarkService* ExpireHistoryBackend::GetBookmarkService() { | 516 BookmarkService* ExpireHistoryBackend::GetBookmarkService() { |
| 632 // We use the bookmark service to determine if a URL is bookmarked. The | 517 // We use the bookmark service to determine if a URL is bookmarked. The |
| 633 // bookmark service is loaded on a separate thread and may not be done by the | 518 // bookmark service is loaded on a separate thread and may not be done by the |
| 634 // time we get here. We therefor block until the bookmarks have finished | 519 // time we get here. We therefor block until the bookmarks have finished |
| 635 // loading. | 520 // loading. |
| 636 if (bookmark_service_) | 521 if (bookmark_service_) |
| 637 bookmark_service_->BlockTillLoaded(); | 522 bookmark_service_->BlockTillLoaded(); |
| 638 return bookmark_service_; | 523 return bookmark_service_; |
| 639 } | 524 } |
| 640 | 525 |
| 641 } // namespace history | 526 } // namespace history |
| OLD | NEW |