LCOV - code coverage report
Current view: top level - util - lru_list.h (source / functions) Hit Total Coverage
Test: report.info Lines: 37 45 82.2 %
Date: 2012-05-15 Functions: 26 67 38.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 18 28 64.3 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #ifndef __LRU_LIST_H
      16                 :            : #define __LRU_LIST_H
      17                 :            : 
      18                 :            : #include <list>
      19                 :            : #include <string>
      20                 :            : 
      21                 :            : #include <boost/noncopyable.hpp>
      22                 :            : #include <boost/shared_ptr.hpp>
      23                 :            : 
      24                 :            : #include <util/locks.h>
      25                 :            : 
      26                 :            : namespace isc {
      27                 :            : namespace util {
      28                 :            : 
      29                 :            : /// \brief LRU List
      30                 :            : ///
      31                 :            : /// Provides the LRU list for the zone and nameserver objects.  The list is
      32                 :            : /// created with a specific size.  Entries are added to the back of the list
      33                 :            : /// and removed from the front.  It is also possible to pull an element out
      34                 :            : /// of the middle of the list and add it to the end of the list, an action that
      35                 :            : /// should be done when the element is referenced.
      36                 :            : ///
      37                 :            : /// It is not intended that the class be copied, and the derivation from
      38                 :            : /// boost::noncopyable enforces this.
      39                 :            : template <typename T>
      40                 :            : class LruList : boost::noncopyable {
      41                 :            : public:
      42                 :            :     typedef typename std::list<boost::shared_ptr<T> > lru_list;
      43                 :            :     typedef typename lru_list::iterator               iterator;
      44                 :            : 
      45                 :            :     /// \brief Dropped Operation
      46                 :            :     ///
      47                 :            :     /// When an object is dropped from the LRU list because it has not been
      48                 :            :     /// accessed for some time, it is possible that the action should trigger
      49                 :            :     /// some other functions.  For this reason, it is possible to register
      50                 :            :     /// a list-wide functor object to execute in this casee.
      51                 :            :     ///
      52                 :            :     /// Note that the function does not execute as the result of a call to
      53                 :            :     /// remove() - that is an explicit call and it is assumed that the caller
      54                 :            :     /// will handle any additional operations needed.
      55                 :            :     class Dropped {
      56                 :            :     public:
      57                 :            :         /// \brief Constructor
      58                 :        221 :         Dropped(){}
      59                 :            : 
      60                 :            :         /// \brief Virtual Destructor
      61                 :        217 :         virtual ~Dropped(){}
      62                 :            : 
      63                 :            :         /// \brief Dropped Object Handler
      64                 :            :         ///
      65                 :            :         /// Function object called when the object drops off the end of the
      66                 :            :         /// LRU list.
      67                 :            :         ///
      68                 :            :         /// \param drop Object being dropped.
      69                 :            :         virtual void operator()(T* drop) const = 0;
      70                 :            :     };
      71                 :            : 
      72                 :            :     /// \brief Constructor
      73                 :            :     ///
      74                 :            :     /// \param max_size Maximum size of the list before elements are dropped.
      75                 :            :     /// \param dropped Pointer to a function object that will get called as
      76                 :            :     /// elements are dropped.  This object will be stored using a shared_ptr,
      77                 :            :     /// so should be allocated with new().
      78                 :         10 :     LruList(uint32_t max_size = 1000, Dropped* dropped = NULL) :
      79                 :        458 :         max_size_(max_size), count_(0), dropped_(dropped)
      80                 :         10 :     {}
      81                 :            : 
      82                 :            :     /// \brief Virtual Destructor
      83                 :        295 :     virtual ~LruList()
      84                 :        295 :     {}
      85                 :            : 
      86                 :            :     /// \brief Add Element
      87                 :            :     ///
      88                 :            :     /// Add a new element to the end of the list.
      89                 :            :     ///
      90                 :            :     /// \param element Reference to the element to add.
      91                 :            :     ///
      92                 :            :     /// \return Handle describing the element in the LRU list.
      93                 :            :     virtual void add(boost::shared_ptr<T>& element);
      94                 :            : 
      95                 :            :     /// \brief Remove Element
      96                 :            :     ///
      97                 :            :     /// Removes an element from the list.  If the element is not present (i.e.
      98                 :            :     /// its internal list pointer is invalid), this is a no-op.
      99                 :            :     ///
     100                 :            :     /// \param element Reference to the element to remove.
     101                 :            :     virtual void remove(boost::shared_ptr<T>& element);
     102                 :            : 
     103                 :            :     /// \brief Touch Element
     104                 :            :     ///
     105                 :            :     /// The name comes from the Unix "touch" command.  All this does is to
     106                 :            :     /// move the specified entry from the middle of the list to the end of
     107                 :            :     /// the list.
     108                 :            :     ///
     109                 :            :     /// \param element Reference to the element to touch.
     110                 :            :     virtual void touch(boost::shared_ptr<T>& element);
     111                 :            : 
     112                 :            :     /// \brief Drop All the Elements in the List .
     113                 :            :     ///
     114                 :            :     /// All the elements will be dropped from the list container, and their
     115                 :            :     /// drop handler(if there is one) will be called, when done, the size of
     116                 :            :     /// of list will be 0.
     117                 :            :     virtual void clear();
     118                 :            : 
     119                 :            :     /// \brief Return Size of the List
     120                 :            :     ///
     121                 :            :     /// An independent count is kept of the list size, as list.size() may take
     122                 :            :     /// some time if the list is big.
     123                 :            :     ///
     124                 :            :     /// \return Number of elements in the list
     125                 :          0 :     virtual uint32_t size() const {
     126                 :            : 
     127                 :            :         // Don't bother to lock the mutex.  If an update is in progress, we
     128                 :            :         // receive either the value just before the update or just after it.
     129                 :            :         // Either way, this call could have come just before or just after
     130                 :            :         // that operation, so the value would have been just as uncertain.
     131                 :          0 :         return count_;
     132                 :            :     }
     133                 :            : 
     134                 :            :     /// \brief Return Maximum Size
     135                 :            :     ///
     136                 :            :     /// \return Maximum size of the list
     137                 :          0 :     virtual uint32_t getMaxSize() const {
     138                 :          0 :         return max_size_;
     139                 :            :     }
     140                 :            : 
     141                 :            :     /// \brief Set Maximum Size
     142                 :            :     ///
     143                 :            :     /// \param max_size New maximum list size
     144                 :          0 :     virtual void setMaxSize(uint32_t max_size) {
     145                 :          1 :         max_size_ = max_size;
     146                 :          0 :     }
     147                 :            : 
     148                 :            : private:
     149                 :            :     locks::mutex                   mutex_;     ///< List protection
     150                 :            :     std::list<boost::shared_ptr<T> >    lru_;       ///< The LRU list itself
     151                 :            :     uint32_t                            max_size_;  ///< Max size of the list
     152                 :            :     uint32_t                            count_;     ///< Count of elements
     153                 :            :     boost::shared_ptr<Dropped>          dropped_;   ///< Dropped object
     154                 :            : };
     155                 :            : 
     156                 :            : // Add entry to the list
     157                 :            : template <typename T>
     158                 :        264 : void LruList<T>::add(boost::shared_ptr<T>& element) {
     159                 :            : 
     160                 :            :     // Protect list against concurrent access
     161                 :            :     locks::scoped_lock<locks::mutex> lock(mutex_);
     162                 :            : 
     163                 :            :     // Add the entry and set its pointer field to point into the list.
     164                 :            :     // insert() is used to get the pointer.
     165                 :        528 :     element->setLruIterator(lru_.insert(lru_.end(), element));
     166                 :            : 
     167                 :            :     // ... and update the count while we have the mutex.
     168                 :        264 :     ++count_;
     169                 :            : 
     170                 :            :     // If the count takes us above the maximum size of the list, remove elements
     171                 :            :     // from the front.  The current list size could be more than one above the
     172                 :            :     // maximum size of the list if the maximum size was changed after
     173                 :            :     // construction.
     174 [ +  + ][ +  + ]:        281 :     while (count_ > max_size_) {
     175 [ +  - ][ +  - ]:         17 :         if (!lru_.empty()) {
     176                 :            : 
     177                 :            :             // Run the drop handler (if there is one) on the
     178                 :            : 
     179                 :            :             // to-be-dropped object.
     180 [ +  + ][ +  - ]:         17 :             if (dropped_) {
     181                 :         10 :                 (*dropped_)(lru_.begin()->get());
     182                 :            :             }
     183                 :            : 
     184                 :            :             // ... and get rid of it from the list
     185                 :         17 :             lru_.pop_front();
     186                 :         17 :             --count_;
     187                 :            :         }
     188                 :            :         else {
     189                 :            : 
     190                 :            :             // TODO: Log this condition (count_ > 0 when list empty) -
     191                 :            :             // it should not happen
     192                 :          0 :             count_ = 0;
     193                 :          0 :             break;
     194                 :            :         }
     195                 :            :     }
     196                 :        264 : }
     197                 :            : 
     198                 :            : // Remove an element from the list
     199                 :            : template <typename T>
     200                 :         30 : void LruList<T>::remove(boost::shared_ptr<T>& element) {
     201                 :            : 
     202                 :            :     // An element can only be removed it its internal pointer is valid.
     203                 :            :     // If it is, the pointer can be used to access the list because no matter
     204                 :            :     // what other elements are added or removed, the pointer remains valid.
     205                 :            :     //
     206                 :            :     // If the pointer is not valid, this is a no-op.
     207 [ +  + ][ +  - ]:         30 :     if (element->iteratorValid()) {
     208                 :            : 
     209                 :            :         // Is valid, so protect list against concurrent access
     210                 :            :         locks::scoped_lock<locks::mutex> lock(mutex_);
     211                 :            : 
     212                 :         29 :         lru_.erase(element->getLruIterator());  // Remove element from list
     213                 :         29 :         element->invalidateIterator();          // Invalidate pointer
     214                 :         29 :         --count_;                               // One less element
     215                 :            :     }
     216                 :         30 : }
     217                 :            : 
     218                 :            : // Touch an element - remove it from the list and add to the end
     219                 :            : template <typename T>
     220                 :       2135 : void LruList<T>::touch(boost::shared_ptr<T>& element) {
     221                 :            : 
     222                 :            :     // As before, if the pointer is not valid, this is a no-op.
     223 [ +  + ][ +  - ]:       2135 :     if (element->iteratorValid()) {
     224                 :            : 
     225                 :            :         // Protect list against concurrent access
     226                 :            :         locks::scoped_lock<locks::mutex> lock(mutex_);
     227                 :            : 
     228                 :            :         // Move the element to the end of the list.
     229                 :       2129 :         lru_.splice(lru_.end(), lru_, element->getLruIterator());
     230                 :            : 
     231                 :            :         // Update the iterator in the element to point to it.  We can
     232                 :            :         // offset from end() as a list has a bidirectional iterator.
     233                 :       4258 :         iterator i = lru_.end();
     234                 :       2129 :         element->setLruIterator(--i);
     235                 :            :     }
     236                 :       2135 : }
     237                 :            : 
     238                 :            : // Clear the list-  when done, the size of list will be 0.
     239                 :            : template <typename T>
     240                 :        145 : void LruList<T>::clear() {
     241                 :            :     // Protect list against concurrent access
     242                 :            :     locks::scoped_lock<locks::mutex> lock(mutex_);
     243                 :            : 
     244                 :            :     // ... and update the count while we have the mutex.
     245                 :        145 :     count_ = 0;
     246                 :            :     typename std::list<boost::shared_ptr<T> >::iterator iter;
     247 [ +  - ][ #  # ]:        145 :     if (dropped_) {
     248 [ +  + ][ #  # ]:        304 :         for (iter = lru_.begin(); iter != lru_.end(); ++iter) {
     249                 :            :             // Call the drop handler.
     250                 :        159 :             (*dropped_)(iter->get());
     251                 :            :         }
     252                 :            :     }
     253                 :            : 
     254                 :        145 :     lru_.clear();
     255                 :        145 : }
     256                 :            : 
     257                 :            : }   // namespace util
     258                 :            : }   // namespace isc
     259                 :            : 
     260                 :            : #endif // __LRU_LIST_H

Generated by: LCOV version 1.9