blob: 0477ddbc3be89d25daa26fcea7f4185b9831802b [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
initial.commit09911bf2008-07-26 23:55:295#include "chrome/browser/net/dns_master.h"
6
[email protected]1933eb202009-02-19 18:23:257#include <algorithm>
[email protected]319d9e6f2009-02-18 19:47:218#include <set>
[email protected]1933eb202009-02-19 18:23:259#include <sstream>
initial.commit09911bf2008-07-26 23:55:2910
[email protected]1933eb202009-02-19 18:23:2511#include "base/compiler_specific.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/histogram.h"
[email protected]fd2f8afe2009-06-11 21:53:5513#include "base/message_loop.h"
[email protected]1933eb202009-02-19 18:23:2514#include "base/lock.h"
initial.commit09911bf2008-07-26 23:55:2915#include "base/stats_counters.h"
[email protected]21dae9b2008-11-06 23:32:5316#include "base/string_util.h"
[email protected]1933eb202009-02-19 18:23:2517#include "base/time.h"
18#include "net/base/address_list.h"
19#include "net/base/completion_callback.h"
20#include "net/base/host_resolver.h"
21#include "net/base/net_errors.h"
[email protected]e1acf6f2008-10-27 20:43:3322
initial.commit09911bf2008-07-26 23:55:2923namespace chrome_browser_net {
24
[email protected]1933eb202009-02-19 18:23:2525class DnsMaster::LookupRequest {
26 public:
[email protected]fd2f8afe2009-06-11 21:53:5527 LookupRequest(DnsMaster* master,
28 net::HostResolver* /*host_resolver*/,
29 const std::string& hostname)
[email protected]1933eb202009-02-19 18:23:2530 : ALLOW_THIS_IN_INITIALIZER_LIST(
31 net_callback_(this, &LookupRequest::OnLookupFinished)),
32 master_(master),
33 hostname_(hostname) {
initial.commit09911bf2008-07-26 23:55:2934 }
[email protected]1933eb202009-02-19 18:23:2535
36 bool Start() {
37 const int result = resolver_.Resolve(hostname_, 80, &addresses_,
38 &net_callback_);
39 return (result == net::ERR_IO_PENDING);
40 }
41
42 private:
43 void OnLookupFinished(int result) {
44 master_->OnLookupFinished(this, hostname_, result == net::OK);
45 }
46
47 // HostResolver will call us using this callback when resolution is complete.
48 net::CompletionCallbackImpl<LookupRequest> net_callback_;
49
50 DnsMaster* master_; // Master which started us.
51
52 const std::string hostname_; // Hostname to resolve.
53 net::HostResolver resolver_;
54 net::AddressList addresses_;
55
56 DISALLOW_COPY_AND_ASSIGN(LookupRequest);
57};
58
[email protected]fd2f8afe2009-06-11 21:53:5559DnsMaster::DnsMaster(net::HostResolver* host_resolver,
60 MessageLoop* host_resolver_loop,
61 size_t max_concurrent)
[email protected]e085c302009-06-01 18:31:3662 : peak_pending_lookups_(0),
63 shutdown_(false),
[email protected]fd2f8afe2009-06-11 21:53:5564 max_concurrent_lookups_(max_concurrent),
65 host_resolver_(host_resolver),
66 host_resolver_loop_(host_resolver_loop) {
[email protected]1933eb202009-02-19 18:23:2567}
68
69DnsMaster::~DnsMaster() {
70 DCHECK(shutdown_);
71}
72
73void DnsMaster::Shutdown() {
74 AutoLock auto_lock(lock_);
75
76 DCHECK(!shutdown_);
77 shutdown_ = true;
78
79 std::set<LookupRequest*>::iterator it;
80 for (it = pending_lookups_.begin(); it != pending_lookups_.end(); ++it)
81 delete *it;
initial.commit09911bf2008-07-26 23:55:2982}
83
84// Overloaded Resolve() to take a vector of names.
[email protected]21dae9b2008-11-06 23:32:5385void DnsMaster::ResolveList(const NameList& hostnames,
86 DnsHostInfo::ResolutionMotivation motivation) {
[email protected]1933eb202009-02-19 18:23:2587 AutoLock auto_lock(lock_);
initial.commit09911bf2008-07-26 23:55:2988
[email protected]fd2f8afe2009-06-11 21:53:5589 // We need to run this on |host_resolver_loop_| since we may access
90 // |host_resolver_| which is not thread safe.
91 if (MessageLoop::current() != host_resolver_loop_) {
92 host_resolver_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
93 &DnsMaster::ResolveList, hostnames, motivation));
94 return;
95 }
96
[email protected]1933eb202009-02-19 18:23:2597 NameList::const_iterator it;
98 for (it = hostnames.begin(); it < hostnames.end(); ++it)
99 PreLockedResolve(*it, motivation);
initial.commit09911bf2008-07-26 23:55:29100}
101
102// Basic Resolve() takes an invidual name, and adds it
103// to the queue.
[email protected]21dae9b2008-11-06 23:32:53104void DnsMaster::Resolve(const std::string& hostname,
105 DnsHostInfo::ResolutionMotivation motivation) {
initial.commit09911bf2008-07-26 23:55:29106 if (0 == hostname.length())
107 return;
[email protected]1933eb202009-02-19 18:23:25108 AutoLock auto_lock(lock_);
[email protected]fd2f8afe2009-06-11 21:53:55109
110 // We need to run this on |host_resolver_loop_| since we may access
111 // |host_resolver_| which is not thread safe.
112 if (MessageLoop::current() != host_resolver_loop_) {
113 host_resolver_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
114 &DnsMaster::Resolve, hostname, motivation));
115 return;
116 }
117
[email protected]1933eb202009-02-19 18:23:25118 PreLockedResolve(hostname, motivation);
initial.commit09911bf2008-07-26 23:55:29119}
120
[email protected]21dae9b2008-11-06 23:32:53121bool DnsMaster::AccruePrefetchBenefits(const GURL& referrer,
122 DnsHostInfo* navigation_info) {
123 std::string hostname = navigation_info->hostname();
124
125 AutoLock auto_lock(lock_);
126 Results::iterator it = results_.find(hostname);
127 if (it == results_.end()) {
128 // Remain under lock to assure static HISTOGRAM constructor is safely run.
129 // Use UMA histogram to quantify potential future gains here.
[email protected]553dba62009-02-24 19:08:23130 UMA_HISTOGRAM_LONG_TIMES("DNS.UnexpectedResolutionL",
[email protected]21dae9b2008-11-06 23:32:53131 navigation_info->resolve_duration());
132 navigation_info->DLogResultsStats("DNS UnexpectedResolution");
133
134 NonlinkNavigation(referrer, navigation_info);
135 return false;
136 }
137 DnsHostInfo& prefetched_host_info(it->second);
138
139 // Sometimes a host is used as a subresource by several referrers, so it is
140 // in our list, but was never motivated by a page-link-scan. In that case, it
141 // really is an "unexpected" navigation, and we should tally it, and augment
142 // our referrers_.
143 bool referrer_based_prefetch = !prefetched_host_info.was_linked();
144 if (referrer_based_prefetch) {
145 // This wasn't the first time this host refered to *some* referrer.
146 NonlinkNavigation(referrer, navigation_info);
147 }
148
149 DnsBenefit benefit = prefetched_host_info.AccruePrefetchBenefits(
150 navigation_info);
151 switch (benefit) {
152 case PREFETCH_NAME_FOUND:
153 case PREFETCH_NAME_NONEXISTANT:
154 // Remain under lock to push data.
155 cache_hits_.push_back(*navigation_info);
156 if (referrer_based_prefetch) {
[email protected]b7779a42008-12-20 11:51:23157 std::string motivating_referrer(
[email protected]21dae9b2008-11-06 23:32:53158 prefetched_host_info.referring_hostname());
159 if (!motivating_referrer.empty()) {
160 referrers_[motivating_referrer].AccrueValue(
161 navigation_info->benefits_remaining(), hostname);
162 }
163 }
164 return true;
165
166 case PREFETCH_CACHE_EVICTION:
167 // Remain under lock to push data.
168 cache_eviction_map_[hostname] = *navigation_info;
169 return false;
170
171 case PREFETCH_NO_BENEFIT:
172 // Prefetch never hit the network. Name was pre-cached.
173 return false;
174
175 default:
176 DCHECK(false);
177 return false;
178 }
179}
180
181void DnsMaster::NonlinkNavigation(const GURL& referrer,
182 DnsHostInfo* navigation_info) {
183 std::string referring_host = referrer.host();
184 if (referring_host.empty() || referring_host == navigation_info->hostname())
185 return;
186
187 referrers_[referring_host].SuggestHost(navigation_info->hostname());
188}
189
190void DnsMaster::NavigatingTo(const std::string& host_name) {
[email protected]1933eb202009-02-19 18:23:25191 AutoLock auto_lock(lock_);
[email protected]fd2f8afe2009-06-11 21:53:55192
193 // We need to run this on |host_resolver_loop_| since we may access
194 // |host_resolver_| which is not thread safe.
195 if (MessageLoop::current() != host_resolver_loop_) {
196 host_resolver_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
197 &DnsMaster::NavigatingTo, host_name));
198 return;
199 }
200
[email protected]1933eb202009-02-19 18:23:25201 Referrers::iterator it = referrers_.find(host_name);
202 if (referrers_.end() == it)
203 return;
204 Referrer* referrer = &(it->second);
205 for (Referrer::iterator future_host = referrer->begin();
206 future_host != referrer->end(); ++future_host) {
207 DnsHostInfo* queued_info = PreLockedResolve(
208 future_host->first,
209 DnsHostInfo::LEARNED_REFERAL_MOTIVATED);
210 if (queued_info)
211 queued_info->SetReferringHostname(host_name);
initial.commit09911bf2008-07-26 23:55:29212 }
213}
214
initial.commit09911bf2008-07-26 23:55:29215// Provide sort order so all .com's are together, etc.
216struct RightToLeftStringSorter {
217 bool operator()(const std::string& left, const std::string& right) const {
[email protected]21dae9b2008-11-06 23:32:53218 if (left == right) return true;
219 size_t left_already_matched = left.size();
220 size_t right_already_matched = right.size();
221
222 // Ensure both strings have characters.
223 if (!left_already_matched) return true;
224 if (!right_already_matched) return false;
225
226 // Watch for trailing dot, so we'll always be safe to go one beyond dot.
227 if ('.' == left[left.size() - 1]) {
228 if ('.' != right[right.size() - 1])
initial.commit09911bf2008-07-26 23:55:29229 return true;
[email protected]21dae9b2008-11-06 23:32:53230 // Both have dots at end of string.
231 --left_already_matched;
232 --right_already_matched;
233 } else {
234 if ('.' == right[right.size() - 1])
235 return false;
236 }
237
238 while (1) {
239 if (!left_already_matched) return true;
240 if (!right_already_matched) return false;
241
242 size_t left_length, right_length;
243 size_t left_start = left.find_last_of('.', left_already_matched - 1);
244 if (std::string::npos == left_start) {
245 left_length = left_already_matched;
246 left_already_matched = left_start = 0;
247 } else {
248 left_length = left_already_matched - left_start;
249 left_already_matched = left_start;
250 ++left_start; // Don't compare the dot.
251 }
252 size_t right_start = right.find_last_of('.', right_already_matched - 1);
253 if (std::string::npos == right_start) {
254 right_length = right_already_matched;
255 right_already_matched = right_start = 0;
256 } else {
257 right_length = right_already_matched - right_start;
258 right_already_matched = right_start;
259 ++right_start; // Don't compare the dot.
260 }
261
262 int diff = left.compare(left_start, left.size(),
263 right, right_start, right.size());
264 if (diff > 0) return false;
265 if (diff < 0) return true;
initial.commit09911bf2008-07-26 23:55:29266 }
267 }
268};
269
[email protected]21dae9b2008-11-06 23:32:53270void DnsMaster::GetHtmlReferrerLists(std::string* output) {
271 AutoLock auto_lock(lock_);
272 if (referrers_.empty())
273 return;
274
275 // TODO(jar): Remove any plausible JavaScript from names before displaying.
276
277 typedef std::set<std::string, struct RightToLeftStringSorter> SortedNames;
278 SortedNames sorted_names;
279
280 for (Referrers::iterator it = referrers_.begin();
281 referrers_.end() != it; ++it)
282 sorted_names.insert(it->first);
283
284 output->append("<br><table border>");
285 StringAppendF(output,
286 "<tr><th>%s</th><th>%s</th></tr>",
287 "Host for Page", "Host(s) in Page<br>(benefits in ms)");
288
289 for (SortedNames::iterator it = sorted_names.begin();
290 sorted_names.end() != it; ++it) {
291 Referrer* referrer = &(referrers_[*it]);
292 StringAppendF(output, "<tr align=right><td>%s</td><td>", it->c_str());
293 output->append("<table>");
294 for (Referrer::iterator future_host = referrer->begin();
295 future_host != referrer->end(); ++future_host) {
296 StringAppendF(output, "<tr align=right><td>(%dms)</td><td>%s</td></tr>",
297 static_cast<int>(future_host->second.latency().InMilliseconds()),
298 future_host->first.c_str());
299 }
300 output->append("</table></td></tr>");
301 }
302 output->append("</table>");
303}
304
initial.commit09911bf2008-07-26 23:55:29305void DnsMaster::GetHtmlInfo(std::string* output) {
306 // Local lists for calling DnsHostInfo
307 DnsHostInfo::DnsInfoTable cache_hits;
308 DnsHostInfo::DnsInfoTable cache_evictions;
309 DnsHostInfo::DnsInfoTable name_not_found;
310 DnsHostInfo::DnsInfoTable network_hits;
311 DnsHostInfo::DnsInfoTable already_cached;
312
313 // Get copies of all useful data under protection of a lock.
314 typedef std::map<std::string, DnsHostInfo, RightToLeftStringSorter> Snapshot;
315 Snapshot snapshot;
316 {
317 AutoLock auto_lock(lock_);
318 // DnsHostInfo supports value semantics, so we can do a shallow copy.
319 for (Results::iterator it(results_.begin()); it != results_.end(); it++) {
320 snapshot[it->first] = it->second;
321 }
322 for (Results::iterator it(cache_eviction_map_.begin());
323 it != cache_eviction_map_.end();
324 it++) {
325 cache_evictions.push_back(it->second);
326 }
327 // Reverse list as we copy cache hits, so that new hits are at the top.
328 size_t index = cache_hits_.size();
329 while (index > 0) {
330 index--;
331 cache_hits.push_back(cache_hits_[index]);
332 }
333 }
334
335 // Partition the DnsHostInfo's into categories.
336 for (Snapshot::iterator it(snapshot.begin()); it != snapshot.end(); it++) {
337 if (it->second.was_nonexistant()) {
338 name_not_found.push_back(it->second);
339 continue;
340 }
341 if (!it->second.was_found())
342 continue; // Still being processed.
[email protected]1933eb202009-02-19 18:23:25343 if (base::TimeDelta() != it->second.benefits_remaining()) {
initial.commit09911bf2008-07-26 23:55:29344 network_hits.push_back(it->second); // With no benefit yet.
345 continue;
346 }
347 if (DnsHostInfo::kMaxNonNetworkDnsLookupDuration >
348 it->second.resolve_duration()) {
349 already_cached.push_back(it->second);
350 continue;
351 }
352 // Remaining case is where prefetch benefit was significant, and was used.
353 // Since we shot those cases as historical hits, we won't bother here.
354 }
355
356 bool brief = false;
357#ifdef NDEBUG
358 brief = true;
359#endif // NDEBUG
360
361 // Call for display of each table, along with title.
362 DnsHostInfo::GetHtmlTable(cache_hits,
363 "Prefetching DNS records produced benefits for ", false, output);
364 DnsHostInfo::GetHtmlTable(cache_evictions,
365 "Cache evictions negated DNS prefetching benefits for ", brief, output);
366 DnsHostInfo::GetHtmlTable(network_hits,
367 "Prefetching DNS records was not yet beneficial for ", brief, output);
368 DnsHostInfo::GetHtmlTable(already_cached,
369 "Previously cached resolutions were found for ", brief, output);
370 DnsHostInfo::GetHtmlTable(name_not_found,
371 "Prefetching DNS records revealed non-existance for ", brief, output);
372}
373
[email protected]21dae9b2008-11-06 23:32:53374DnsHostInfo* DnsMaster::PreLockedResolve(
375 const std::string& hostname,
376 DnsHostInfo::ResolutionMotivation motivation) {
initial.commit09911bf2008-07-26 23:55:29377 // DCHECK(We have the lock);
initial.commit09911bf2008-07-26 23:55:29378 DCHECK(0 != hostname.length());
379
[email protected]1933eb202009-02-19 18:23:25380 if (shutdown_)
381 return NULL;
382
initial.commit09911bf2008-07-26 23:55:29383 DnsHostInfo* info = &results_[hostname];
384 info->SetHostname(hostname); // Initialize or DCHECK.
385 // TODO(jar): I need to discard names that have long since expired.
386 // Currently we only add to the domain map :-/
387
388 DCHECK(info->HasHostname(hostname));
389
initial.commit09911bf2008-07-26 23:55:29390 if (!info->NeedsDnsUpdate(hostname)) {
391 info->DLogResultsStats("DNS PrefetchNotUpdated");
[email protected]21dae9b2008-11-06 23:32:53392 return NULL;
initial.commit09911bf2008-07-26 23:55:29393 }
394
[email protected]21dae9b2008-11-06 23:32:53395 info->SetQueuedState(motivation);
[email protected]a20bc092009-06-05 01:34:20396 work_queue_.Push(hostname, motivation);
[email protected]1933eb202009-02-19 18:23:25397 PreLockedScheduleLookups();
[email protected]21dae9b2008-11-06 23:32:53398 return info;
initial.commit09911bf2008-07-26 23:55:29399}
400
[email protected]1933eb202009-02-19 18:23:25401void DnsMaster::PreLockedScheduleLookups() {
[email protected]fd2f8afe2009-06-11 21:53:55402 // We need to run this on |host_resolver_loop_| since we may access
403 // |host_resolver_| which is not thread safe.
404 DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
405
[email protected]a20bc092009-06-05 01:34:20406 while (!work_queue_.IsEmpty() &&
[email protected]e085c302009-06-01 18:31:36407 pending_lookups_.size() < max_concurrent_lookups_) {
[email protected]a20bc092009-06-05 01:34:20408 const std::string hostname(work_queue_.Pop());
[email protected]1933eb202009-02-19 18:23:25409 DnsHostInfo* info = &results_[hostname];
410 DCHECK(info->HasHostname(hostname));
initial.commit09911bf2008-07-26 23:55:29411 info->SetAssignedState();
412
[email protected]a20bc092009-06-05 01:34:20413 if (PreLockedCongestionControlPerformed(info)) {
414 DCHECK(work_queue_.IsEmpty());
415 return;
416 }
417
[email protected]fd2f8afe2009-06-11 21:53:55418 LookupRequest* request = new LookupRequest(this, host_resolver_, hostname);
[email protected]1933eb202009-02-19 18:23:25419 if (request->Start()) {
[email protected]fd2f8afe2009-06-11 21:53:55420 // Will complete asynchronously.
[email protected]1933eb202009-02-19 18:23:25421 pending_lookups_.insert(request);
422 peak_pending_lookups_ = std::max(peak_pending_lookups_,
423 pending_lookups_.size());
424 } else {
[email protected]fd2f8afe2009-06-11 21:53:55425 // Completed synchyronously (was already cached by HostResolver).
[email protected]1933eb202009-02-19 18:23:25426 delete request;
427 }
428 }
initial.commit09911bf2008-07-26 23:55:29429}
430
[email protected]a20bc092009-06-05 01:34:20431bool DnsMaster::PreLockedCongestionControlPerformed(DnsHostInfo* info) {
432 // Note: queue_duration is ONLY valid after we go to assigned state.
433 // TODO(jar): Tune selection of arbitrary 1 second constant. Add plumbing so
434 // that this can be set as part of an A/B experiment.
435 if (info->queue_duration() < base::TimeDelta::FromSeconds(1))
436 return false;
437 // We need to discard all entries in our queue, as we're keeping them waiting
438 // too long. By doing this, we'll have a chance to quickly service urgent
439 // resolutions, and not have a bogged down system.
440 while (true) {
441 info->RemoveFromQueue();
442 if (work_queue_.IsEmpty())
443 break;
444 info = &results_[work_queue_.Pop()];
445 info->SetAssignedState();
446 }
447 return true;
448}
449
[email protected]1933eb202009-02-19 18:23:25450void DnsMaster::OnLookupFinished(LookupRequest* request,
451 const std::string& hostname, bool found) {
[email protected]fd2f8afe2009-06-11 21:53:55452 DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
453
initial.commit09911bf2008-07-26 23:55:29454 AutoLock auto_lock(lock_); // For map access (changing info values).
455 DnsHostInfo* info = &results_[hostname];
456 DCHECK(info->HasHostname(hostname));
[email protected]a20bc092009-06-05 01:34:20457 if (info->is_marked_to_delete()) {
initial.commit09911bf2008-07-26 23:55:29458 results_.erase(hostname);
[email protected]a20bc092009-06-05 01:34:20459 } else {
[email protected]1933eb202009-02-19 18:23:25460 if (found)
461 info->SetFoundState();
462 else
463 info->SetNoSuchNameState();
[email protected]7c19b87b02009-01-26 16:19:44464 }
465
[email protected]1933eb202009-02-19 18:23:25466 pending_lookups_.erase(request);
467 delete request;
[email protected]7c19b87b02009-01-26 16:19:44468
[email protected]1933eb202009-02-19 18:23:25469 PreLockedScheduleLookups();
initial.commit09911bf2008-07-26 23:55:29470}
471
472void DnsMaster::DiscardAllResults() {
473 AutoLock auto_lock(lock_);
474 // Delete anything listed so far in this session that shows in about:dns.
475 cache_eviction_map_.clear();
476 cache_hits_.clear();
[email protected]21dae9b2008-11-06 23:32:53477 referrers_.clear();
initial.commit09911bf2008-07-26 23:55:29478
479
480 // Try to delete anything in our work queue.
[email protected]a20bc092009-06-05 01:34:20481 while (!work_queue_.IsEmpty()) {
initial.commit09911bf2008-07-26 23:55:29482 // Emulate processing cycle as though host was not found.
[email protected]a20bc092009-06-05 01:34:20483 std::string hostname = work_queue_.Pop();
initial.commit09911bf2008-07-26 23:55:29484 DnsHostInfo* info = &results_[hostname];
485 DCHECK(info->HasHostname(hostname));
486 info->SetAssignedState();
487 info->SetNoSuchNameState();
488 }
[email protected]1933eb202009-02-19 18:23:25489 // Now every result_ is either resolved, or is being resolved
490 // (see LookupRequest).
initial.commit09911bf2008-07-26 23:55:29491
492 // Step through result_, recording names of all hosts that can't be erased.
[email protected]1933eb202009-02-19 18:23:25493 // We can't erase anything being worked on.
initial.commit09911bf2008-07-26 23:55:29494 Results assignees;
495 for (Results::iterator it = results_.begin(); results_.end() != it; ++it) {
496 std::string hostname = it->first;
497 DnsHostInfo* info = &it->second;
498 DCHECK(info->HasHostname(hostname));
499 if (info->is_assigned()) {
500 info->SetPendingDeleteState();
501 assignees[hostname] = *info;
502 }
503 }
[email protected]e085c302009-06-01 18:31:36504 DCHECK(assignees.size() <= max_concurrent_lookups_);
initial.commit09911bf2008-07-26 23:55:29505 results_.clear();
[email protected]1933eb202009-02-19 18:23:25506 // Put back in the names being worked on.
initial.commit09911bf2008-07-26 23:55:29507 for (Results::iterator it = assignees.begin(); assignees.end() != it; ++it) {
508 DCHECK(it->second.is_marked_to_delete());
509 results_[it->first] = it->second;
510 }
511}
512
[email protected]03c5e862009-02-17 22:50:14513void DnsMaster::TrimReferrers() {
514 std::vector<std::string> hosts;
515 AutoLock auto_lock(lock_);
516 for (Referrers::const_iterator it = referrers_.begin();
517 it != referrers_.end(); ++it)
518 hosts.push_back(it->first);
519 for (size_t i = 0; i < hosts.size(); ++i)
520 if (!referrers_[hosts[i]].Trim())
521 referrers_.erase(hosts[i]);
522}
523
524void DnsMaster::SerializeReferrers(ListValue* referral_list) {
525 referral_list->Clear();
526 AutoLock auto_lock(lock_);
527 for (Referrers::const_iterator it = referrers_.begin();
528 it != referrers_.end(); ++it) {
529 // Serialize the list of subresource names.
530 Value* subresource_list(it->second.Serialize());
531
532 // Create a list for each referer.
533 ListValue* motivating_host(new ListValue);
534 motivating_host->Append(new StringValue(it->first));
535 motivating_host->Append(subresource_list);
536
537 referral_list->Append(motivating_host);
538 }
539}
540
541void DnsMaster::DeserializeReferrers(const ListValue& referral_list) {
542 AutoLock auto_lock(lock_);
543 for (size_t i = 0; i < referral_list.GetSize(); ++i) {
544 ListValue* motivating_host;
545 if (!referral_list.GetList(i, &motivating_host))
546 continue;
547 std::string motivating_referrer;
548 if (!motivating_host->GetString(0, &motivating_referrer))
549 continue;
550 Value* subresource_list;
551 if (!motivating_host->Get(1, &subresource_list))
552 continue;
553 if (motivating_referrer.empty())
554 continue;
555 referrers_[motivating_referrer].Deserialize(*subresource_list);
556 }
557}
558
[email protected]a20bc092009-06-05 01:34:20559
560//------------------------------------------------------------------------------
561
562DnsMaster::HostNameQueue::HostNameQueue() {
563}
564
565DnsMaster::HostNameQueue::~HostNameQueue() {
566}
567
568void DnsMaster::HostNameQueue::Push(const std::string& hostname,
569 DnsHostInfo::ResolutionMotivation motivation) {
570 switch (motivation) {
571 case DnsHostInfo::STATIC_REFERAL_MOTIVATED:
572 case DnsHostInfo::LEARNED_REFERAL_MOTIVATED:
573 case DnsHostInfo::MOUSE_OVER_MOTIVATED:
574 rush_queue_.push(hostname);
575 break;
576
577 default:
578 background_queue_.push(hostname);
579 break;
580 }
581}
582
583bool DnsMaster::HostNameQueue::IsEmpty() const {
584 return rush_queue_.empty() && background_queue_.empty();
585}
586
587std::string DnsMaster::HostNameQueue::Pop() {
588 DCHECK(!IsEmpty());
589 if (!rush_queue_.empty()) {
590 std::string hostname(rush_queue_.front());
591 rush_queue_.pop();
592 return hostname;
593 }
594 std::string hostname(background_queue_.front());
595 background_queue_.pop();
596 return hostname;
597}
598
initial.commit09911bf2008-07-26 23:55:29599} // namespace chrome_browser_net