1 // Copyright (c) 2009 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. 4 5 #include "net/base/host_cache.h" 6 7 #include "base/logging.h" 8 #include "net/base/net_errors.h" 9 10 namespace net { 11 12 //----------------------------------------------------------------------------- 13 14 HostCache::Entry::Entry(int error, 15 const AddressList& addrlist, 16 base::TimeTicks expiration) 17 : error(error), addrlist(addrlist), expiration(expiration) { 18 } 19 20 HostCache::Entry::~Entry() { 21 } 22 23 //----------------------------------------------------------------------------- 24 25 HostCache::HostCache(size_t max_entries, 26 base::TimeDelta success_entry_ttl, 27 base::TimeDelta failure_entry_ttl) 28 : max_entries_(max_entries), 29 success_entry_ttl_(success_entry_ttl), 30 failure_entry_ttl_(failure_entry_ttl) { 31 } 32 33 HostCache::~HostCache() { 34 } 35 36 const HostCache::Entry* HostCache::Lookup(const Key& key, 37 base::TimeTicks now) const { 38 if (caching_is_disabled()) 39 return NULL; 40 41 EntryMap::const_iterator it = entries_.find(key); 42 if (it == entries_.end()) 43 return NULL; // Not found. 44 45 Entry* entry = it->second.get(); 46 if (CanUseEntry(entry, now)) 47 return entry; 48 49 return NULL; 50 } 51 52 HostCache::Entry* HostCache::Set(const Key& key, 53 int error, 54 const AddressList addrlist, 55 base::TimeTicks now) { 56 if (caching_is_disabled()) 57 return NULL; 58 59 base::TimeTicks expiration = now + 60 (error == OK ? success_entry_ttl_ : failure_entry_ttl_); 61 62 scoped_refptr<Entry>& entry = entries_[key]; 63 if (!entry) { 64 // Entry didn't exist, creating one now. 65 Entry* ptr = new Entry(error, addrlist, expiration); 66 entry = ptr; 67 68 // Compact the cache if we grew it beyond limit -- exclude |entry| from 69 // being pruned though! 70 if (entries_.size() > max_entries_) 71 Compact(now, ptr); 72 return ptr; 73 } else { 74 // Update an existing cache entry. 75 entry->error = error; 76 entry->addrlist = addrlist; 77 entry->expiration = expiration; 78 return entry.get(); 79 } 80 } 81 82 // static 83 bool HostCache::CanUseEntry(const Entry* entry, const base::TimeTicks now) { 84 return entry->expiration > now; 85 } 86 87 void HostCache::Compact(base::TimeTicks now, const Entry* pinned_entry) { 88 // Clear out expired entries. 89 for (EntryMap::iterator it = entries_.begin(); it != entries_.end(); ) { 90 Entry* entry = (it->second).get(); 91 if (entry != pinned_entry && !CanUseEntry(entry, now)) { 92 entries_.erase(it++); 93 } else { 94 ++it; 95 } 96 } 97 98 if (entries_.size() <= max_entries_) 99 return; 100 101 // If we still have too many entries, start removing unexpired entries 102 // at random. 103 // TODO(eroman): this eviction policy could be better (access count FIFO 104 // or whatever). 105 for (EntryMap::iterator it = entries_.begin(); 106 it != entries_.end() && entries_.size() > max_entries_; ) { 107 Entry* entry = (it->second).get(); 108 if (entry != pinned_entry) { 109 entries_.erase(it++); 110 } else { 111 ++it; 112 } 113 } 114 115 if (entries_.size() > max_entries_) 116 DLOG(WARNING) << "Still above max entries limit"; 117 } 118 119 } // namespace net 120