Home | History | Annotate | Download | only in base
      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   DCHECK(CalledOnValidThread());
     39   if (caching_is_disabled())
     40     return NULL;
     41 
     42   EntryMap::const_iterator it = entries_.find(key);
     43   if (it == entries_.end())
     44     return NULL;  // Not found.
     45 
     46   Entry* entry = it->second.get();
     47   if (CanUseEntry(entry, now))
     48     return entry;
     49 
     50   return NULL;
     51 }
     52 
     53 HostCache::Entry* HostCache::Set(const Key& key,
     54                                  int error,
     55                                  const AddressList& addrlist,
     56                                  base::TimeTicks now) {
     57   DCHECK(CalledOnValidThread());
     58   if (caching_is_disabled())
     59     return NULL;
     60 
     61   base::TimeTicks expiration = now +
     62       (error == OK ? success_entry_ttl_ : failure_entry_ttl_);
     63 
     64   scoped_refptr<Entry>& entry = entries_[key];
     65   if (!entry) {
     66     // Entry didn't exist, creating one now.
     67     Entry* ptr = new Entry(error, addrlist, expiration);
     68     entry = ptr;
     69 
     70     // Compact the cache if we grew it beyond limit -- exclude |entry| from
     71     // being pruned though!
     72     if (entries_.size() > max_entries_)
     73       Compact(now, ptr);
     74     return ptr;
     75   } else {
     76     // Update an existing cache entry.
     77     entry->error = error;
     78     entry->addrlist = addrlist;
     79     entry->expiration = expiration;
     80     return entry.get();
     81   }
     82 }
     83 
     84 void HostCache::clear() {
     85   DCHECK(CalledOnValidThread());
     86   entries_.clear();
     87 }
     88 
     89 size_t HostCache::size() const {
     90   DCHECK(CalledOnValidThread());
     91   return entries_.size();
     92 }
     93 
     94 size_t HostCache::max_entries() const {
     95   DCHECK(CalledOnValidThread());
     96   return max_entries_;
     97 }
     98 
     99 base::TimeDelta HostCache::success_entry_ttl() const {
    100   DCHECK(CalledOnValidThread());
    101   return success_entry_ttl_;
    102 }
    103 
    104 base::TimeDelta HostCache::failure_entry_ttl() const {
    105   DCHECK(CalledOnValidThread());
    106   return failure_entry_ttl_;
    107 }
    108 
    109 // Note that this map may contain expired entries.
    110 const HostCache::EntryMap& HostCache::entries() const {
    111   DCHECK(CalledOnValidThread());
    112   return entries_;
    113 }
    114 
    115 // static
    116 bool HostCache::CanUseEntry(const Entry* entry, const base::TimeTicks now) {
    117   return entry->expiration > now;
    118 }
    119 
    120 void HostCache::Compact(base::TimeTicks now, const Entry* pinned_entry) {
    121   // Clear out expired entries.
    122   for (EntryMap::iterator it = entries_.begin(); it != entries_.end(); ) {
    123     Entry* entry = (it->second).get();
    124     if (entry != pinned_entry && !CanUseEntry(entry, now)) {
    125       entries_.erase(it++);
    126     } else {
    127       ++it;
    128     }
    129   }
    130 
    131   if (entries_.size() <= max_entries_)
    132     return;
    133 
    134   // If we still have too many entries, start removing unexpired entries
    135   // at random.
    136   // TODO(eroman): this eviction policy could be better (access count FIFO
    137   // or whatever).
    138   for (EntryMap::iterator it = entries_.begin();
    139        it != entries_.end() && entries_.size() > max_entries_; ) {
    140     Entry* entry = (it->second).get();
    141     if (entry != pinned_entry) {
    142       entries_.erase(it++);
    143     } else {
    144       ++it;
    145     }
    146   }
    147 
    148   if (entries_.size() > max_entries_)
    149     DLOG(WARNING) << "Still above max entries limit";
    150 }
    151 
    152 }  // namespace net
    153