123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <stdint.h>
- #include <map>
- #include <dns/question.h>
- #include <dns/rrclass.h>
- #include <dns/rrset.h>
- #include <dns/rrtype.h>
- #include <list>
- #include <datasrc/cache.h>
- #include <datasrc/logger.h>
- using namespace std;
- using namespace isc::dns;
- namespace isc {
- namespace datasrc {
- /// \brief A \c CacheEntry object contains the data stored with
- /// each \c CacheNode: a pointer to the cached RRset (empty in
- /// the case of a negative cache entry), and a copy of the
- /// query-response flags that were returned when the RRset
- /// was originally looked up in the low-level data source.
- class CacheEntry {
- private:
- /// The copy constructor and the assignment operator are intentionally
- /// defined as private.
- CacheEntry(const CacheEntry& source);
- CacheEntry& operator=(const CacheEntry& source);
- public:
- CacheEntry(RRsetPtr r, uint32_t f) : rrset(r), flags(f) {};
- RRsetPtr rrset;
- uint32_t flags;
- };
- typedef boost::shared_ptr<CacheEntry> CacheEntryPtr;
- /// \brief A \c CacheNode is a node in the \c HotCache LRU queue. It
- /// contains a pointer to a \c CacheEntry, a reference to the \c Question
- /// that we are answering, a lifespan during which this entry remains
- /// valid, and pointers to the next and previous entries in the list.
- class CacheNode {
- private:
- /// \name Constructors and Assignment Operator
- ///
- /// Note: The copy constructor and the assignment operator are intentionally
- /// defined as private.
- //@{
- CacheNode(const CacheNode& source);
- CacheNode& operator=(const CacheNode& source);
- public:
- /// \brief Constructor for positive cache entry.
- ///
- /// \param rrset The \c RRset to cache.
- /// \param flags The query response flags returned from the low-level
- /// data source when this \c RRset was looked up.
- /// \param lifespan How long the cache node is to be considered valid.
- CacheNode(const RRsetPtr rrset, uint32_t flags, time_t lifespan);
- /// \brief Constructor for negative cache entry.
- ///
- /// \param name Query name
- /// \param rrclass Query class
- /// \param rrtype Query type
- /// \param flags Query response flags returned from the low-level
- /// data source, indicating why this lookup failed (name not found,
- /// type not found, etc).
- /// \param lifespan How long the cache node is to be considered valid.
- CacheNode(const Name& name,
- const RRClass& rrclass,
- const RRType& rrtype,
- uint32_t flags,
- time_t lifespan);
- //@}
- /// \name Getter and Setter Methods
- //@{
- /// \brief Returns a pointer to the cached RRset (or an empty
- /// RRsetPtr for negative cache entries).
- /// \return \c RRsetPtr
- RRsetPtr getRRset() const { return (entry->rrset); }
- /// \brief Returns name associated with cached node
- ///
- /// This is the name associated with the RRset if it is a positive
- /// entry, and the associated question name if the RRSet is NULL
- /// and this is a negative entry (together with an indication that
- /// this is a negative entry).
- string getNodeName() const {
- if (getRRset()) {
- return (getRRset()->getName().toText());
- }
- return (std::string("negative entry for ") + question.toText());
- }
- /// \brief Returns the query response flags associated with the data.
- ///
- /// \return \c uint32_t
- uint32_t getFlags() const { return (entry->flags); }
- /// \brief Is this record still valid?
- ///
- /// \return True if the expiration time has not yet passed,
- /// or false if it has.
- bool isValid() const;
- //@}
- // An iterator referencing this entry in the LRU list. This
- // permits unit-time removal using list::erase().
- list<CacheNodePtr>::iterator lru_entry_;
- /// The \c Question (name/rrclass/rrtype) answered by this cache node
- const isc::dns::Question question;
- private:
- // The cached RRset data
- CacheEntryPtr entry;
- // When this record should be discarded
- time_t expiry;
- };
- // CacheNode constructor for a positive cache entry
- CacheNode::CacheNode(const RRsetPtr rrset, const uint32_t flags,
- const time_t lifespan) :
- question(Question(rrset->getName(), rrset->getClass(), rrset->getType()))
- {
- const time_t now = time(NULL);
- expiry = now + lifespan;
- entry = CacheEntryPtr(new CacheEntry(rrset, flags));
- }
- // CacheNode constructor for a negative cache entry
- CacheNode::CacheNode(const Name& name,
- const RRClass& rrclass,
- const RRType& rrtype,
- const uint32_t flags,
- const time_t lifespan) :
- question(Question(name, rrclass, rrtype))
- {
- const time_t now = time(NULL);
- expiry = now + lifespan;
- entry = CacheEntryPtr(new CacheEntry(RRsetPtr(), flags));
- }
- // Returns true if the node has not yet expired.
- bool
- CacheNode::isValid() const {
- const time_t now = time(NULL);
- return (now < expiry);
- }
- /// This class abstracts the implementation details for \c HotCache.
- ///
- /// Each node inserted into the cache is placed at the head of a
- /// doubly-linked list. Whenever that node is retrieved from the cache,
- /// it is again moved to the head of the list. When the configured
- /// number of slots in the cache has been exceeded, the least recently
- /// used nodes will be removed from the tail of the list.
- ///
- /// A pointer to each cache node is also placed in a \c std::map object,
- /// keyed by \c isc::dns::Question. This allows retrieval of data in
- /// (usually) logarithmic time. (Possible TODO item: replace this with a
- /// hash table instead.)
- class HotCacheImpl {
- public:
- HotCacheImpl(int slots, bool enabled);
- // The LRU list
- list<CacheNodePtr> lru_;
- // Flag to indicate whether the cache is enabled
- bool enabled_;
- // The number of available slots in the LRU list. (If zero,
- // then the list is unbounded; otherwise, items are removed
- // from the tail of the list whenever it grows past slots_.)
- int slots_;
- // The number of items currently in the list.
- int count_;
- // Map from query tuple to cache node pointer, allowing fast retrieval
- // of data without a linear search of the LRU list
- std::map<Question, CacheNodePtr> map_;
- // Move a node to the front of the LRU list.
- void promote(CacheNodePtr node);
- // Remove a node from the cache.
- void remove(ConstCacheNodePtr node);
- // Insert a node into the cache (called by both cache() and ncache())
- void insert(CacheNodePtr node);
- };
- // HotCacheImpl constructor
- HotCacheImpl::HotCacheImpl(int slots, bool enabled) :
- enabled_(enabled), slots_(slots), count_(0)
- {
- LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_CACHE_CREATE);
- }
- // Insert a cache node into the cache
- inline void
- HotCacheImpl::insert(const CacheNodePtr node) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_INSERT).
- arg(node->getNodeName());
- std::map<Question, CacheNodePtr>::const_iterator iter;
- iter = map_.find(node->question);
- if (iter != map_.end()) {
- CacheNodePtr old = iter->second;
- if (old && old->isValid()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_OLD_FOUND);
- remove(old);
- }
- }
- lru_.push_front(node);
- node->lru_entry_ = lru_.begin();
- map_[node->question] = node;
- ++count_;
- if (slots_ != 0 && count_ > slots_) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_FULL);
- remove(lru_.back());
- }
- }
- // Promote a node to the head of the LRU list
- void
- HotCacheImpl::promote(CacheNodePtr node) {
- if (!node) {
- return;
- }
- if (node->lru_entry_ == lru_.begin()) {
- return;
- }
- lru_.splice(lru_.begin(), lru_, node->lru_entry_); // move node to front
- node->lru_entry_ = lru_.begin();
- }
- // Remove a node from the LRU list and the map
- void
- HotCacheImpl::remove(ConstCacheNodePtr node) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_REMOVE).
- arg(node->getNodeName());
- lru_.erase(node->lru_entry_);
- map_.erase(node->question);
- --count_;
- }
- // HotCache constructor
- HotCache::HotCache(const int slots) {
- impl_ = new HotCacheImpl(slots, true);
- }
- // HotCache destructor
- HotCache::~HotCache() {
- LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_CACHE_DESTROY);
- delete impl_;
- }
- // Add a positive entry to the cache
- void
- HotCache::addPositive(RRsetPtr rrset, const uint32_t flags,
- const time_t lifespan)
- {
- if (!impl_->enabled_) {
- return;
- }
- impl_->insert(CacheNodePtr(new CacheNode(rrset, flags, lifespan)));
- }
- // Add a negative entry to the cache
- void
- HotCache::addNegative(const Name& name, const RRClass &rrclass,
- const RRType& rrtype, const uint32_t flags,
- const time_t lifespan)
- {
- if (!impl_->enabled_) {
- return;
- }
- if (rrtype == RRType::ANY() || rrclass == RRClass::ANY()) {
- return;
- }
- impl_->insert(CacheNodePtr(new CacheNode(name, rrclass, rrtype,
- flags, lifespan)));
- }
- // Try to retrieve an entry from the cache, returning true if
- // it was found and valid.
- bool
- HotCache::retrieve(const Name& n, const RRClass& c, const RRType& t,
- RRsetPtr& rrset, uint32_t& flags)
- {
- if (!impl_->enabled_) {
- return (false);
- }
- std::map<Question, CacheNodePtr>::const_iterator iter;
- iter = impl_->map_.find(Question(n, c, t));
- if (iter == impl_->map_.end()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_NOT_FOUND).arg(n);
- return (false);
- }
- CacheNodePtr node = iter->second;
- if (node->isValid()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_FOUND).arg(n);
- impl_->promote(node);
- rrset = node->getRRset();
- flags = node->getFlags();
- return (true);
- }
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_EXPIRED).arg(n);
- impl_->remove(node);
- return (false);
- }
- // Set the number of slots in the cache.
- void
- HotCache::setSlots(const int slots) {
- impl_->slots_ = slots;
- if (!impl_->enabled_) {
- return;
- }
- logger.info(DATASRC_CACHE_SLOTS).arg(slots).arg(max(0, impl_->count_ -
- slots));
- while (impl_->slots_ != 0 && impl_->count_ > impl_->slots_) {
- impl_->remove(impl_->lru_.back());
- }
- }
- // Return the number of slots in the cache
- int
- HotCache::getSlots() const {
- return (impl_->slots_);
- }
- /// Enable or disable the cache
- void
- HotCache::setEnabled(const bool e) {
- impl_->enabled_ = e;
- if (e) {
- logger.info(DATASRC_CACHE_ENABLE);
- } else {
- logger.info(DATASRC_CACHE_DISABLE);
- }
- }
- /// Indicate whether the cache is enabled
- bool
- HotCache::getEnabled() const {
- return (impl_->enabled_);
- }
- // Return the number of entries in the cache
- int
- HotCache::getCount() const {
- return (impl_->count_);
- }
- }
- }
|