1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/host_cache.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h"
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//-----------------------------------------------------------------------------
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHostCache::Entry::Entry(int error,
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                        const AddressList& addrlist,
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                        base::TimeTicks expiration)
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : error(error), addrlist(addrlist), expiration(expiration) {
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHostCache::Entry::~Entry() {
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//-----------------------------------------------------------------------------
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHostCache::HostCache(size_t max_entries,
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                     base::TimeDelta success_entry_ttl,
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                     base::TimeDelta failure_entry_ttl)
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : max_entries_(max_entries),
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      success_entry_ttl_(success_entry_ttl),
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      failure_entry_ttl_(failure_entry_ttl) {
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHostCache::~HostCache() {
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst HostCache::Entry* HostCache::Lookup(const Key& key,
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                          base::TimeTicks now) const {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(CalledOnValidThread());
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (caching_is_disabled())
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return NULL;
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EntryMap::const_iterator it = entries_.find(key);
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (it == entries_.end())
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return NULL;  // Not found.
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Entry* entry = it->second.get();
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (CanUseEntry(entry, now))
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return entry;
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return NULL;
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHostCache::Entry* HostCache::Set(const Key& key,
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                 int error,
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const AddressList& addrlist,
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                 base::TimeTicks now) {
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(CalledOnValidThread());
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (caching_is_disabled())
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return NULL;
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::TimeTicks expiration = now +
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      (error == OK ? success_entry_ttl_ : failure_entry_ttl_);
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<Entry>& entry = entries_[key];
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!entry) {
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Entry didn't exist, creating one now.
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    Entry* ptr = new Entry(error, addrlist, expiration);
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    entry = ptr;
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Compact the cache if we grew it beyond limit -- exclude |entry| from
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // being pruned though!
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (entries_.size() > max_entries_)
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      Compact(now, ptr);
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ptr;
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Update an existing cache entry.
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    entry->error = error;
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    entry->addrlist = addrlist;
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    entry->expiration = expiration;
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return entry.get();
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HostCache::clear() {
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(CalledOnValidThread());
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entries_.clear();
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsize_t HostCache::size() const {
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(CalledOnValidThread());
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return entries_.size();
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsize_t HostCache::max_entries() const {
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(CalledOnValidThread());
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return max_entries_;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbase::TimeDelta HostCache::success_entry_ttl() const {
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(CalledOnValidThread());
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return success_entry_ttl_;
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbase::TimeDelta HostCache::failure_entry_ttl() const {
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(CalledOnValidThread());
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return failure_entry_ttl_;
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Note that this map may contain expired entries.
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst HostCache::EntryMap& HostCache::entries() const {
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(CalledOnValidThread());
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return entries_;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HostCache::CanUseEntry(const Entry* entry, const base::TimeTicks now) {
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return entry->expiration > now;
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HostCache::Compact(base::TimeTicks now, const Entry* pinned_entry) {
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Clear out expired entries.
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (EntryMap::iterator it = entries_.begin(); it != entries_.end(); ) {
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    Entry* entry = (it->second).get();
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (entry != pinned_entry && !CanUseEntry(entry, now)) {
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      entries_.erase(it++);
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else {
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ++it;
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (entries_.size() <= max_entries_)
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If we still have too many entries, start removing unexpired entries
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // at random.
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // TODO(eroman): this eviction policy could be better (access count FIFO
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // or whatever).
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (EntryMap::iterator it = entries_.begin();
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott       it != entries_.end() && entries_.size() > max_entries_; ) {
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    Entry* entry = (it->second).get();
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (entry != pinned_entry) {
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      entries_.erase(it++);
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else {
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ++it;
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (entries_.size() > max_entries_)
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DLOG(WARNING) << "Still above max entries limit";
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
153