| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 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 "components/precache/core/precache_database.h" | 5 #include "components/precache/core/precache_database.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
| 9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/metrics/histogram_macros.h" | 10 #include "base/metrics/histogram_macros.h" |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 db_.reset(new sql::Connection()); | 51 db_.reset(new sql::Connection()); |
| 52 db_->set_histogram_tag("Precache"); | 52 db_->set_histogram_tag("Precache"); |
| 53 | 53 |
| 54 if (!db_->Open(db_path)) { | 54 if (!db_->Open(db_path)) { |
| 55 // Don't initialize the URL table if unable to access | 55 // Don't initialize the URL table if unable to access |
| 56 // the database. | 56 // the database. |
| 57 return false; | 57 return false; |
| 58 } | 58 } |
| 59 | 59 |
| 60 if (!precache_url_table_.Init(db_.get()) || | 60 if (!precache_url_table_.Init(db_.get()) || |
| 61 !precache_referrer_host_table_.Init(db_.get()) || |
| 61 !precache_session_table_.Init(db_.get())) { | 62 !precache_session_table_.Init(db_.get())) { |
| 62 // Raze and close the database connection to indicate that it's not usable, | 63 // Raze and close the database connection to indicate that it's not usable, |
| 63 // and so that the database will be created anew next time, in case it's | 64 // and so that the database will be created anew next time, in case it's |
| 64 // corrupted. | 65 // corrupted. |
| 65 db_->RazeAndClose(); | 66 db_->RazeAndClose(); |
| 66 return false; | 67 return false; |
| 67 } | 68 } |
| 68 return true; | 69 return true; |
| 69 } | 70 } |
| 70 | 71 |
| 71 void PrecacheDatabase::DeleteExpiredPrecacheHistory( | 72 void PrecacheDatabase::DeleteExpiredPrecacheHistory( |
| 72 const base::Time& current_time) { | 73 const base::Time& current_time) { |
| 73 if (!IsDatabaseAccessible()) { | 74 if (!IsDatabaseAccessible()) { |
| 74 // Do nothing if unable to access the database. | 75 // Do nothing if unable to access the database. |
| 75 return; | 76 return; |
| 76 } | 77 } |
| 77 | 78 |
| 78 // Delete old precache history that has expired. | 79 // Delete old precache history that has expired. |
| 79 base::Time delete_end = current_time - base::TimeDelta::FromDays( | 80 base::Time delete_end = current_time - base::TimeDelta::FromDays( |
| 80 kPrecacheHistoryExpiryPeriodDays); | 81 kPrecacheHistoryExpiryPeriodDays); |
| 81 buffered_writes_.push_back( | 82 buffered_writes_.push_back( |
| 82 base::Bind(&PrecacheURLTable::DeleteAllPrecachedBefore, | 83 base::Bind(&PrecacheURLTable::DeleteAllPrecachedBefore, |
| 83 base::Unretained(&precache_url_table_), delete_end)); | 84 base::Unretained(&precache_url_table_), delete_end)); |
| 85 buffered_writes_.push_back( |
| 86 base::Bind(&PrecacheReferrerHostTable::DeleteAllEntriesBefore, |
| 87 base::Unretained(&precache_referrer_host_table_), delete_end)); |
| 84 Flush(); | 88 Flush(); |
| 85 } | 89 } |
| 86 | 90 |
| 87 void PrecacheDatabase::ClearHistory() { | 91 void PrecacheDatabase::ClearHistory() { |
| 88 if (!IsDatabaseAccessible()) { | 92 if (!IsDatabaseAccessible()) { |
| 89 // Do nothing if unable to access the database. | 93 // Do nothing if unable to access the database. |
| 90 return; | 94 return; |
| 91 } | 95 } |
| 92 | 96 |
| 93 buffered_writes_.push_back(base::Bind( | 97 buffered_writes_.push_back(base::Bind( |
| 94 &PrecacheURLTable::DeleteAll, base::Unretained(&precache_url_table_))); | 98 &PrecacheURLTable::DeleteAll, base::Unretained(&precache_url_table_))); |
| 99 buffered_writes_.push_back( |
| 100 base::Bind(&PrecacheReferrerHostTable::DeleteAll, |
| 101 base::Unretained(&precache_referrer_host_table_))); |
| 95 Flush(); | 102 Flush(); |
| 96 } | 103 } |
| 97 | 104 |
| 98 void PrecacheDatabase::SetLastPrecacheTimestamp(const base::Time& time) { | 105 void PrecacheDatabase::SetLastPrecacheTimestamp(const base::Time& time) { |
| 99 last_precache_timestamp_ = time; | 106 last_precache_timestamp_ = time; |
| 100 | 107 |
| 101 if (!IsDatabaseAccessible()) { | 108 if (!IsDatabaseAccessible()) { |
| 102 // Do nothing if unable to access the database. | 109 // Do nothing if unable to access the database. |
| 103 return; | 110 return; |
| 104 } | 111 } |
| 105 | 112 |
| 106 buffered_writes_.push_back( | 113 buffered_writes_.push_back( |
| 107 base::Bind(&PrecacheSessionTable::SetLastPrecacheTimestamp, | 114 base::Bind(&PrecacheSessionTable::SetLastPrecacheTimestamp, |
| 108 base::Unretained(&precache_session_table_), time)); | 115 base::Unretained(&precache_session_table_), time)); |
| 109 MaybePostFlush(); | 116 MaybePostFlush(); |
| 110 } | 117 } |
| 111 | 118 |
| 112 base::Time PrecacheDatabase::GetLastPrecacheTimestamp() { | 119 base::Time PrecacheDatabase::GetLastPrecacheTimestamp() { |
| 113 if (last_precache_timestamp_.is_null() && IsDatabaseAccessible()) { | 120 if (last_precache_timestamp_.is_null() && IsDatabaseAccessible()) { |
| 114 last_precache_timestamp_ = | 121 last_precache_timestamp_ = |
| 115 precache_session_table_.GetLastPrecacheTimestamp(); | 122 precache_session_table_.GetLastPrecacheTimestamp(); |
| 116 } | 123 } |
| 117 return last_precache_timestamp_; | 124 return last_precache_timestamp_; |
| 118 } | 125 } |
| 119 | 126 |
| 120 void PrecacheDatabase::RecordURLPrefetch(const GURL& url, | 127 PrecacheReferrerHostEntry PrecacheDatabase::GetReferrerHost( |
| 121 const base::TimeDelta& latency, | 128 const std::string& referrer_host) { |
| 122 const base::Time& fetch_time, | 129 DCHECK(thread_checker_.CalledOnValidThread()); |
| 123 const net::HttpResponseInfo& info, | 130 return precache_referrer_host_table_.GetReferrerHost(referrer_host); |
| 124 int64_t size) { | 131 } |
| 132 |
| 133 void PrecacheDatabase::GetURLListForReferrerHost( |
| 134 int64_t referrer_host_id, |
| 135 std::deque<GURL>& used_urls, |
| 136 std::deque<GURL>& unused_urls) { |
| 137 DCHECK_NE(PrecacheReferrerHostEntry::INVALID_ID, referrer_host_id); |
| 138 precache_url_table_.GetURLListForReferrerHost(referrer_host_id, used_urls, |
| 139 unused_urls); |
| 140 } |
| 141 |
| 142 void PrecacheDatabase::RecordURLPrefetchMetrics( |
| 143 const net::HttpResponseInfo& info, |
| 144 const base::TimeDelta& latency) { |
| 145 DCHECK(thread_checker_.CalledOnValidThread()); |
| 146 |
| 125 UMA_HISTOGRAM_TIMES("Precache.Latency.Prefetch", latency); | 147 UMA_HISTOGRAM_TIMES("Precache.Latency.Prefetch", latency); |
| 126 | 148 |
| 127 if (!IsDatabaseAccessible()) { | |
| 128 // Don't track anything if unable to access the database. | |
| 129 return; | |
| 130 } | |
| 131 | |
| 132 if (buffered_urls_.find(url.spec()) != buffered_urls_.end()) { | |
| 133 // If the URL for this fetch is in the write buffer, then flush the write | |
| 134 // buffer. | |
| 135 Flush(); | |
| 136 } | |
| 137 | |
| 138 DCHECK(info.headers) << "The headers are required to get the freshness."; | 149 DCHECK(info.headers) << "The headers are required to get the freshness."; |
| 139 if (info.headers) { | 150 if (info.headers) { |
| 140 UMA_HISTOGRAM_CUSTOM_COUNTS( | 151 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 141 "Precache.Freshness.Prefetch", | 152 "Precache.Freshness.Prefetch", |
| 142 info.headers->GetFreshnessLifetimes(info.response_time) | 153 info.headers->GetFreshnessLifetimes(info.response_time) |
| 143 .freshness.InSeconds(), | 154 .freshness.InSeconds(), |
| 144 base::TimeDelta::FromMinutes(5).InSeconds() /* min */, | 155 base::TimeDelta::FromMinutes(5).InSeconds() /* min */, |
| 145 base::TimeDelta::FromDays(356).InSeconds() /* max */, | 156 base::TimeDelta::FromDays(356).InSeconds() /* max */, |
| 146 100 /* bucket_count */); | 157 100 /* bucket_count */); |
| 147 } | 158 } |
| 159 } |
| 148 | 160 |
| 149 if (info.was_cached && !precache_url_table_.HasURL(url)) { | 161 void PrecacheDatabase::RecordURLPrefetch(const GURL& url, |
| 150 // Since the precache came from the cache, and there's no entry in the URL | 162 const std::string& referrer_host, |
| 151 // table for the URL, this means that the resource was already in the cache | 163 const base::Time& fetch_time, |
| 152 // because of user browsing. Therefore, this precache won't be considered as | 164 bool was_cached, |
| 153 // precache-motivated since it had no significant effect (besides a possible | 165 int64_t size) { |
| 154 // revalidation and a change in the cache LRU priority). | 166 DCHECK(thread_checker_.CalledOnValidThread()); |
| 167 |
| 168 if (!IsDatabaseAccessible()) { |
| 169 // Don't track anything if unable to access the database. |
| 155 return; | 170 return; |
| 156 } | 171 } |
| 157 | 172 |
| 158 if (!info.was_cached) { | 173 if (buffered_urls_.find(url.spec()) != buffered_urls_.end()) { |
| 174 // If the URL for this fetch is in the write buffer, then flush the write |
| 175 // buffer. |
| 176 Flush(); |
| 177 } |
| 178 |
| 179 if (!was_cached) { |
| 159 // The precache only counts as overhead if it was downloaded over the | 180 // The precache only counts as overhead if it was downloaded over the |
| 160 // network. | 181 // network. |
| 161 UMA_HISTOGRAM_COUNTS("Precache.DownloadedPrecacheMotivated", | 182 UMA_HISTOGRAM_COUNTS("Precache.DownloadedPrecacheMotivated", |
| 162 static_cast<base::HistogramBase::Sample>(size)); | 183 static_cast<base::HistogramBase::Sample>(size)); |
| 163 } | 184 } |
| 164 | 185 |
| 165 // Use the URL table to keep track of URLs that are in the cache thanks to | 186 // Use the URL table to keep track of URLs. URLs that are fetched via network |
| 166 // precaching. If a row for the URL already exists, than update the timestamp | 187 // or already in the cache due to prior precaching are recorded as |
| 167 // to |fetch_time|. | 188 // precache-motivated. URLs that came from the cache and not recorded as |
| 168 buffered_writes_.push_back( | 189 // precached previously, were already in the cache because of user browsing. |
| 169 base::Bind(&PrecacheURLTable::AddURL, | 190 // Therefore, this precache will not be considered as precache-motivated, |
| 170 base::Unretained(&precache_url_table_), url, fetch_time)); | 191 // since it had no significant effect (besides a possible revalidation and a |
| 192 // change in the cache LRU priority). If a row for the URL already exists, |
| 193 // then the timestamp is updated. |
| 194 buffered_writes_.push_back(base::Bind( |
| 195 &PrecacheDatabase::RecordURLPrefetchInternal, GetWeakPtr(), url, |
| 196 referrer_host, !was_cached || precache_url_table_.IsURLPrecached(url), |
| 197 fetch_time)); |
| 171 buffered_urls_.insert(url.spec()); | 198 buffered_urls_.insert(url.spec()); |
| 172 MaybePostFlush(); | 199 MaybePostFlush(); |
| 173 } | 200 } |
| 174 | 201 |
| 202 void PrecacheDatabase::RecordURLPrefetchInternal( |
| 203 const GURL& url, |
| 204 const std::string& referrer_host, |
| 205 bool is_precached, |
| 206 const base::Time& fetch_time) { |
| 207 auto referrer_host_id = |
| 208 precache_referrer_host_table_.GetReferrerHost(referrer_host).id; |
| 209 if (referrer_host_id == PrecacheReferrerHostEntry::INVALID_ID) { |
| 210 referrer_host_id = precache_referrer_host_table_.UpdateReferrerHost( |
| 211 referrer_host, 0, fetch_time); |
| 212 DCHECK_NE(referrer_host_id, PrecacheReferrerHostEntry::INVALID_ID); |
| 213 } |
| 214 precache_url_table_.AddURL(url, referrer_host_id, is_precached, fetch_time); |
| 215 } |
| 216 |
| 175 void PrecacheDatabase::RecordURLNonPrefetch(const GURL& url, | 217 void PrecacheDatabase::RecordURLNonPrefetch(const GURL& url, |
| 176 const base::TimeDelta& latency, | 218 const base::TimeDelta& latency, |
| 177 const base::Time& fetch_time, | 219 const base::Time& fetch_time, |
| 178 const net::HttpResponseInfo& info, | 220 const net::HttpResponseInfo& info, |
| 179 int64_t size, | 221 int64_t size, |
| 180 int host_rank, | 222 int host_rank, |
| 181 bool is_connection_cellular) { | 223 bool is_connection_cellular) { |
| 182 UMA_HISTOGRAM_TIMES("Precache.Latency.NonPrefetch", latency); | 224 UMA_HISTOGRAM_TIMES("Precache.Latency.NonPrefetch", latency); |
| 183 UMA_HISTOGRAM_ENUMERATION("Precache.CacheStatus.NonPrefetch", | 225 UMA_HISTOGRAM_ENUMERATION("Precache.CacheStatus.NonPrefetch", |
| 184 info.cache_entry_status, | 226 info.cache_entry_status, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 200 } | 242 } |
| 201 | 243 |
| 202 RecordTimeSinceLastPrecache(fetch_time); | 244 RecordTimeSinceLastPrecache(fetch_time); |
| 203 | 245 |
| 204 if (buffered_urls_.find(url.spec()) != buffered_urls_.end()) { | 246 if (buffered_urls_.find(url.spec()) != buffered_urls_.end()) { |
| 205 // If the URL for this fetch is in the write buffer, then flush the write | 247 // If the URL for this fetch is in the write buffer, then flush the write |
| 206 // buffer. | 248 // buffer. |
| 207 Flush(); | 249 Flush(); |
| 208 } | 250 } |
| 209 | 251 |
| 210 if (info.was_cached && !precache_url_table_.HasURL(url)) { | 252 bool is_precached = precache_url_table_.IsURLPrecachedAndUnused(url); |
| 253 if (info.was_cached && !is_precached) { |
| 211 // Ignore cache hits that precache can't take credit for. | 254 // Ignore cache hits that precache can't take credit for. |
| 212 return; | 255 return; |
| 213 } | 256 } |
| 214 | 257 |
| 215 base::HistogramBase::Sample size_sample = | 258 base::HistogramBase::Sample size_sample = |
| 216 static_cast<base::HistogramBase::Sample>(size); | 259 static_cast<base::HistogramBase::Sample>(size); |
| 217 if (!info.was_cached) { | 260 if (!info.was_cached) { |
| 218 // The fetch was served over the network during user browsing, so count it | 261 // The fetch was served over the network during user browsing, so count it |
| 219 // as downloaded non-precache bytes. | 262 // as downloaded non-precache bytes. |
| 220 UMA_HISTOGRAM_COUNTS("Precache.DownloadedNonPrecache", size_sample); | 263 UMA_HISTOGRAM_COUNTS("Precache.DownloadedNonPrecache", size_sample); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 238 UMA_HISTOGRAM_CUSTOM_COUNTS( | 281 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 239 "Precache.Saved.Freshness", | 282 "Precache.Saved.Freshness", |
| 240 info.headers->GetFreshnessLifetimes(info.response_time) | 283 info.headers->GetFreshnessLifetimes(info.response_time) |
| 241 .freshness.InSeconds(), | 284 .freshness.InSeconds(), |
| 242 base::TimeDelta::FromMinutes(5).InSeconds() /* min */, | 285 base::TimeDelta::FromMinutes(5).InSeconds() /* min */, |
| 243 base::TimeDelta::FromDays(356).InSeconds() /* max */, | 286 base::TimeDelta::FromDays(356).InSeconds() /* max */, |
| 244 100 /* bucket_count */); | 287 100 /* bucket_count */); |
| 245 } | 288 } |
| 246 } | 289 } |
| 247 | 290 |
| 248 // Since the resource has been fetched during user browsing, remove any record | 291 if (is_precached) { |
| 249 // of that URL having been precached from the URL table, if any exists. | 292 // Since the resource has been fetched during user browsing, mark the URL as |
| 250 // The current fetch would have put this resource in the cache regardless of | 293 // used in the precache URL table, if any exists. The current fetch would |
| 251 // whether or not it was previously precached, so delete any record of that | 294 // have put this resource in the cache regardless of whether or not it was |
| 252 // URL having been precached from the URL table. | 295 // previously precached, so mark the URL as used. |
| 296 buffered_writes_.push_back( |
| 297 base::Bind(&PrecacheURLTable::SetPrecachedURLAsUsed, |
| 298 base::Unretained(&precache_url_table_), url)); |
| 299 buffered_urls_.insert(url.spec()); |
| 300 MaybePostFlush(); |
| 301 } |
| 302 } |
| 303 |
| 304 void PrecacheDatabase::UpdatePrecacheReferrerHost( |
| 305 const std::string& hostname, |
| 306 int64_t manifest_id, |
| 307 const base::Time& fetch_time) { |
| 308 DCHECK(thread_checker_.CalledOnValidThread()); |
| 309 |
| 310 if (!IsDatabaseAccessible()) { |
| 311 // Don't track anything if unable to access the database. |
| 312 return; |
| 313 } |
| 314 |
| 253 buffered_writes_.push_back( | 315 buffered_writes_.push_back( |
| 254 base::Bind(&PrecacheURLTable::DeleteURL, | 316 base::Bind(&PrecacheDatabase::UpdatePrecacheReferrerHostInternal, |
| 255 base::Unretained(&precache_url_table_), url)); | 317 GetWeakPtr(), hostname, manifest_id, fetch_time)); |
| 256 buffered_urls_.insert(url.spec()); | |
| 257 MaybePostFlush(); | 318 MaybePostFlush(); |
| 258 } | 319 } |
| 259 | 320 |
| 321 void PrecacheDatabase::UpdatePrecacheReferrerHostInternal( |
| 322 const std::string& hostname, |
| 323 int64_t manifest_id, |
| 324 const base::Time& fetch_time) { |
| 325 precache_referrer_host_table_.UpdateReferrerHost(hostname, manifest_id, |
| 326 fetch_time); |
| 327 } |
| 328 |
| 260 void PrecacheDatabase::RecordTimeSinceLastPrecache( | 329 void PrecacheDatabase::RecordTimeSinceLastPrecache( |
| 261 const base::Time& fetch_time) { | 330 const base::Time& fetch_time) { |
| 262 const base::Time& last_precache_timestamp = GetLastPrecacheTimestamp(); | 331 const base::Time& last_precache_timestamp = GetLastPrecacheTimestamp(); |
| 263 // It could still be null if the DB was not accessible. | 332 // It could still be null if the DB was not accessible. |
| 264 if (!last_precache_timestamp.is_null()) { | 333 if (!last_precache_timestamp.is_null()) { |
| 265 // This is the timespan (in seconds) between the last call to | 334 // This is the timespan (in seconds) between the last call to |
| 266 // PrecacheManager::StartPrecaching and the fetch time of a non-precache | 335 // PrecacheManager::StartPrecaching and the fetch time of a non-precache |
| 267 // URL. Please note that the session started by that call to | 336 // URL. Please note that the session started by that call to |
| 268 // PrecacheManager::StartPrecaching may not have precached this particular | 337 // PrecacheManager::StartPrecaching may not have precached this particular |
| 269 // URL or even any URL for that matter. | 338 // URL or even any URL for that matter. |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 | 421 |
| 353 void PrecacheDatabase::DeleteUnfinishedWork() { | 422 void PrecacheDatabase::DeleteUnfinishedWork() { |
| 354 precache_session_table_.DeleteUnfinishedWork(); | 423 precache_session_table_.DeleteUnfinishedWork(); |
| 355 } | 424 } |
| 356 | 425 |
| 357 base::WeakPtr<PrecacheDatabase> PrecacheDatabase::GetWeakPtr() { | 426 base::WeakPtr<PrecacheDatabase> PrecacheDatabase::GetWeakPtr() { |
| 358 return weak_factory_.GetWeakPtr(); | 427 return weak_factory_.GetWeakPtr(); |
| 359 } | 428 } |
| 360 | 429 |
| 361 } // namespace precache | 430 } // namespace precache |
| OLD | NEW |