| // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/base/host_cache.h" |
| |
| #include "base/logging.h" |
| #include "net/base/net_errors.h" |
| |
| namespace net { |
| |
| //----------------------------------------------------------------------------- |
| |
| HostCache::Entry::Entry(int error, |
| const AddressList& addrlist, |
| base::TimeTicks expiration) |
| : error(error), addrlist(addrlist), expiration(expiration) { |
| } |
| |
| HostCache::Entry::~Entry() { |
| } |
| |
| //----------------------------------------------------------------------------- |
| |
| HostCache::HostCache(size_t max_entries, |
| base::TimeDelta success_entry_ttl, |
| base::TimeDelta failure_entry_ttl) |
| : max_entries_(max_entries), |
| success_entry_ttl_(success_entry_ttl), |
| failure_entry_ttl_(failure_entry_ttl) { |
| } |
| |
| HostCache::~HostCache() { |
| } |
| |
| const HostCache::Entry* HostCache::Lookup(const Key& key, |
| base::TimeTicks now) const { |
| DCHECK(CalledOnValidThread()); |
| if (caching_is_disabled()) |
| return NULL; |
| |
| EntryMap::const_iterator it = entries_.find(key); |
| if (it == entries_.end()) |
| return NULL; // Not found. |
| |
| Entry* entry = it->second.get(); |
| if (CanUseEntry(entry, now)) |
| return entry; |
| |
| return NULL; |
| } |
| |
| HostCache::Entry* HostCache::Set(const Key& key, |
| int error, |
| const AddressList& addrlist, |
| base::TimeTicks now) { |
| DCHECK(CalledOnValidThread()); |
| if (caching_is_disabled()) |
| return NULL; |
| |
| base::TimeTicks expiration = now + |
| (error == OK ? success_entry_ttl_ : failure_entry_ttl_); |
| |
| scoped_refptr<Entry>& entry = entries_[key]; |
| if (!entry) { |
| // Entry didn't exist, creating one now. |
| Entry* ptr = new Entry(error, addrlist, expiration); |
| entry = ptr; |
| |
| // Compact the cache if we grew it beyond limit -- exclude |entry| from |
| // being pruned though! |
| if (entries_.size() > max_entries_) |
| Compact(now, ptr); |
| return ptr; |
| } else { |
| // Update an existing cache entry. |
| entry->error = error; |
| entry->addrlist = addrlist; |
| entry->expiration = expiration; |
| return entry.get(); |
| } |
| } |
| |
| void HostCache::clear() { |
| DCHECK(CalledOnValidThread()); |
| entries_.clear(); |
| } |
| |
| size_t HostCache::size() const { |
| DCHECK(CalledOnValidThread()); |
| return entries_.size(); |
| } |
| |
| size_t HostCache::max_entries() const { |
| DCHECK(CalledOnValidThread()); |
| return max_entries_; |
| } |
| |
| base::TimeDelta HostCache::success_entry_ttl() const { |
| DCHECK(CalledOnValidThread()); |
| return success_entry_ttl_; |
| } |
| |
| base::TimeDelta HostCache::failure_entry_ttl() const { |
| DCHECK(CalledOnValidThread()); |
| return failure_entry_ttl_; |
| } |
| |
| // Note that this map may contain expired entries. |
| const HostCache::EntryMap& HostCache::entries() const { |
| DCHECK(CalledOnValidThread()); |
| return entries_; |
| } |
| |
| // static |
| bool HostCache::CanUseEntry(const Entry* entry, const base::TimeTicks now) { |
| return entry->expiration > now; |
| } |
| |
| void HostCache::Compact(base::TimeTicks now, const Entry* pinned_entry) { |
| // Clear out expired entries. |
| for (EntryMap::iterator it = entries_.begin(); it != entries_.end(); ) { |
| Entry* entry = (it->second).get(); |
| if (entry != pinned_entry && !CanUseEntry(entry, now)) { |
| entries_.erase(it++); |
| } else { |
| ++it; |
| } |
| } |
| |
| if (entries_.size() <= max_entries_) |
| return; |
| |
| // If we still have too many entries, start removing unexpired entries |
| // at random. |
| // TODO(eroman): this eviction policy could be better (access count FIFO |
| // or whatever). |
| for (EntryMap::iterator it = entries_.begin(); |
| it != entries_.end() && entries_.size() > max_entries_; ) { |
| Entry* entry = (it->second).get(); |
| if (entry != pinned_entry) { |
| entries_.erase(it++); |
| } else { |
| ++it; |
| } |
| } |
| |
| if (entries_.size() > max_entries_) |
| DLOG(WARNING) << "Still above max entries limit"; |
| } |
| |
| } // namespace net |