blob: b900828fcc2e7ebe8a7ad33ad533ef126a89ab8f [file] [log] [blame]
[email protected]a2730882012-01-21 00:56:271// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]8a00f00a2009-06-12 00:49:382// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]bc71b8772013-04-10 20:55:165#include "net/dns/host_cache.h"
[email protected]8a00f00a2009-06-12 00:49:386
mgershaf3ec7b2017-05-31 23:15:397#include <utility>
8
[email protected]8a00f00a2009-06-12 00:49:389#include "base/logging.h"
[email protected]2144768d2012-11-07 18:24:0210#include "base/metrics/field_trial.h"
asvitkinec3c93722015-06-17 14:48:3711#include "base/metrics/histogram_macros.h"
[email protected]be528af2013-06-11 07:39:4812#include "base/strings/string_number_conversions.h"
ssid6d6b40102016-04-05 18:59:5613#include "base/trace_event/trace_event.h"
mgershaf3ec7b2017-05-31 23:15:3914#include "base/values.h"
[email protected]8a00f00a2009-06-12 00:49:3815#include "net/base/net_errors.h"
xunjieli0b7f5b62016-12-06 20:43:4816#include "net/base/trace_constants.h"
juliatuttle317860e2016-05-12 14:47:2217#include "net/dns/dns_util.h"
mgershaf3ec7b2017-05-31 23:15:3918#include "net/log/net_log.h"
[email protected]8a00f00a2009-06-12 00:49:3819
20namespace net {
21
juliatuttle317860e2016-05-12 14:47:2222namespace {
[email protected]8a00f00a2009-06-12 00:49:3823
juliatuttle317860e2016-05-12 14:47:2224#define CACHE_HISTOGRAM_TIME(name, time) \
25 UMA_HISTOGRAM_LONG_TIMES("DNS.HostCache." name, time)
26
27#define CACHE_HISTOGRAM_COUNT(name, count) \
28 UMA_HISTOGRAM_COUNTS_1000("DNS.HostCache." name, count)
29
30#define CACHE_HISTOGRAM_ENUM(name, value, max) \
31 UMA_HISTOGRAM_ENUMERATION("DNS.HostCache." name, value, max)
32
mgershaf3ec7b2017-05-31 23:15:3933// String constants for dictionary keys.
34const char kHostnameKey[] = "hostname";
35const char kAddressFamilyKey[] = "address_family";
36const char kFlagsKey[] = "flags";
37const char kExpirationKey[] = "expiration";
38const char kTtlKey[] = "ttl";
39const char kNetworkChangesKey[] = "network_changes";
40const char kErrorKey[] = "error";
41const char kAddressesKey[] = "addresses";
42
mgersh120380c72017-06-16 18:25:2743bool AddressListFromListValue(const base::ListValue* value, AddressList* list) {
mgershaf3ec7b2017-05-31 23:15:3944 list->clear();
45 for (base::ListValue::const_iterator it = value->begin(); it != value->end();
46 it++) {
47 IPAddress address;
48 std::string addr_string;
49 if (!it->GetAsString(&addr_string) ||
50 !address.AssignFromIPLiteral(addr_string)) {
51 return false;
52 }
53 list->push_back(IPEndPoint(address, 0));
54 }
55 return true;
56}
57
juliatuttle317860e2016-05-12 14:47:2258} // namespace
59
60// Used in histograms; do not modify existing values.
61enum HostCache::SetOutcome : int {
62 SET_INSERT = 0,
63 SET_UPDATE_VALID = 1,
64 SET_UPDATE_STALE = 2,
65 MAX_SET_OUTCOME
66};
67
68// Used in histograms; do not modify existing values.
69enum HostCache::LookupOutcome : int {
70 LOOKUP_MISS_ABSENT = 0,
71 LOOKUP_MISS_STALE = 1,
72 LOOKUP_HIT_VALID = 2,
73 LOOKUP_HIT_STALE = 3,
74 MAX_LOOKUP_OUTCOME
75};
76
77// Used in histograms; do not modify existing values.
78enum HostCache::EraseReason : int {
79 ERASE_EVICT = 0,
80 ERASE_CLEAR = 1,
81 ERASE_DESTRUCT = 2,
82 MAX_ERASE_REASON
83};
84
85HostCache::Entry::Entry(int error,
86 const AddressList& addresses,
Rob Percival94f21ad2017-11-14 10:20:2487 Source source,
[email protected]1339a2a22012-10-17 08:39:4388 base::TimeDelta ttl)
Rob Percival94f21ad2017-11-14 10:20:2489 : error_(error), addresses_(addresses), source_(source), ttl_(ttl) {
[email protected]1339a2a22012-10-17 08:39:4390 DCHECK(ttl >= base::TimeDelta());
91}
92
Rob Percival94f21ad2017-11-14 10:20:2493HostCache::Entry::Entry(int error, const AddressList& addresses, Source source)
juliatuttle317860e2016-05-12 14:47:2294 : error_(error),
95 addresses_(addresses),
Rob Percival94f21ad2017-11-14 10:20:2496 source_(source),
juliatuttle317860e2016-05-12 14:47:2297 ttl_(base::TimeDelta::FromSeconds(-1)) {}
98
Chris Watkins68b15032017-12-01 03:07:1399HostCache::Entry::~Entry() = default;
juliatuttle317860e2016-05-12 14:47:22100
Rob Percival94f21ad2017-11-14 10:20:24101HostCache::Entry::Entry(HostCache::Entry&& entry) = default;
102
juliatuttle317860e2016-05-12 14:47:22103HostCache::Entry::Entry(const HostCache::Entry& entry,
104 base::TimeTicks now,
105 base::TimeDelta ttl,
106 int network_changes)
107 : error_(entry.error()),
108 addresses_(entry.addresses()),
Rob Percival94f21ad2017-11-14 10:20:24109 source_(entry.source()),
juliatuttle317860e2016-05-12 14:47:22110 ttl_(entry.ttl()),
111 expires_(now + ttl),
112 network_changes_(network_changes),
113 total_hits_(0),
114 stale_hits_(0) {}
115
mgershaf3ec7b2017-05-31 23:15:39116HostCache::Entry::Entry(int error,
117 const AddressList& addresses,
Rob Percival94f21ad2017-11-14 10:20:24118 Source source,
mgershaf3ec7b2017-05-31 23:15:39119 base::TimeTicks expires,
120 int network_changes)
121 : error_(error),
122 addresses_(addresses),
Rob Percival94f21ad2017-11-14 10:20:24123 source_(source),
mgershaf3ec7b2017-05-31 23:15:39124 ttl_(base::TimeDelta::FromSeconds(-1)),
125 expires_(expires),
126 network_changes_(network_changes),
127 total_hits_(0),
128 stale_hits_(0) {}
129
juliatuttle317860e2016-05-12 14:47:22130bool HostCache::Entry::IsStale(base::TimeTicks now, int network_changes) const {
131 EntryStaleness stale;
132 stale.expired_by = now - expires_;
133 stale.network_changes = network_changes - network_changes_;
134 stale.stale_hits = stale_hits_;
135 return stale.is_stale();
[email protected]8a00f00a2009-06-12 00:49:38136}
137
juliatuttle317860e2016-05-12 14:47:22138void HostCache::Entry::CountHit(bool hit_is_stale) {
139 ++total_hits_;
140 if (hit_is_stale)
141 ++stale_hits_;
[email protected]8a00f00a2009-06-12 00:49:38142}
143
juliatuttle317860e2016-05-12 14:47:22144void HostCache::Entry::GetStaleness(base::TimeTicks now,
145 int network_changes,
146 EntryStaleness* out) const {
147 DCHECK(out);
148 out->expired_by = now - expires_;
149 out->network_changes = network_changes - network_changes_;
150 out->stale_hits = stale_hits_;
151}
[email protected]8a00f00a2009-06-12 00:49:38152
[email protected]a2730882012-01-21 00:56:27153HostCache::HostCache(size_t max_entries)
Miriam Gershenson2839ef112017-08-30 03:25:37154 : max_entries_(max_entries),
155 network_changes_(0),
156 restore_size_(0),
157 delegate_(nullptr) {}
[email protected]8a00f00a2009-06-12 00:49:38158
159HostCache::~HostCache() {
gab47aa7da2017-06-02 16:09:43160 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
juliatuttle317860e2016-05-12 14:47:22161 RecordEraseAll(ERASE_DESTRUCT, base::TimeTicks::Now());
[email protected]8a00f00a2009-06-12 00:49:38162}
163
[email protected]123ab1e32009-10-21 19:12:57164const HostCache::Entry* HostCache::Lookup(const Key& key,
[email protected]eb2efb102012-02-25 06:28:45165 base::TimeTicks now) {
gab47aa7da2017-06-02 16:09:43166 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
[email protected]8a00f00a2009-06-12 00:49:38167 if (caching_is_disabled())
juliatuttle317860e2016-05-12 14:47:22168 return nullptr;
[email protected]8a00f00a2009-06-12 00:49:38169
juliatuttle317860e2016-05-12 14:47:22170 HostCache::Entry* entry = LookupInternal(key);
171 if (!entry) {
172 RecordLookup(LOOKUP_MISS_ABSENT, now, nullptr);
173 return nullptr;
174 }
175 if (entry->IsStale(now, network_changes_)) {
176 RecordLookup(LOOKUP_MISS_STALE, now, entry);
177 return nullptr;
178 }
179
180 entry->CountHit(/* hit_is_stale= */ false);
181 RecordLookup(LOOKUP_HIT_VALID, now, entry);
182 return entry;
183}
184
185const HostCache::Entry* HostCache::LookupStale(
186 const Key& key,
187 base::TimeTicks now,
188 HostCache::EntryStaleness* stale_out) {
gab47aa7da2017-06-02 16:09:43189 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
juliatuttle317860e2016-05-12 14:47:22190 if (caching_is_disabled())
191 return nullptr;
192
193 HostCache::Entry* entry = LookupInternal(key);
194 if (!entry) {
195 RecordLookup(LOOKUP_MISS_ABSENT, now, nullptr);
196 return nullptr;
197 }
198
199 bool is_stale = entry->IsStale(now, network_changes_);
200 entry->CountHit(/* hit_is_stale= */ is_stale);
201 RecordLookup(is_stale ? LOOKUP_HIT_STALE : LOOKUP_HIT_VALID, now, entry);
202
203 if (stale_out)
204 entry->GetStaleness(now, network_changes_, stale_out);
205 return entry;
206}
207
208HostCache::Entry* HostCache::LookupInternal(const Key& key) {
209 auto it = entries_.find(key);
210 return (it != entries_.end()) ? &it->second : nullptr;
[email protected]8a00f00a2009-06-12 00:49:38211}
212
[email protected]eb2efb102012-02-25 06:28:45213void HostCache::Set(const Key& key,
[email protected]1339a2a22012-10-17 08:39:43214 const Entry& entry,
[email protected]eb2efb102012-02-25 06:28:45215 base::TimeTicks now,
216 base::TimeDelta ttl) {
xunjieli0b7f5b62016-12-06 20:43:48217 TRACE_EVENT0(kNetTracingCategory, "HostCache::Set");
gab47aa7da2017-06-02 16:09:43218 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
[email protected]8a00f00a2009-06-12 00:49:38219 if (caching_is_disabled())
[email protected]eb2efb102012-02-25 06:28:45220 return;
[email protected]8a00f00a2009-06-12 00:49:38221
mgersh7c28e7982017-06-20 23:12:29222 bool result_changed = false;
juliatuttle317860e2016-05-12 14:47:22223 auto it = entries_.find(key);
224 if (it != entries_.end()) {
225 bool is_stale = it->second.IsStale(now, network_changes_);
mgersh7c28e7982017-06-20 23:12:29226 AddressListDeltaType delta =
227 FindAddressListDeltaType(it->second.addresses(), entry.addresses());
juliatuttle317860e2016-05-12 14:47:22228 RecordSet(is_stale ? SET_UPDATE_STALE : SET_UPDATE_VALID, now, &it->second,
mgersh7c28e7982017-06-20 23:12:29229 entry, delta);
juliatuttle317860e2016-05-12 14:47:22230 // TODO(juliatuttle): Remember some old metadata (hit count or frequency or
231 // something like that) if it's useful for better eviction algorithms?
mgersh7c28e7982017-06-20 23:12:29232 result_changed =
233 entry.error() == OK &&
234 (it->second.error() != entry.error() || delta != DELTA_IDENTICAL);
juliatuttle317860e2016-05-12 14:47:22235 entries_.erase(it);
236 } else {
mgersh7c28e7982017-06-20 23:12:29237 result_changed = true;
juliatuttle317860e2016-05-12 14:47:22238 if (size() == max_entries_)
239 EvictOneEntry(now);
mgersh7c28e7982017-06-20 23:12:29240 RecordSet(SET_INSERT, now, nullptr, entry, DELTA_DISJOINT);
juliatuttle317860e2016-05-12 14:47:22241 }
242
mgershaf3ec7b2017-05-31 23:15:39243 AddEntry(Key(key), Entry(entry, now, ttl, network_changes_));
mgersh7c28e7982017-06-20 23:12:29244
245 if (delegate_ && result_changed)
246 delegate_->ScheduleWrite();
mgershaf3ec7b2017-05-31 23:15:39247}
248
Rob Percival94f21ad2017-11-14 10:20:24249void HostCache::AddEntry(const Key& key, Entry&& entry) {
juliatuttle317860e2016-05-12 14:47:22250 DCHECK_GT(max_entries_, size());
251 DCHECK_EQ(0u, entries_.count(key));
Rob Percival94f21ad2017-11-14 10:20:24252 entries_.emplace(key, std::move(entry));
juliatuttle317860e2016-05-12 14:47:22253 DCHECK_GE(max_entries_, size());
254}
255
256void HostCache::OnNetworkChange() {
257 ++network_changes_;
[email protected]8a00f00a2009-06-12 00:49:38258}
259
mgersh983dbf82017-06-23 20:17:06260void HostCache::set_persistence_delegate(PersistenceDelegate* delegate) {
261 // A PersistenceDelegate shouldn't be added if there already was one, and
262 // shouldn't be removed (by setting to nullptr) if it wasn't previously there.
263 DCHECK_NE(delegate == nullptr, delegate_ == nullptr);
264 delegate_ = delegate;
265}
266
[email protected]9e7bb5082010-06-09 18:07:27267void HostCache::clear() {
gab47aa7da2017-06-02 16:09:43268 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
juliatuttle317860e2016-05-12 14:47:22269 RecordEraseAll(ERASE_CLEAR, base::TimeTicks::Now());
mgersh7c28e7982017-06-20 23:12:29270
271 // Don't bother scheduling a write if there's nothing to clear.
272 if (size() == 0)
273 return;
274
juliatuttle317860e2016-05-12 14:47:22275 entries_.clear();
mgersh7c28e7982017-06-20 23:12:29276 if (delegate_)
277 delegate_->ScheduleWrite();
[email protected]9e7bb5082010-06-09 18:07:27278}
279
msramek94f5656c2016-08-31 17:08:29280void HostCache::ClearForHosts(
281 const base::Callback<bool(const std::string&)>& host_filter) {
gab47aa7da2017-06-02 16:09:43282 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
msramek94f5656c2016-08-31 17:08:29283
284 if (host_filter.is_null()) {
285 clear();
286 return;
287 }
288
mgersh7c28e7982017-06-20 23:12:29289 bool changed = false;
msramek94f5656c2016-08-31 17:08:29290 base::TimeTicks now = base::TimeTicks::Now();
291 for (EntryMap::iterator it = entries_.begin(); it != entries_.end();) {
292 EntryMap::iterator next_it = std::next(it);
293
294 if (host_filter.Run(it->first.hostname)) {
295 RecordErase(ERASE_CLEAR, now, it->second);
296 entries_.erase(it);
mgersh7c28e7982017-06-20 23:12:29297 changed = true;
msramek94f5656c2016-08-31 17:08:29298 }
299
300 it = next_it;
301 }
mgersh7c28e7982017-06-20 23:12:29302
303 if (delegate_ && changed)
304 delegate_->ScheduleWrite();
msramek94f5656c2016-08-31 17:08:29305}
306
mgersh983dbf82017-06-23 20:17:06307void HostCache::GetAsListValue(base::ListValue* entry_list,
308 bool include_staleness) const {
309 DCHECK(entry_list);
310 entry_list->Clear();
mgershaf3ec7b2017-05-31 23:15:39311
312 for (const auto& pair : entries_) {
313 const Key& key = pair.first;
314 const Entry& entry = pair.second;
315
316 std::unique_ptr<base::DictionaryValue> entry_dict(
317 new base::DictionaryValue());
318
319 entry_dict->SetString(kHostnameKey, key.hostname);
320 entry_dict->SetInteger(kAddressFamilyKey,
321 static_cast<int>(key.address_family));
322 entry_dict->SetInteger(kFlagsKey, key.host_resolver_flags);
323
324 if (include_staleness) {
325 entry_dict->SetString(kExpirationKey,
326 NetLog::TickCountToString(entry.expires()));
327 entry_dict->SetInteger(kTtlKey, entry.ttl().InMilliseconds());
328 entry_dict->SetInteger(kNetworkChangesKey, entry.network_changes());
329 } else {
330 // Convert expiration time in TimeTicks to Time for serialization, using a
331 // string because base::Value doesn't handle 64-bit integers.
332 base::Time expiration_time =
333 base::Time::Now() - (base::TimeTicks::Now() - entry.expires());
334 entry_dict->SetString(
335 kExpirationKey,
336 base::Int64ToString(expiration_time.ToInternalValue()));
337 }
338
339 if (entry.error() != OK) {
340 entry_dict->SetInteger(kErrorKey, entry.error());
341 } else {
342 const AddressList& addresses = entry.addresses();
343 // Append all of the resolved addresses.
Jeremy Roman0579ed62017-08-29 15:56:19344 auto addresses_value = std::make_unique<base::ListValue>();
mgershaf3ec7b2017-05-31 23:15:39345 for (size_t i = 0; i < addresses.size(); ++i)
346 addresses_value->AppendString(addresses[i].ToStringWithoutPort());
347 entry_dict->SetList(kAddressesKey, std::move(addresses_value));
348 }
349
350 entry_list->Append(std::move(entry_dict));
351 }
mgershaf3ec7b2017-05-31 23:15:39352}
353
mgersh120380c72017-06-16 18:25:27354bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) {
355 for (auto it = old_cache.begin(); it != old_cache.end(); it++) {
356 const base::DictionaryValue* entry_dict;
mgershaf3ec7b2017-05-31 23:15:39357 if (!it->GetAsDictionary(&entry_dict))
358 return false;
359
360 std::string hostname;
361 int address_family;
362 HostResolverFlags flags;
363 int error = OK;
364 std::string expiration;
365 base::ListValue empty_list;
mgersh120380c72017-06-16 18:25:27366 const base::ListValue* addresses_value = &empty_list;
mgershaf3ec7b2017-05-31 23:15:39367 AddressList address_list;
368
369 if (!entry_dict->GetString(kHostnameKey, &hostname) ||
370 !entry_dict->GetInteger(kFlagsKey, &flags) ||
371 !entry_dict->GetInteger(kAddressFamilyKey, &address_family) ||
372 !entry_dict->GetString(kExpirationKey, &expiration)) {
373 return false;
374 }
375
376 // Only one of these fields should be in the dictionary.
377 if (!entry_dict->GetInteger(kErrorKey, &error) &&
378 !entry_dict->GetList(kAddressesKey, &addresses_value)) {
379 return false;
380 }
381
382 int64_t time_internal;
383 if (!base::StringToInt64(expiration, &time_internal))
384 return false;
385
386 base::TimeTicks expiration_time =
387 base::TimeTicks::Now() -
388 (base::Time::Now() - base::Time::FromInternalValue(time_internal));
389
390 Key key(hostname, static_cast<AddressFamily>(address_family), flags);
391 if (error == OK &&
392 !AddressListFromListValue(addresses_value, &address_list)) {
393 return false;
394 }
395
396 // If the key is already in the cache, assume it's more recent and don't
397 // replace the entry. If the cache is already full, don't bother
398 // prioritizing what to evict, just stop restoring.
399 auto found = entries_.find(key);
400 if (found == entries_.end() && size() < max_entries_) {
Rob Percival94f21ad2017-11-14 10:20:24401 AddEntry(key, Entry(error, address_list, Entry::SOURCE_UNKNOWN,
402 expiration_time, network_changes_ - 1));
mgershaf3ec7b2017-05-31 23:15:39403 }
404 }
Miriam Gershenson2839ef112017-08-30 03:25:37405 restore_size_ = old_cache.GetSize();
mgershaf3ec7b2017-05-31 23:15:39406 return true;
407}
408
[email protected]9e7bb5082010-06-09 18:07:27409size_t HostCache::size() const {
gab47aa7da2017-06-02 16:09:43410 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
[email protected]9e7bb5082010-06-09 18:07:27411 return entries_.size();
412}
413
414size_t HostCache::max_entries() const {
gab47aa7da2017-06-02 16:09:43415 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
juliatuttle317860e2016-05-12 14:47:22416 return max_entries_;
[email protected]9e7bb5082010-06-09 18:07:27417}
418
[email protected]8a00f00a2009-06-12 00:49:38419// static
danakj22f90e72016-04-16 01:55:40420std::unique_ptr<HostCache> HostCache::CreateDefaultCache() {
[email protected]308689682013-01-11 19:26:50421#if defined(ENABLE_BUILT_IN_DNS)
422 const size_t kDefaultMaxEntries = 1000;
423#else
424 const size_t kDefaultMaxEntries = 100;
425#endif
Gayane Petrosyan66f4f74852018-01-04 20:34:14426 return std::make_unique<HostCache>(kDefaultMaxEntries);
[email protected]ba25bb12011-07-21 21:24:24427}
428
juliatuttle317860e2016-05-12 14:47:22429void HostCache::EvictOneEntry(base::TimeTicks now) {
430 DCHECK_LT(0u, entries_.size());
431
432 auto oldest_it = entries_.begin();
433 for (auto it = entries_.begin(); it != entries_.end(); ++it) {
mgersh9cdf01f72017-02-17 23:24:54434 if ((it->second.expires() < oldest_it->second.expires()) &&
435 (it->second.IsStale(now, network_changes_) ||
436 !oldest_it->second.IsStale(now, network_changes_))) {
juliatuttle317860e2016-05-12 14:47:22437 oldest_it = it;
mgersh9cdf01f72017-02-17 23:24:54438 }
[email protected]0de360c62012-11-08 22:26:48439 }
juliatuttle317860e2016-05-12 14:47:22440
juliatuttle317860e2016-05-12 14:47:22441 RecordErase(ERASE_EVICT, now, oldest_it->second);
442 entries_.erase(oldest_it);
443}
444
445void HostCache::RecordSet(SetOutcome outcome,
446 base::TimeTicks now,
447 const Entry* old_entry,
mgersh7c28e7982017-06-20 23:12:29448 const Entry& new_entry,
449 AddressListDeltaType delta) {
juliatuttle317860e2016-05-12 14:47:22450 CACHE_HISTOGRAM_ENUM("Set", outcome, MAX_SET_OUTCOME);
451 switch (outcome) {
452 case SET_INSERT:
453 case SET_UPDATE_VALID:
454 // Nothing to log here.
455 break;
456 case SET_UPDATE_STALE: {
457 EntryStaleness stale;
458 old_entry->GetStaleness(now, network_changes_, &stale);
459 CACHE_HISTOGRAM_TIME("UpdateStale.ExpiredBy", stale.expired_by);
460 CACHE_HISTOGRAM_COUNT("UpdateStale.NetworkChanges",
461 stale.network_changes);
462 CACHE_HISTOGRAM_COUNT("UpdateStale.StaleHits", stale.stale_hits);
463 if (old_entry->error() == OK && new_entry.error() == OK) {
juliatuttle317860e2016-05-12 14:47:22464 RecordUpdateStale(delta, stale);
465 }
466 break;
467 }
468 case MAX_SET_OUTCOME:
469 NOTREACHED();
470 break;
471 }
472}
473
474void HostCache::RecordUpdateStale(AddressListDeltaType delta,
475 const EntryStaleness& stale) {
476 CACHE_HISTOGRAM_ENUM("UpdateStale.AddressListDelta", delta, MAX_DELTA_TYPE);
477 switch (delta) {
478 case DELTA_IDENTICAL:
479 CACHE_HISTOGRAM_TIME("UpdateStale.ExpiredBy_Identical", stale.expired_by);
480 CACHE_HISTOGRAM_COUNT("UpdateStale.NetworkChanges_Identical",
481 stale.network_changes);
482 break;
483 case DELTA_REORDERED:
484 CACHE_HISTOGRAM_TIME("UpdateStale.ExpiredBy_Reordered", stale.expired_by);
485 CACHE_HISTOGRAM_COUNT("UpdateStale.NetworkChanges_Reordered",
486 stale.network_changes);
487 break;
488 case DELTA_OVERLAP:
489 CACHE_HISTOGRAM_TIME("UpdateStale.ExpiredBy_Overlap", stale.expired_by);
490 CACHE_HISTOGRAM_COUNT("UpdateStale.NetworkChanges_Overlap",
491 stale.network_changes);
492 break;
493 case DELTA_DISJOINT:
494 CACHE_HISTOGRAM_TIME("UpdateStale.ExpiredBy_Disjoint", stale.expired_by);
juliatuttleabd7fc82016-05-23 21:07:45495 CACHE_HISTOGRAM_COUNT("UpdateStale.NetworkChanges_Disjoint",
juliatuttle317860e2016-05-12 14:47:22496 stale.network_changes);
497 break;
498 case MAX_DELTA_TYPE:
499 NOTREACHED();
500 break;
501 }
502}
503
504void HostCache::RecordLookup(LookupOutcome outcome,
505 base::TimeTicks now,
506 const Entry* entry) {
507 CACHE_HISTOGRAM_ENUM("Lookup", outcome, MAX_LOOKUP_OUTCOME);
508 switch (outcome) {
509 case LOOKUP_MISS_ABSENT:
510 case LOOKUP_MISS_STALE:
511 case LOOKUP_HIT_VALID:
512 // Nothing to log here.
513 break;
514 case LOOKUP_HIT_STALE:
515 CACHE_HISTOGRAM_TIME("LookupStale.ExpiredBy", now - entry->expires());
516 CACHE_HISTOGRAM_COUNT("LookupStale.NetworkChanges",
517 network_changes_ - entry->network_changes());
518 break;
519 case MAX_LOOKUP_OUTCOME:
520 NOTREACHED();
521 break;
522 }
523}
524
525void HostCache::RecordErase(EraseReason reason,
526 base::TimeTicks now,
527 const Entry& entry) {
528 HostCache::EntryStaleness stale;
529 entry.GetStaleness(now, network_changes_, &stale);
530 CACHE_HISTOGRAM_ENUM("Erase", reason, MAX_ERASE_REASON);
531 if (stale.is_stale()) {
juliatuttleabd7fc82016-05-23 21:07:45532 CACHE_HISTOGRAM_TIME("EraseStale.ExpiredBy", stale.expired_by);
533 CACHE_HISTOGRAM_COUNT("EraseStale.NetworkChanges", stale.network_changes);
534 CACHE_HISTOGRAM_COUNT("EraseStale.StaleHits", entry.stale_hits());
[email protected]0de360c62012-11-08 22:26:48535 } else {
juliatuttleabd7fc82016-05-23 21:07:45536 CACHE_HISTOGRAM_TIME("EraseValid.ValidFor", -stale.expired_by);
[email protected]0de360c62012-11-08 22:26:48537 }
538}
539
juliatuttle317860e2016-05-12 14:47:22540void HostCache::RecordEraseAll(EraseReason reason, base::TimeTicks now) {
541 for (const auto& it : entries_)
542 RecordErase(reason, now, it.second);
543}
544
Rob Percivalbc658a22017-12-13 08:24:42545bool HostCache::HasEntry(base::StringPiece hostname,
546 HostCache::Entry::Source* source_out,
547 HostCache::EntryStaleness* stale_out) {
548 net::HostCache::Key cache_key;
549 hostname.CopyToString(&cache_key.hostname);
550
551 const HostCache::Entry* entry =
552 LookupStale(cache_key, base::TimeTicks::Now(), stale_out);
553 if (!entry) {
554 // Might not have found the cache entry because the address_family or
555 // host_resolver_flags in cache_key do not match those used for the
556 // original DNS lookup. Try another common combination of address_family
557 // and host_resolver_flags in an attempt to find a matching cache entry.
558 cache_key.address_family = net::ADDRESS_FAMILY_IPV4;
559 cache_key.host_resolver_flags =
560 net::HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
561 entry = LookupStale(cache_key, base::TimeTicks::Now(), stale_out);
562 if (!entry)
563 return false;
564 }
565
566 if (source_out != nullptr)
567 *source_out = entry->source();
568
569 return true;
570}
571
[email protected]8a00f00a2009-06-12 00:49:38572} // namespace net