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