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

Side by Side Diff: net/dns/host_cache.cc

Issue 1908543002: DNS: Retain stale entries in HostCache and return when requested (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase, tweak histograms a bit Created 4 years, 8 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) 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 "net/dns/host_cache.h" 5 #include "net/dns/host_cache.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/memory/ptr_util.h" 8 #include "base/memory/ptr_util.h"
9 #include "base/metrics/field_trial.h" 9 #include "base/metrics/field_trial.h"
10 #include "base/metrics/histogram_macros.h" 10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_number_conversions.h"
12 #include "base/trace_event/trace_event.h" 12 #include "base/trace_event/trace_event.h"
13 #include "net/base/net_errors.h" 13 #include "net/base/net_errors.h"
14 #include "net/dns/dns_util.h"
14 15
15 namespace net { 16 namespace net {
16 17
17 //----------------------------------------------------------------------------- 18 namespace {
19
20 #define CACHE_HISTOGRAM_TIME(name, time) \
21 UMA_HISTOGRAM_LONG_TIMES("DNS.HostCache" name, time)
22
23 #define CACHE_HISTOGRAM_COUNT(name, count) \
24 UMA_HISTOGRAM_COUNTS_1000("DNS.HostCache" name, count)
25
26 #define CACHE_HISTOGRAM_ENUM(name, value, max) \
27 UMA_HISTOGRAM_ENUMERATION("DNS.HostCache" name, value, max)
28
29 void HistogramUpdateStale(const HostCache::EntryInternal& old_entry,
30 const HostCache::Entry& new_entry,
31 base::TimeDelta expired_by,
32 unsigned network_changes,
33 unsigned stale_hits) {
34 AddressListDeltaType delta =
35 FindAddressListDeltaType(old_entry.addrlist, new_entry.addrlist);
36 CACHE_HISTOGRAM_ENUM("UpdateStaleDelta", delta, MAX_DELTA_TYPE);
37 switch (delta) {
38 case DELTA_IDENTICAL:
39 CACHE_HISTOGRAM_TIME("UpdateStaleExpiredBy_Identical", expired_by);
40 CACHE_HISTOGRAM_COUNT("UpdateStaleNetworkChanges_Identical",
41 network_changes);
42 break;
43 case DELTA_REORDERED:
44 CACHE_HISTOGRAM_TIME("UpdateStaleExpiredBy_Reordered", expired_by);
45 CACHE_HISTOGRAM_COUNT("UpdateStaleNetworkChanges_Reordered",
46 network_changes);
47 break;
48 case DELTA_OVERLAP:
49 CACHE_HISTOGRAM_TIME("UpdateStaleExpiredBy_Overlap", expired_by);
50 CACHE_HISTOGRAM_COUNT("UpdateStaleNetworkChanges_Overlap",
51 network_changes);
52 break;
53 case DELTA_DISJOINT:
54 CACHE_HISTOGRAM_TIME("UpdateStaleExpiredBy_Disjoint", expired_by);
55 CACHE_HISTOGRAM_COUNT("UpdateStaleNetworkChanges_Dijsoint",
56 network_changes);
57 break;
58 case MAX_DELTA_TYPE:
59 NOTREACHED();
60 break;
61 }
62 }
63
64 // Used in histograms; please only insert new entries before MAX.
65 enum SetOutcome {
66 SET_INSERT,
67 SET_UPDATE_VALID,
68 SET_UPDATE_STALE,
69 MAX_SET_OUTCOME
70 };
71
72 void HistogramSet(SetOutcome outcome,
73 base::TimeTicks now,
74 unsigned network_changes,
75 const HostCache::EntryInternal* old_entry,
76 const HostCache::Entry& new_entry) {
77 CACHE_HISTOGRAM_ENUM("Set", outcome, MAX_SET_OUTCOME);
78 switch (outcome) {
79 case SET_INSERT:
80 // Nothing to log here.
81 break;
82 case SET_UPDATE_VALID:
83 break;
84 case SET_UPDATE_STALE: {
85 base::TimeDelta expired_by = now - old_entry->expires;
86 network_changes = network_changes - old_entry->network_changes;
87 unsigned stale_hits = old_entry->stale_hits;
88 CACHE_HISTOGRAM_TIME("UpdateStaleExpiredBy", expired_by);
89 CACHE_HISTOGRAM_COUNT("UpdateStaleNetworkChanges", network_changes);
90 CACHE_HISTOGRAM_COUNT("UpdateStaleHits", stale_hits);
91 if (old_entry->error == OK && new_entry.error == OK) {
92 HistogramUpdateStale(*old_entry, new_entry, expired_by, network_changes,
93 stale_hits);
94 }
95 break;
96 }
97 case MAX_SET_OUTCOME:
98 NOTREACHED();
99 break;
100 }
101 }
102
103 // Used in histograms; please only insert new entries before MAX.
104 enum LookupOutcome {
105 LOOKUP_MISS_ABSENT,
106 LOOKUP_MISS_STALE,
107 LOOKUP_HIT_VALID,
108 LOOKUP_HIT_STALE,
109 MAX_LOOKUP_OUTCOME
110 };
111
112 void HistogramLookup(LookupOutcome outcome,
113 base::TimeTicks now,
114 unsigned network_changes,
115 const HostCache::EntryInternal* entry) {
116 CACHE_HISTOGRAM_ENUM("Lookup", outcome, MAX_LOOKUP_OUTCOME);
117 switch (outcome) {
118 case LOOKUP_MISS_ABSENT:
119 // Nothing to log here.
120 break;
121 case LOOKUP_MISS_STALE:
122 case LOOKUP_HIT_VALID:
123 break;
124 case LOOKUP_HIT_STALE:
125 CACHE_HISTOGRAM_TIME("LookupStaleExpiredBy", now - entry->expires);
126 CACHE_HISTOGRAM_COUNT("LookupStaleNetworkChanges",
127 network_changes - entry->network_changes);
128 CACHE_HISTOGRAM_COUNT("LookupStaleHits", entry->stale_hits);
129 break;
130 case MAX_LOOKUP_OUTCOME:
131 NOTREACHED();
132 break;
133 }
134 }
135
136 // Used in histograms; please only insert new entries before MAX.
137 enum EraseReason { ERASE_EVICT, ERASE_CLEAR, ERASE_DESTRUCT, MAX_ERASE_REASON };
138
139 void HistogramErase(EraseReason reason,
140 base::TimeTicks now,
141 unsigned network_changes,
142 const HostCache::EntryInternal& entry) {
143 HostCache::StaleEntryInfo stale;
144 entry.CheckStale(now, network_changes, &stale);
145 CACHE_HISTOGRAM_ENUM("Erase", reason, MAX_ERASE_REASON);
146 switch (reason) {
147 case ERASE_EVICT:
148 if (stale.is_stale()) {
149 CACHE_HISTOGRAM_TIME("EvictStaleExpiredBy", stale.expired_by);
150 CACHE_HISTOGRAM_COUNT("EvictStaleNetworkChanges",
151 stale.network_changes);
152 CACHE_HISTOGRAM_COUNT("EvictStaleHits", entry.stale_hits);
153 } else {
154 CACHE_HISTOGRAM_TIME("EvictValidFor", -stale.expired_by);
155 }
156 break;
157 case ERASE_CLEAR:
158 // TODO(juliatuttle): Remove these once we stop clearing the cache on
159 // network change.
160 if (stale.is_stale()) {
161 CACHE_HISTOGRAM_TIME("ClearStaleExpiredBy", stale.expired_by);
162 CACHE_HISTOGRAM_COUNT("ClearStaleNetworkChanges",
163 stale.network_changes);
164 CACHE_HISTOGRAM_COUNT("ClearStaleHits", entry.stale_hits);
165 } else {
166 CACHE_HISTOGRAM_TIME("ClearValidFor", -stale.expired_by);
167 }
168 break;
169 case ERASE_DESTRUCT:
170 break;
171 default:
172 NOTREACHED();
173 break;
174 }
175 }
176
177 void HistogramEraseAll(EraseReason reason,
178 base::TimeTicks now,
179 unsigned network_changes,
180 const HostCache::EntryMap& entries) {
181 for (const auto& it : entries)
182 HistogramErase(reason, now, network_changes, it.second);
183 }
184
185 } // namespace
18 186
19 HostCache::Entry::Entry(int error, const AddressList& addrlist, 187 HostCache::Entry::Entry(int error, const AddressList& addrlist,
20 base::TimeDelta ttl) 188 base::TimeDelta ttl)
21 : error(error), 189 : error(error),
22 addrlist(addrlist), 190 addrlist(addrlist),
23 ttl(ttl) { 191 ttl(ttl) {
24 DCHECK(ttl >= base::TimeDelta()); 192 DCHECK(ttl >= base::TimeDelta());
25 } 193 }
26 194
27 HostCache::Entry::Entry(int error, const AddressList& addrlist) 195 HostCache::Entry::Entry(int error, const AddressList& addrlist)
28 : error(error), 196 : error(error),
29 addrlist(addrlist), 197 addrlist(addrlist),
30 ttl(base::TimeDelta::FromSeconds(-1)) { 198 ttl(base::TimeDelta::FromSeconds(-1)) {
31 } 199 }
32 200
33 HostCache::Entry::~Entry() { 201 HostCache::Entry::~Entry() {}
34 }
35
36 //-----------------------------------------------------------------------------
37 202
38 HostCache::HostCache(size_t max_entries) 203 HostCache::HostCache(size_t max_entries)
39 : entries_(max_entries) { 204 : max_entries_(max_entries), network_changes_(0u) {}
40 }
41 205
42 HostCache::~HostCache() { 206 HostCache::~HostCache() {
207 HistogramEraseAll(ERASE_DESTRUCT, base::TimeTicks::Now(), network_changes_,
208 entries_);
43 } 209 }
44 210
45 const HostCache::Entry* HostCache::Lookup(const Key& key, 211 const HostCache::Entry* HostCache::Lookup(const Key& key,
46 base::TimeTicks now) { 212 base::TimeTicks now) {
213 return LookupStale(key, now, nullptr);
214 }
215
216 const HostCache::Entry* HostCache::LookupStale(
217 const Key& key,
218 base::TimeTicks now,
219 HostCache::StaleEntryInfo* stale_out) {
47 DCHECK(CalledOnValidThread()); 220 DCHECK(CalledOnValidThread());
48 if (caching_is_disabled()) 221 if (caching_is_disabled())
49 return NULL; 222 return nullptr;
50 223
51 return entries_.Get(key, now); 224 auto it = entries_.find(key);
225 if (it == entries_.end()) {
226 HistogramLookup(LOOKUP_MISS_ABSENT, now, network_changes_, nullptr);
227 return nullptr;
228 }
229
230 bool is_stale = it->second.CheckStale(now, network_changes_, stale_out);
231 if (is_stale && !stale_out) {
232 HistogramLookup(LOOKUP_MISS_STALE, now, network_changes_, &it->second);
233 return nullptr;
234 }
235
236 if (is_stale) {
237 HistogramLookup(LOOKUP_HIT_STALE, now, network_changes_, &it->second);
238 stale_out->stale_hits = ++it->second.stale_hits;
239 } else {
240 HistogramLookup(LOOKUP_HIT_VALID, now, network_changes_, &it->second);
241 }
242 ++it->second.total_hits;
243
244 return &it->second;
52 } 245 }
53 246
54 void HostCache::Set(const Key& key, 247 void HostCache::Set(const Key& key,
55 const Entry& entry, 248 const Entry& entry,
56 base::TimeTicks now, 249 base::TimeTicks now,
57 base::TimeDelta ttl) { 250 base::TimeDelta ttl) {
58 TRACE_EVENT0("net", "HostCache::Set"); 251 TRACE_EVENT0("net", "HostCache::Set");
59 DCHECK(CalledOnValidThread()); 252 DCHECK(CalledOnValidThread());
60 if (caching_is_disabled()) 253 if (caching_is_disabled())
61 return; 254 return;
62 255
63 entries_.Put(key, entry, now, now + ttl); 256 auto it = entries_.find(key);
257 if (it != entries_.end()) {
258 bool is_stale = it->second.CheckStale(now, network_changes_, nullptr);
259 if (is_stale)
260 HistogramSet(SET_UPDATE_STALE, now, network_changes_, &it->second, entry);
261 else
262 HistogramSet(SET_UPDATE_VALID, now, network_changes_, &it->second, entry);
263 // TODO: Remember some old metadata, if it's useful?
264 entries_.erase(it);
265 } else {
266 if (size() == max_entries_)
267 Evict(now);
268 HistogramSet(SET_INSERT, now, network_changes_, nullptr, entry);
269 }
270
271 DCHECK_GT(max_entries_, size());
272 DCHECK_EQ(0u, entries_.count(key));
273 entries_.insert(std::make_pair(
274 Key(key), EntryInternal(entry, now, ttl, network_changes_)));
275 DCHECK_GE(max_entries_, size());
276 }
277
278 void HostCache::OnNetworkChange() {
279 ++network_changes_;
64 } 280 }
65 281
66 void HostCache::clear() { 282 void HostCache::clear() {
67 DCHECK(CalledOnValidThread()); 283 DCHECK(CalledOnValidThread());
68 entries_.Clear(); 284 HistogramEraseAll(ERASE_CLEAR, base::TimeTicks::Now(), network_changes_,
285 entries_);
286 entries_.clear();
69 } 287 }
70 288
71 size_t HostCache::size() const { 289 size_t HostCache::size() const {
72 DCHECK(CalledOnValidThread()); 290 DCHECK(CalledOnValidThread());
73 return entries_.size(); 291 return entries_.size();
74 } 292 }
75 293
76 size_t HostCache::max_entries() const { 294 size_t HostCache::max_entries() const {
77 DCHECK(CalledOnValidThread()); 295 DCHECK(CalledOnValidThread());
78 return entries_.max_entries(); 296 return max_entries_;
297 }
298
299 std::unique_ptr<base::Value> HostCache::GetEntriesAsValue() const {
300 base::ListValue* entry_list = new base::ListValue();
301
302 for (auto& pair : entries_) {
303 const Key& key = pair.first;
304 const EntryInternal& entry = pair.second;
305
306 base::DictionaryValue* entry_dict = new base::DictionaryValue();
307
308 entry_dict->SetString("hostname", key.hostname);
309 entry_dict->SetInteger("address_family",
310 static_cast<int>(key.address_family));
311 entry_dict->SetString("expiration",
312 NetLog::TickCountToString(entry.expires));
313
314 if (entry.error != OK) {
315 entry_dict->SetInteger("error", entry.error);
316 } else {
317 base::ListValue* address_list = new base::ListValue();
318 for (size_t i = 0; i < entry.addrlist.size(); ++i)
319 address_list->AppendString(entry.addrlist[i].ToStringWithoutPort());
320 entry_dict->Set("addresses", address_list);
321 }
322
323 entry_list->Append(entry_dict);
324 }
325
326 return base::WrapUnique(entry_list);
79 } 327 }
80 328
81 // Note that this map may contain expired entries. 329 // Note that this map may contain expired entries.
82 const HostCache::EntryMap& HostCache::entries() const { 330 /* const HostCache::EntryMap& HostCache::entries() const {
83 DCHECK(CalledOnValidThread()); 331 DCHECK(CalledOnValidThread());
84 return entries_; 332 return entries_;
85 } 333 } */
86 334
87 // static 335 // static
88 std::unique_ptr<HostCache> HostCache::CreateDefaultCache() { 336 std::unique_ptr<HostCache> HostCache::CreateDefaultCache() {
89 // Cache capacity is determined by the field trial. 337 // Cache capacity is determined by the field trial.
90 #if defined(ENABLE_BUILT_IN_DNS) 338 #if defined(ENABLE_BUILT_IN_DNS)
91 const size_t kDefaultMaxEntries = 1000; 339 const size_t kDefaultMaxEntries = 1000;
92 #else 340 #else
93 const size_t kDefaultMaxEntries = 100; 341 const size_t kDefaultMaxEntries = 100;
94 #endif 342 #endif
95 const size_t kSaneMaxEntries = 1 << 20; 343 const size_t kSaneMaxEntries = 1 << 20;
96 size_t max_entries = 0; 344 size_t max_entries = 0;
97 base::StringToSizeT(base::FieldTrialList::FindFullName("HostCacheSize"), 345 base::StringToSizeT(base::FieldTrialList::FindFullName("HostCacheSize"),
98 &max_entries); 346 &max_entries);
99 if ((max_entries == 0) || (max_entries > kSaneMaxEntries)) 347 if ((max_entries == 0) || (max_entries > kSaneMaxEntries))
100 max_entries = kDefaultMaxEntries; 348 max_entries = kDefaultMaxEntries;
101 return base::WrapUnique(new HostCache(max_entries)); 349 return base::WrapUnique(new HostCache(max_entries));
102 } 350 }
103 351
104 void HostCache::EvictionHandler::Handle( 352 HostCache::EntryInternal::EntryInternal(const HostCache::Entry& entry,
105 const Key& key, 353 base::TimeTicks now,
106 const Entry& entry, 354 base::TimeDelta ttl,
107 const base::TimeTicks& expiration, 355 unsigned network_changes)
108 const base::TimeTicks& now, 356 : HostCache::Entry(entry),
109 bool on_get) const { 357 added(now),
110 if (on_get) { 358 expires(now + ttl),
111 DCHECK(now >= expiration); 359 network_changes(network_changes),
112 UMA_HISTOGRAM_CUSTOM_TIMES("DNS.CacheExpiredOnGet", now - expiration, 360 total_hits(0u),
113 base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(1), 100); 361 stale_hits(0u) {}
114 return; 362
363 bool HostCache::EntryInternal::CheckStale(
364 base::TimeTicks now,
365 unsigned network_changes,
366 HostCache::StaleEntryInfo* out) const {
367 StaleEntryInfo stale;
368 stale.expired_by = now - expires;
369 stale.network_changes = network_changes - this->network_changes;
370 stale.stale_hits = stale_hits;
371
372 if (out)
373 *out = stale;
374 return stale.is_stale();
375 }
376
377 void HostCache::Evict(base::TimeTicks now) {
378 DCHECK_LT(0u, entries_.size());
379
380 EntryMap::iterator it = SelectEntryToEvict();
381 HistogramErase(ERASE_EVICT, now, network_changes_, it->second);
382 entries_.erase(it);
383 }
384
385 HostCache::EntryMap::iterator HostCache::SelectEntryToEvict() {
386 DCHECK_LT(0u, entries_.size());
387
388 auto oldest_it = entries_.begin();
389 for (auto it = entries_.begin(); it != entries_.end(); ++it) {
390 if (it->second.expires < oldest_it->second.expires)
391 oldest_it = it;
115 } 392 }
116 if (expiration > now) { 393 return oldest_it;
117 UMA_HISTOGRAM_CUSTOM_TIMES("DNS.CacheEvicted", expiration - now,
118 base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(1), 100);
119 } else {
120 UMA_HISTOGRAM_CUSTOM_TIMES("DNS.CacheExpired", now - expiration,
121 base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(1), 100);
122 }
123 } 394 }
124 395
125 } // namespace net 396 } // namespace net
OLDNEW
« net/dns/dns_util.h ('K') | « net/dns/host_cache.h ('k') | net/dns/host_cache_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698