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

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

Issue 2791653002: Serialize and deserialize HostCache for persistence (Closed)
Patch Set: fix warning Created 3 years, 6 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
« no previous file with comments | « net/dns/host_cache.h ('k') | net/dns/host_cache_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <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
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
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
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
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
OLDNEW
« no previous file with comments | « 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