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   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