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 "net/dns/host_cache.h" | 5 #include "net/dns/host_cache.h" |
6 | 6 |
| 7 #include <utility> |
| 8 |
7 #include "base/logging.h" | 9 #include "base/logging.h" |
8 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
9 #include "base/metrics/field_trial.h" | 11 #include "base/metrics/field_trial.h" |
10 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
11 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
12 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
| 15 #include "base/values.h" |
13 #include "net/base/net_errors.h" | 16 #include "net/base/net_errors.h" |
14 #include "net/base/trace_constants.h" | 17 #include "net/base/trace_constants.h" |
15 #include "net/dns/dns_util.h" | 18 #include "net/dns/dns_util.h" |
| 19 #include "net/log/net_log.h" |
16 | 20 |
17 namespace net { | 21 namespace net { |
18 | 22 |
19 namespace { | 23 namespace { |
20 | 24 |
21 #define CACHE_HISTOGRAM_TIME(name, time) \ | 25 #define CACHE_HISTOGRAM_TIME(name, time) \ |
22 UMA_HISTOGRAM_LONG_TIMES("DNS.HostCache." name, time) | 26 UMA_HISTOGRAM_LONG_TIMES("DNS.HostCache." name, time) |
23 | 27 |
24 #define CACHE_HISTOGRAM_COUNT(name, count) \ | 28 #define CACHE_HISTOGRAM_COUNT(name, count) \ |
25 UMA_HISTOGRAM_COUNTS_1000("DNS.HostCache." name, count) | 29 UMA_HISTOGRAM_COUNTS_1000("DNS.HostCache." name, count) |
26 | 30 |
27 #define CACHE_HISTOGRAM_ENUM(name, value, max) \ | 31 #define CACHE_HISTOGRAM_ENUM(name, value, max) \ |
28 UMA_HISTOGRAM_ENUMERATION("DNS.HostCache." name, value, max) | 32 UMA_HISTOGRAM_ENUMERATION("DNS.HostCache." name, value, max) |
29 | 33 |
| 34 // String constants for dictionary keys. |
| 35 const char kHostnameKey[] = "hostname"; |
| 36 const char kAddressFamilyKey[] = "address_family"; |
| 37 const char kFlagsKey[] = "flags"; |
| 38 const char kExpirationKey[] = "expiration"; |
| 39 const char kTtlKey[] = "ttl"; |
| 40 const char kNetworkChangesKey[] = "network_changes"; |
| 41 const char kErrorKey[] = "error"; |
| 42 const char kAddressesKey[] = "addresses"; |
| 43 |
| 44 bool AddressListFromListValue(base::ListValue* value, AddressList* list) { |
| 45 list->clear(); |
| 46 for (base::ListValue::const_iterator it = value->begin(); it != value->end(); |
| 47 it++) { |
| 48 IPAddress address; |
| 49 std::string addr_string; |
| 50 if (!it->GetAsString(&addr_string) || |
| 51 !address.AssignFromIPLiteral(addr_string)) { |
| 52 return false; |
| 53 } |
| 54 list->push_back(IPEndPoint(address, 0)); |
| 55 } |
| 56 return true; |
| 57 } |
| 58 |
30 } // namespace | 59 } // namespace |
31 | 60 |
32 // Used in histograms; do not modify existing values. | 61 // Used in histograms; do not modify existing values. |
33 enum HostCache::SetOutcome : int { | 62 enum HostCache::SetOutcome : int { |
34 SET_INSERT = 0, | 63 SET_INSERT = 0, |
35 SET_UPDATE_VALID = 1, | 64 SET_UPDATE_VALID = 1, |
36 SET_UPDATE_STALE = 2, | 65 SET_UPDATE_STALE = 2, |
37 MAX_SET_OUTCOME | 66 MAX_SET_OUTCOME |
38 }; | 67 }; |
39 | 68 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 base::TimeDelta ttl, | 102 base::TimeDelta ttl, |
74 int network_changes) | 103 int network_changes) |
75 : error_(entry.error()), | 104 : error_(entry.error()), |
76 addresses_(entry.addresses()), | 105 addresses_(entry.addresses()), |
77 ttl_(entry.ttl()), | 106 ttl_(entry.ttl()), |
78 expires_(now + ttl), | 107 expires_(now + ttl), |
79 network_changes_(network_changes), | 108 network_changes_(network_changes), |
80 total_hits_(0), | 109 total_hits_(0), |
81 stale_hits_(0) {} | 110 stale_hits_(0) {} |
82 | 111 |
| 112 HostCache::Entry::Entry(int error, |
| 113 const AddressList& addresses, |
| 114 base::TimeTicks expires, |
| 115 int network_changes) |
| 116 : error_(error), |
| 117 addresses_(addresses), |
| 118 ttl_(base::TimeDelta::FromSeconds(-1)), |
| 119 expires_(expires), |
| 120 network_changes_(network_changes), |
| 121 total_hits_(0), |
| 122 stale_hits_(0) {} |
| 123 |
83 bool HostCache::Entry::IsStale(base::TimeTicks now, int network_changes) const { | 124 bool HostCache::Entry::IsStale(base::TimeTicks now, int network_changes) const { |
84 EntryStaleness stale; | 125 EntryStaleness stale; |
85 stale.expired_by = now - expires_; | 126 stale.expired_by = now - expires_; |
86 stale.network_changes = network_changes - network_changes_; | 127 stale.network_changes = network_changes - network_changes_; |
87 stale.stale_hits = stale_hits_; | 128 stale.stale_hits = stale_hits_; |
88 return stale.is_stale(); | 129 return stale.is_stale(); |
89 } | 130 } |
90 | 131 |
91 void HostCache::Entry::CountHit(bool hit_is_stale) { | 132 void HostCache::Entry::CountHit(bool hit_is_stale) { |
92 ++total_hits_; | 133 ++total_hits_; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 entry); | 216 entry); |
176 // TODO(juliatuttle): Remember some old metadata (hit count or frequency or | 217 // TODO(juliatuttle): Remember some old metadata (hit count or frequency or |
177 // something like that) if it's useful for better eviction algorithms? | 218 // something like that) if it's useful for better eviction algorithms? |
178 entries_.erase(it); | 219 entries_.erase(it); |
179 } else { | 220 } else { |
180 if (size() == max_entries_) | 221 if (size() == max_entries_) |
181 EvictOneEntry(now); | 222 EvictOneEntry(now); |
182 RecordSet(SET_INSERT, now, nullptr, entry); | 223 RecordSet(SET_INSERT, now, nullptr, entry); |
183 } | 224 } |
184 | 225 |
| 226 AddEntry(Key(key), Entry(entry, now, ttl, network_changes_)); |
| 227 } |
| 228 |
| 229 void HostCache::AddEntry(const Key& key, const Entry& entry) { |
185 DCHECK_GT(max_entries_, size()); | 230 DCHECK_GT(max_entries_, size()); |
186 DCHECK_EQ(0u, entries_.count(key)); | 231 DCHECK_EQ(0u, entries_.count(key)); |
187 entries_.insert( | 232 entries_.insert(std::make_pair(key, entry)); |
188 std::make_pair(Key(key), Entry(entry, now, ttl, network_changes_))); | |
189 DCHECK_GE(max_entries_, size()); | 233 DCHECK_GE(max_entries_, size()); |
190 } | 234 } |
191 | 235 |
192 void HostCache::OnNetworkChange() { | 236 void HostCache::OnNetworkChange() { |
193 ++network_changes_; | 237 ++network_changes_; |
194 } | 238 } |
195 | 239 |
196 void HostCache::clear() { | 240 void HostCache::clear() { |
197 DCHECK(CalledOnValidThread()); | 241 DCHECK(CalledOnValidThread()); |
198 RecordEraseAll(ERASE_CLEAR, base::TimeTicks::Now()); | 242 RecordEraseAll(ERASE_CLEAR, base::TimeTicks::Now()); |
(...skipping 15 matching lines...) Expand all Loading... |
214 | 258 |
215 if (host_filter.Run(it->first.hostname)) { | 259 if (host_filter.Run(it->first.hostname)) { |
216 RecordErase(ERASE_CLEAR, now, it->second); | 260 RecordErase(ERASE_CLEAR, now, it->second); |
217 entries_.erase(it); | 261 entries_.erase(it); |
218 } | 262 } |
219 | 263 |
220 it = next_it; | 264 it = next_it; |
221 } | 265 } |
222 } | 266 } |
223 | 267 |
| 268 std::unique_ptr<base::ListValue> HostCache::GetAsListValue( |
| 269 bool include_staleness) const { |
| 270 std::unique_ptr<base::ListValue> entry_list(new base::ListValue()); |
| 271 |
| 272 for (const auto& pair : entries_) { |
| 273 const Key& key = pair.first; |
| 274 const Entry& entry = pair.second; |
| 275 |
| 276 std::unique_ptr<base::DictionaryValue> entry_dict( |
| 277 new base::DictionaryValue()); |
| 278 |
| 279 entry_dict->SetString(kHostnameKey, key.hostname); |
| 280 entry_dict->SetInteger(kAddressFamilyKey, |
| 281 static_cast<int>(key.address_family)); |
| 282 entry_dict->SetInteger(kFlagsKey, key.host_resolver_flags); |
| 283 |
| 284 if (include_staleness) { |
| 285 entry_dict->SetString(kExpirationKey, |
| 286 NetLog::TickCountToString(entry.expires())); |
| 287 entry_dict->SetInteger(kTtlKey, entry.ttl().InMilliseconds()); |
| 288 entry_dict->SetInteger(kNetworkChangesKey, entry.network_changes()); |
| 289 } else { |
| 290 // Convert expiration time in TimeTicks to Time for serialization, using a |
| 291 // string because base::Value doesn't handle 64-bit integers. |
| 292 base::Time expiration_time = |
| 293 base::Time::Now() - (base::TimeTicks::Now() - entry.expires()); |
| 294 entry_dict->SetString( |
| 295 kExpirationKey, |
| 296 base::Int64ToString(expiration_time.ToInternalValue())); |
| 297 } |
| 298 |
| 299 if (entry.error() != OK) { |
| 300 entry_dict->SetInteger(kErrorKey, entry.error()); |
| 301 } else { |
| 302 const AddressList& addresses = entry.addresses(); |
| 303 // Append all of the resolved addresses. |
| 304 auto addresses_value = base::MakeUnique<base::ListValue>(); |
| 305 for (size_t i = 0; i < addresses.size(); ++i) |
| 306 addresses_value->AppendString(addresses[i].ToStringWithoutPort()); |
| 307 entry_dict->SetList(kAddressesKey, std::move(addresses_value)); |
| 308 } |
| 309 |
| 310 entry_list->Append(std::move(entry_dict)); |
| 311 } |
| 312 |
| 313 return entry_list; |
| 314 } |
| 315 |
| 316 // TODO(mgersh): Add histograms to track failures. |
| 317 bool HostCache::RestoreFromListValue(base::ListValue& old_cache) { |
| 318 for (base::ListValue::iterator it = old_cache.begin(); it != old_cache.end(); |
| 319 it++) { |
| 320 base::DictionaryValue* entry_dict; |
| 321 if (!it->GetAsDictionary(&entry_dict)) |
| 322 return false; |
| 323 |
| 324 std::string hostname; |
| 325 int address_family; |
| 326 HostResolverFlags flags; |
| 327 int error = OK; |
| 328 std::string expiration; |
| 329 base::ListValue empty_list; |
| 330 base::ListValue* addresses_value = &empty_list; |
| 331 AddressList address_list; |
| 332 |
| 333 if (!entry_dict->GetString(kHostnameKey, &hostname) || |
| 334 !entry_dict->GetInteger(kFlagsKey, &flags) || |
| 335 !entry_dict->GetInteger(kAddressFamilyKey, &address_family) || |
| 336 !entry_dict->GetString(kExpirationKey, &expiration)) { |
| 337 return false; |
| 338 } |
| 339 |
| 340 // Only one of these fields should be in the dictionary. |
| 341 if (!entry_dict->GetInteger(kErrorKey, &error) && |
| 342 !entry_dict->GetList(kAddressesKey, &addresses_value)) { |
| 343 return false; |
| 344 } |
| 345 |
| 346 int64_t time_internal; |
| 347 if (!base::StringToInt64(expiration, &time_internal)) |
| 348 return false; |
| 349 |
| 350 base::TimeTicks expiration_time = |
| 351 base::TimeTicks::Now() - |
| 352 (base::Time::Now() - base::Time::FromInternalValue(time_internal)); |
| 353 |
| 354 Key key(hostname, static_cast<AddressFamily>(address_family), flags); |
| 355 if (error == OK && |
| 356 !AddressListFromListValue(addresses_value, &address_list)) { |
| 357 return false; |
| 358 } |
| 359 |
| 360 // If the key is already in the cache, assume it's more recent and don't |
| 361 // replace the entry. If the cache is already full, don't bother |
| 362 // prioritizing what to evict, just stop restoring. |
| 363 auto found = entries_.find(key); |
| 364 if (found == entries_.end() && size() < max_entries_) { |
| 365 AddEntry(key, Entry(error, address_list, expiration_time, |
| 366 network_changes_ - 1)); |
| 367 } |
| 368 } |
| 369 return true; |
| 370 } |
| 371 |
224 size_t HostCache::size() const { | 372 size_t HostCache::size() const { |
225 DCHECK(CalledOnValidThread()); | 373 DCHECK(CalledOnValidThread()); |
226 return entries_.size(); | 374 return entries_.size(); |
227 } | 375 } |
228 | 376 |
229 size_t HostCache::max_entries() const { | 377 size_t HostCache::max_entries() const { |
230 DCHECK(CalledOnValidThread()); | 378 DCHECK(CalledOnValidThread()); |
231 return max_entries_; | 379 return max_entries_; |
232 } | 380 } |
233 | 381 |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 CACHE_HISTOGRAM_TIME("EraseValid.ValidFor", -stale.expired_by); | 509 CACHE_HISTOGRAM_TIME("EraseValid.ValidFor", -stale.expired_by); |
362 } | 510 } |
363 } | 511 } |
364 | 512 |
365 void HostCache::RecordEraseAll(EraseReason reason, base::TimeTicks now) { | 513 void HostCache::RecordEraseAll(EraseReason reason, base::TimeTicks now) { |
366 for (const auto& it : entries_) | 514 for (const auto& it : entries_) |
367 RecordErase(reason, now, it.second); | 515 RecordErase(reason, now, it.second); |
368 } | 516 } |
369 | 517 |
370 } // namespace net | 518 } // namespace net |
OLD | NEW |