Parcourir la source

1. Changes to tests made in response to review.
2. Additional classes and changes towards the logic for manipulating the
data structures in the nameserver address store.


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac356@3402 e5f2f494-b856-4b98-b285-d166d9295462

Stephen Morris il y a 14 ans
Parent
commit
c3e4332096

+ 3 - 1
src/lib/nsas/Makefile.am

@@ -9,10 +9,12 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
 lib_LTLIBRARIES = libnsas.la
 libnsas_la_SOURCES  = address_entry.h address_entry.cc
 libnsas_la_SOURCES += hash.cc hash.h
-libnsas_la_SOURCES += hash_key.h
+libnsas_la_SOURCES += hash_deleter.h
+libnsas_la_SOURCES += hash_key.cc hash_key.h
 libnsas_la_SOURCES += hash_table.h
 libnsas_la_SOURCES += lru_list.h
 libnsas_la_SOURCES += nameserver_entry.cc nameserver_entry.h
+libnsas_la_SOURCES += nsas_entry.h
 libnsas_la_SOURCES += asiolink.h
 
 CLEANFILES = *.gcno *.gcda

+ 71 - 0
src/lib/nsas/hash_deleter.h

@@ -0,0 +1,71 @@
+// 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.
+
+// $Id$
+
+#ifndef __HASH_DELETER_H
+#define __HASH_DELETER_H
+
+#include <boost/shared_ptr.hpp>
+#include "hash_table.h"
+
+namespace isc {
+namespace nsas {
+
+/// \brief Delete Object from Hash Table
+///
+/// This is the object passed to the LRU list constructors that deletes the
+/// ZoneEntry from the hash table when the zone is deleted from the LRU list.
+///
+/// It is declared as a nested class so as to be able to access the
+/// hash table without the need to be declared as "friend" or the need
+/// to define accessor methods.
+template <typename T>
+class HashDeleter : public LruList<T>::Dropped {
+public:
+
+    /// \brief Constructor
+    ///
+    /// \param hashtable Reference to the hash table from which information is
+    /// to be deleted.  The table is assumed to remain in existence for the life
+    /// of this object.
+    ///
+    /// \param hashtable Hash table from which the element should be deleted.
+    HashDeleter(HashTable<T>& hashtable) : hashtable_(hashtable)
+    {}
+
+    // The default copy constructor and assignment operator are correct for
+    // this object.
+
+    /// \brief Deletion Function
+    ///
+    /// Performs the deletion of the zone entry from the hash table.
+    ///
+    /// \param element Element to be deleted
+    virtual void operator()(boost::shared_ptr<T>& element);
+
+private:
+    HashTable<T>& hashtable_;         ///< Hash table to access element
+};
+
+// delete the object from the relevant hash table
+template <class T>
+void HashDeleter<T>::operator()(boost::shared_ptr<T>& element) {
+    hashtable_.remove(element->hashKey());
+}
+
+} // namespace nsas
+} // namespace isc
+
+#endif // __HASH_DELETER_H

+ 53 - 0
src/lib/nsas/hash_key.cc

@@ -0,0 +1,53 @@
+// 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.
+
+// $Id$
+
+#include <string.h>
+
+#include "config.h"
+#include "hash_key.h"
+
+namespace isc {
+namespace nsas {
+
+/// Hash Equality Function
+bool HashKey::operator==(const isc::nsas::HashKey& other) {
+
+    // Check key lengths
+    if (other.keylen == keylen) {
+
+        // ... and classes
+        if (other.class_code == class_code) {
+
+            // ... before the expensive operation.  This involves a
+            // byte-by-byte comparison, doing a case-independent match.
+            // memcmp() doesn't work (exact match) nor does strcmp or its
+            // variation (stops on the first null byte).
+            //
+            // TODO: Use a lookup table to map upper to lower case (for speed)
+            for (int i = 0; i < other.keylen; ++i) {
+                if (tolower(static_cast<unsigned char>(other.key[i])) !=
+                    tolower(static_cast<unsigned char>(key[i]))) {
+                    return false;   // Mismatch
+                }
+            }
+            return true;    // All bytes matched
+        }
+    }
+    return false;   // Key length or class did not match
+}
+
+} // namespace nsas
+} // namespace isc

+ 19 - 4
src/lib/nsas/hash_key.h

@@ -17,11 +17,13 @@
 #ifndef __HASH_KEY_H
 #define __HASH_KEY_H
 
+#include <stdint.h>
+#include <string>
+#include "config.h"
+
 namespace isc {
 namespace nsas {
 
-#include <stdint.h>
-
 /// \brief Hash Key
 ///
 /// In the nameserver address store, an object is placed into a hash table
@@ -63,7 +65,21 @@ struct HashKey {
         key(the_key.c_str()), keylen(the_key.size()), class_code(the_class_code)
     {}
 
-    // As these are public variables, they names do not end with an underscore.
+    /// \brief Equality
+    ///
+    /// Convenience for unit testing, this matches two hash keys as being
+    /// equal if the key strings match on a case-independent basis and the
+    /// classes match.
+    ///
+    /// Note that the class strings may include null bytes; the match is
+    /// done on a byte-by-byte basis, with codes in the range 'A' to 'Z' being
+    /// mapped to 'a' to 'z'.
+    ///
+    /// \param other Hash key to compare against.
+    ///
+    /// \return true if the two hash key objects are the same.
+    bool operator==(const isc::nsas::HashKey& other);
+
     const char* key;        ///< Pointer to the start of the key string
     uint32_t    keylen;     ///< Length of the key string
     uint16_t    class_code; ///< Class associated with the key
@@ -72,5 +88,4 @@ struct HashKey {
 } // namespace nsas
 } // namespace isc
 
-
 #endif // __HASH_KEY_H

+ 31 - 14
src/lib/nsas/hash_table.h

@@ -32,9 +32,6 @@
 // Maximum key length if the maximum size of a DNS name
 #define MAX_KEY_LENGTH 255
 
-using namespace std;
-using namespace boost::interprocess;
-
 namespace isc {
 namespace nsas {
 
@@ -48,10 +45,17 @@ namespace nsas {
 /// does not copy its argument.
 template <typename T>
 struct HashTableSlot {
-    typedef boost::interprocess::interprocess_upgradable_mutex mutex_type;
 
-    mutex_type                          mutex_;     ///< Protection mutex
-    std::list<boost::shared_ptr<T> >    list_;      ///< List head
+    /// \brief Type definitions
+    ///
+    //@{
+
+    typedef typename std::list<boost::shared_ptr<T> >::iterator  iterator;
+                                    ///< Iterator over elements with same hash
+
+    typedef boost::interprocess::interprocess_upgradable_mutex mutex_type;
+                                    ///< Mutex protecting this slot
+    //@}
 
     /// \brief Default Constructor
     HashTableSlot()
@@ -63,8 +67,9 @@ struct HashTableSlot {
     /// defined outside the class to allow for use of the UNUSED_PARAM macro.
     HashTableSlot(const HashTableSlot<T>& unused);
 
-    /// ... and a couple of external definitions
-    typedef typename std::list<boost::shared_ptr<T> >::iterator  iterator;
+public:
+    mutex_type                          mutex_;     ///< Protection mutex
+    std::list<boost::shared_ptr<T> >    list_;      ///< List head
 };
 
 // (Non)Copy Constructor
@@ -94,7 +99,7 @@ public:
     /// \param key Key describing the object
     ///
     /// \return bool true of the name of the object is equal to the name given.
-    virtual bool operator()(T* object, const HashKey& key) = 0;
+    virtual bool operator()(T* object, const HashKey& key) const = 0;
 };
 
 
@@ -114,6 +119,18 @@ template <typename T>
 class HashTable {
 public:
 
+    /// \brief Type Definitions
+    ///
+    //@{
+    typedef typename
+    boost::interprocess::sharable_lock<typename HashTableSlot<T>::mutex_type>
+    sharable_lock;                  ///< Type for a scope-limited read-lock
+
+    typedef typename
+    boost::interprocess::scoped_lock<typename HashTableSlot<T>::mutex_type>
+    scoped_lock;                    ///< Type for a scope-limited write-lock
+    //@}
+
     /// \brief Constructor
     ///
     /// Initialises the hash table.
@@ -174,8 +191,8 @@ public:
     }
 
 private:
-    Hash                        hash_;  ///< Hashing function
-    vector<HashTableSlot<T> >   table_; ///< The hash table itself
+    Hash                             hash_;  ///< Hashing function
+    std::vector<HashTableSlot<T> >   table_; ///< The hash table itself
     boost::shared_ptr<HashTableCompare<T> > compare_;  ///< Compare object
 };
 
@@ -195,7 +212,7 @@ boost::shared_ptr<T> HashTable<T>::get(const HashKey& key) {
 
     // Take out a read lock on this hash slot.  The lock is released when this
     // object goes out of scope.
-    sharable_lock<typename HashTableSlot<T>::mutex_type> lock(table_[index].mutex_);
+    sharable_lock lock(table_[index].mutex_);
 
     // Locate the object.
     typename HashTableSlot<T>::iterator i;
@@ -221,7 +238,7 @@ bool HashTable<T>::remove(const HashKey& key) {
     // Access to the elements of this hash slot are accessed under a mutex.
     // The mutex will be released when this object goes out of scope and is
     // destroyed.
-    scoped_lock<typename HashTableSlot<T>::mutex_type> lock(table_[index].mutex_);
+    scoped_lock lock(table_[index].mutex_);
 
     // Now search this list to see if the element already exists.
     typename HashTableSlot<T>::iterator i;
@@ -249,7 +266,7 @@ bool HashTable<T>::add(boost::shared_ptr<T>& object, const HashKey& key,
     uint32_t index = hash_(key);
 
     // Access to the elements of this hash slot are accessed under a mutex.
-    scoped_lock<typename HashTableSlot<T>::mutex_type> lock(table_[index].mutex_);
+    scoped_lock lock(table_[index].mutex_);
 
     // Now search this list to see if the element already exists.
     typename HashTableSlot<T>::iterator i;

+ 27 - 53
src/lib/nsas/lru_list.h

@@ -44,11 +44,12 @@ namespace nsas {
 template <typename T>
 class LruList : boost::noncopyable {
 public:
-    typedef typename std::list<boost::shared_ptr<T> >::iterator iterator;
+    typedef typename std::list<boost::shared_ptr<T> > lru_list;
+    typedef typename lru_list::iterator               iterator;
 
-    /// \brief Expired Operation
+    /// \brief Dropped Operation
     ///
-    /// When an object is removed from the LRU list because it has not been
+    /// When an object is dropped from the LRU list because it has not been
     /// accessed for some time, it is possible that the action should trigger
     /// some other functions.  For this reason, it is possible to register
     /// a list-wide functor object to execute in this casee.
@@ -56,53 +57,26 @@ public:
     /// Note that the function does not execute as the result of a call to
     /// remove() - that is an explicit call and it is assumed that the caller
     /// will handle any additional operations needed.
-    class Expired {
+    class Dropped {
     public:
 
-        /// \brief Expired Object Handler
+        /// \brief Dropped Object Handler
         ///
-        /// Function object called when the object expires from the LRU list.
+        /// Function object called when the object drops off the end of the
+        /// LRU list.
         ///
-        /// \param expired Expired object.
-        virtual void operator()(boost::shared_ptr<T>& element) = 0;
-    };
-
-    /// \brief Element of an LRU List
-    ///
-    /// This defines an element of the LRU List.  All objects stored in one
-    /// of these lists MUST be derived from this element.
-    ///
-    /// The class provides the storage for a pointer into the LRU list,
-    /// used to quickly locate the element when it is being "touched".
-    ///
-    /// Although it would be possible to require classes stored in the list
-    /// to have particular methods (and so eliminate the inheritance), this
-    /// would require the implementor to know something about the list and to
-    /// provide the appropriate logic.
-    ///
-    /// Unfortunately, using a base class does not simplify the definition of
-    /// the LRU list list class (by allowing the list to be defined as a list
-    /// of base class objects), as the list is a list of shared pointers to
-    /// objects, not a list of pointers to object.  Arguments are shared
-    /// pointers, but a shared pointer to a base class is not a subclass of a
-    /// shared pointer to a derived class.  For this reason, the list type
-    /// is a template parameter.
-    struct Element {
-        typename LruList<T>::iterator  handle_;    ///< Handle into the LRU List
-        bool                           valid_;     ///< true if handle is valid
-
-        Element() : valid_(false)
-        {}
+        /// \param drop Object being dropped.
+        virtual void operator()(boost::shared_ptr<T>& drop) = 0;
     };
 
     /// \brief Constructor
     ///
     /// \param max_size Maximum size of the list before elements are dropped.
-    /// \param expired Pointer to a function object that will get called as
+    /// \param dropped Pointer to a function object that will get called as
     /// elements are dropped.  This object will be stored using a shared_ptr,
     /// so should be allocated with new().
-    LruList(uint32_t max_size = 1000, Expired* expired = NULL) :
-        max_size_(max_size), count_(0), expired_(expired)
+    LruList(uint32_t max_size = 1000, Dropped* dropped = NULL) :
+        max_size_(max_size), count_(0), dropped_(dropped)
     {}
 
     /// \brief Virtual Destructor
@@ -169,7 +143,7 @@ private:
     std::list<boost::shared_ptr<T> >    lru_;       ///< The LRU list itself
     uint32_t                            max_size_;  ///< Max size of the list
     uint32_t                            count_;     ///< Count of elements
-    boost::shared_ptr<Expired>          expired_;   ///< Expired object
+    boost::shared_ptr<Dropped>          dropped_;   ///< Dropped object
 };
 
 // Add entry to the list
@@ -181,8 +155,7 @@ void LruList<T>::add(boost::shared_ptr<T>& element) {
 
     // Add the entry and set its pointer field to point into the list.
     // insert() is used to get the pointer.
-    element.get()->handle_ = lru_.insert(lru_.end(), element);
-    element.get()->valid_ = true;
+    element->setLruIterator(lru_.insert(lru_.end(), element));
 
     // ... and update the count while we have the mutex.
     ++count_;
@@ -194,10 +167,11 @@ void LruList<T>::add(boost::shared_ptr<T>& element) {
     while (count_ > max_size_) {
         if (!lru_.empty()) {
 
-            // Run the expiration handler (if there is one) on the
-            // to-be-expired object.
-            if (expired_) {
-                (*expired_)(*lru_.begin());
+            // Run the drop handler (if there is one) on the
+
+            // to-be-dropped object.
+            if (dropped_) {
+                (*dropped_)(*lru_.begin());
             }
 
             // ... and get rid of it from the list
@@ -223,14 +197,14 @@ void LruList<T>::remove(boost::shared_ptr<T>& element) {
     // what other elements are added or removed, the pointer remains valid.
     //
     // If the pointer is not valid, this is a no-op.
-    if (element.get()->valid_) {
+    if (element->iteratorValid()) {
 
         // Is valid, so protect list against concurrent access
         boost::interprocess::scoped_lock<boost::mutex> lock(mutex_);
 
-        element.get()->valid_ = false;      // Invalidate element
-        lru_.erase(element.get()->handle_); // Remove element from list
-        --count_;                           // One less element
+        lru_.erase(element->getLruIterator());  // Remove element from list
+        element->invalidateIterator();          // Invalidate pointer
+        --count_;                               // One less element
     }
 }
 
@@ -239,18 +213,18 @@ template <typename T>
 void LruList<T>::touch(boost::shared_ptr<T>& element) {
 
     // As before, if the pointer is not valid, this is a no-op.
-    if (element.get()->valid_) {
+    if (element->iteratorValid()) {
 
         // Protect list against concurrent access
         boost::interprocess::scoped_lock<boost::mutex> lock(mutex_);
 
         // Move the element to the end of the list.
-        lru_.splice(lru_.end(), lru_, element.get()->handle_);
+        lru_.splice(lru_.end(), lru_, element->getLruIterator());
 
         // Update the iterator in the element to point to it.  We can
         // offset from end() as a list has a bidirectional iterator.
         iterator i = lru_.end();
-        element.get()->handle_ = --i;
+        element->setLruIterator(--i);
     }
 }
 

+ 11 - 4
src/lib/nsas/nameserver_entry.h

@@ -24,6 +24,8 @@
 #include "address_entry.h"
 #include "asiolink.h"
 #include "exceptions/exceptions.h"
+#include "nsas_entry.h"
+#include "hash_key.h"
 #include "lru_list.h"
 #include "rrset.h"
 
@@ -74,9 +76,9 @@ public:
 /// started for the information.
 ///
 /// As this object will be stored in the nameserver address store LRU list,
-/// it is derived from the LRU list element class.
+/// it is derived from the LRU list entry class.
 
-class NameserverEntry : public LruList<NameserverEntry>::Element {
+class NameserverEntry : public NsasEntry<NameserverEntry> {
 public:
     /// List of addresses associated with this nameserver
     typedef std::vector<AddressEntry>   AddressVector;
@@ -121,7 +123,8 @@ public:
     /// convenient.)
     /// \param family Set to AF_INET/AF_INET6 for V6/V6 addresses, anything
     /// else for all addresses.
-    virtual void getAddresses(NameserverEntry::AddressVector& addresses, short family = 0) const;
+    virtual void getAddresses(NameserverEntry::AddressVector& addresses,
+        short family = 0) const;
 
     /// \brief Update RTT
     ///
@@ -148,6 +151,11 @@ public:
         return classCode_;
     }
 
+    /// \return Hash Key of the Nameserver
+    virtual HashKey hashKey() const {
+        return HashKey(name_, classCode_);
+    }
+
     /// \return Expiration Time of Data
     ///
     /// Returns the expiration time of addresses for this nameserver.  For
@@ -157,7 +165,6 @@ public:
         return expiration_;
     }
 
-
     /// \brief Predicate for Address Selection
     ///
     /// Returns false if the address family of a given entry matches the address

+ 138 - 0
src/lib/nsas/nsas_entry.h

@@ -0,0 +1,138 @@
+// 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.
+
+// $Id$
+
+#ifndef __NSAS_ENTRY_H
+#define __NSAS_ENTRY_H
+
+#include <iostream>
+
+#include "exceptions/exceptions.h"
+
+#include "hash_key.h"
+#include "hash_table.h"
+#include "lru_list.h"
+
+namespace isc {
+namespace nsas {
+
+/// \brief Invalid Iterator
+///
+/// Thrown if an attempt was made to access the iterator - the pointer into
+/// the LRU list where this element is located - when it is marked as invalid.
+class InvalidLruIterator : public isc::Exception {
+public:
+    InvalidLruIterator(const char* file, size_t line, const char* what) :
+        Exception(file, line, what)
+    {}
+};
+
+
+/// \brief Element of NSAS Internal Lists
+///
+/// This defines an element of the NSAS lists.  All elements stored in these
+/// lists *MUST* be derived from this object.
+///
+/// The class provides two properties:
+///
+/// # The method hashKey(), which returns a hash key associated with the
+/// object.
+/// # Storage for a pointer into the LRU list, used to quickly locate the
+/// element when it is being "touched".
+///
+/// Although it would be possible to require classes stored in the list
+/// to have particular methods (and so eliminate the inheritance), this
+/// would require the implementor to know something about the list and to
+/// provide the appropriate logic.
+///
+/// Unfortunately, using a base class does not simplify the definition of
+/// the list classes (by allowing the list to be defined as a list
+/// of base class objects), as the lists are a list of shared pointers to
+/// objects, not a list of pointers to object.  Arguments are shared
+/// pointers, but a shared pointer to a base class is not a subclass of a
+/// shared pointer to a derived class.  For this reason, the type of element
+/// being stored is a template parameter.
+
+template <typename T>
+class NsasEntry {
+public:
+
+    /// \brief Default Constructor
+    ///
+    /// Ensures that the handle into the LRU list is invalid.
+    NsasEntry() : valid_(false)
+    {}
+
+    /// \brief Virtual Destructor
+    virtual ~NsasEntry()
+    {}
+
+    /// Copy constructor and assignment operator OK for this class
+
+    /// \brief Hash Key
+    ///
+    /// Returns the hash key for this element.
+    ///
+    /// TODO: Consider returning a reference to an internal object, for speed
+    virtual HashKey hashKey() const = 0;
+
+    /// \brief Sets the iterator of the object
+    ///
+    /// Sets the iterator of an object and, as a side effect, marks it as valid.
+    ///
+    /// \param iterator Iterator of this element in the list
+    virtual void setLruIterator(typename LruList<T>::iterator iterator) {
+        iterator_ = iterator;
+        valid_ = true;
+    }
+
+    /// \brief Return Iterator
+    ///
+    /// \return iterator Iterator of this element in the list.
+    ///
+    /// \exception InvalidLruIterator Thrown if the iterator is not valid.
+    virtual typename LruList<T>::iterator getLruIterator() const {
+        if (! valid_) {
+            isc_throw(InvalidLruIterator,
+                "pointer of element into LRU list was not valid");
+        }
+        return iterator_;
+    }
+
+    /// \brief Iterator Valid
+    ///
+    /// \return true if the stored iterator is valid.
+    virtual bool iteratorValid() const {
+        return valid_;
+    }
+
+    /// \brief Invalidate Iterator
+    ///
+    /// Marks the iterator as invalid; it can oly be set valid again by a call
+    /// to setLruIterator.
+    virtual void invalidateIterator() {
+        valid_ = false;
+    }
+
+private:
+    typename LruList<T>::iterator  iterator_;  ///< Handle into the LRU List
+    bool                           valid_;     ///< true if handle is valid
+};
+
+} // namespace nsas
+} // namespace isc
+
+
+#endif // __NSAS_ENTRY_H

+ 55 - 0
src/lib/nsas/nsas_entry_compare.h

@@ -0,0 +1,55 @@
+// 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.
+
+// $Id$
+
+#ifndef __NSAS_ENTRY_COMPARE_H
+#define __NSAS_ENTRY_COMPARE_H
+
+#include "hash_key.h"
+#include "hash_table.h"
+
+namespace isc {
+namespace nsas {
+
+/// \brief Hash Table Comparison Object
+///
+/// The HashTable class requires a comparison object that checks if an object
+/// matches a hash key.  This check can be generalised for objects derived from
+/// NsasEntry, as they all have the hashKey() method; this class takes
+/// advantage of that.
+template <typename T>
+class NsasEntryCompare : public HashTableCompare<T> {
+public:
+
+    // The default constructor is OK for this class.
+
+    /// \brief Comparison Function
+    ///
+    /// Checks the hash key given against the hash key provided by the NSAS
+    /// element.
+    ///
+    /// \param object Pointer to the object
+    /// \param key Hash key to compare against.
+    ///
+    /// \return true if the object matches the key.
+    virtual bool operator()(T* object, const HashKey& key) const {
+        return (object->hashKey() == key);
+    }
+};
+
+} // namespace nsas
+} // namespace isc
+
+#endif // __NSAS_ENTRY_COMPARE_H

+ 6 - 4
src/lib/nsas/tests/Makefile.am

@@ -7,9 +7,9 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 AM_LDFLAGS =
 if USE_STATIC_LINK
-AM_LDFLAGS = -static
+AM_LDFLAGS += -static
 endif
-AM_LDFLAGS = -lboost_thread
+AM_LDFLAGS += -lboost_thread
 
 CLEANFILES = *.gcno *.gcda
 
@@ -17,13 +17,15 @@ TESTS =
 if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES  = run_unittests.cc
-run_unittests_SOURCES += nsas_test_utilities.h 
 run_unittests_SOURCES += address_entry_unittest.cc
-run_unittests_SOURCES += hash_unittest.cc
+run_unittests_SOURCES += hash_deleter_unittest.cc
 run_unittests_SOURCES += hash_key_unittest.cc
 run_unittests_SOURCES += hash_table_unittest.cc
+run_unittests_SOURCES += hash_unittest.cc
 run_unittests_SOURCES += lru_list_unittest.cc
 run_unittests_SOURCES += nameserver_entry_unittest.cc
+run_unittests_SOURCES += nsas_entry_compare_unittest.cc
+run_unittests_SOURCES += nsas_test_utilities.h 
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)

+ 113 - 0
src/lib/nsas/tests/hash_deleter_unittest.cc

@@ -0,0 +1,113 @@
+// 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.
+
+// $Id$
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <boost/lexical_cast.hpp>
+
+#include "nsas_entry.h"
+#include "hash_table.h"
+#include "hash_key.h"
+#include "lru_list.h"
+#include "hash_deleter.h"
+
+#include "nsas_test.h"
+#include "nsas_entry_compare.h"
+
+using namespace std;
+
+namespace isc {
+namespace nsas {
+
+
+/// \brief Text Fixture Class
+class HashDeleterTest : public ::testing::Test {
+protected:
+    HashDeleterTest() :
+        entry1_(new TestEntry("alpha", 1)),
+        entry2_(new TestEntry("beta", 2)),
+        entry3_(new TestEntry("gamma", 3)),
+        entry4_(new TestEntry("delta", 4)),
+        entry5_(new TestEntry("epsilon", 5)),
+        entry6_(new TestEntry("zeta", 6)),
+        entry7_(new TestEntry("eta", 7)),
+        hash_table_(new NsasEntryCompare<TestEntry>()),
+        lru_list_(3, new HashDeleter<TestEntry>(hash_table_))
+    {}
+
+
+    boost::shared_ptr<TestEntry>    entry1_;
+    boost::shared_ptr<TestEntry>    entry2_;
+    boost::shared_ptr<TestEntry>    entry3_;
+    boost::shared_ptr<TestEntry>    entry4_;
+    boost::shared_ptr<TestEntry>    entry5_;
+    boost::shared_ptr<TestEntry>    entry6_;
+    boost::shared_ptr<TestEntry>    entry7_;
+
+    HashTable<TestEntry>    hash_table_;    ///< Hash table being tested
+    LruList<TestEntry>      lru_list_;      ///< Associated LRU list
+};
+
+
+// Basic test.  The test of the constructor etc. have been done in the test
+// fixture class.
+TEST_F(HashDeleterTest, Constructor) {
+
+    // Add entry1 to both the hash table and the LRU list
+    EXPECT_EQ(1, entry1_.use_count());
+    hash_table_.add(entry1_, entry1_->hashKey());
+    EXPECT_EQ(2, entry1_.use_count());
+    lru_list_.add(entry1_);
+    EXPECT_EQ(3, entry1_.use_count());
+
+    // Add entry 2.
+    EXPECT_EQ(1, entry2_.use_count());
+    hash_table_.add(entry2_, entry2_->hashKey());
+    EXPECT_EQ(2, entry2_.use_count());
+    lru_list_.add(entry2_);
+    EXPECT_EQ(3, entry2_.use_count());
+
+    // Add entry 3.
+    EXPECT_EQ(1, entry3_.use_count());
+    hash_table_.add(entry3_, entry3_->hashKey());
+    EXPECT_EQ(2, entry3_.use_count());
+    lru_list_.add(entry3_);
+    EXPECT_EQ(3, entry3_.use_count());
+
+    // Adding entry 4 should drop entry 1 from the list and from the
+    // associated hash table.
+
+    // Add entry 4.
+    EXPECT_EQ(1, entry4_.use_count());
+    hash_table_.add(entry4_, entry4_->hashKey());
+    EXPECT_EQ(2, entry4_.use_count());
+    lru_list_.add(entry4_);
+    EXPECT_EQ(3, entry4_.use_count());
+
+    // Entry 1 should only be referred to by the text fixture, being removed
+    // from both the LRU list and the hash table.
+    EXPECT_EQ(1, entry1_.use_count());
+
+    // ... and check that is does not exist in the table.
+    boost::shared_ptr<TestEntry> x = hash_table_.get(entry1_->hashKey());
+    EXPECT_EQ(NULL, x.get());
+}
+
+} // namespace nsas
+} // namespace isc

+ 22 - 2
src/lib/nsas/tests/hash_key_unittest.cc

@@ -21,14 +21,13 @@
 #include <gtest/gtest.h>
 #include <boost/lexical_cast.hpp>
 
-#include "hash.h"
+#include "hash_key.h"
 
 using namespace std;
 
 namespace isc {
 namespace nsas {
 
-
 /// \brief Test Fixture Class
 class HashKeyTest : public ::testing::Test {
 };
@@ -52,5 +51,26 @@ TEST_F(HashKeyTest, Constructor) {
     EXPECT_EQ(key2.class_code, 2);
 }
 
+// Equality check
+TEST_F(HashKeyTest, Equality) {
+    string  test1("abcdef123");    // Simple string
+    string  test2("abcdef123");    // Same key, different object
+    string  test3("AbCdEf123");    // Same key, different case (unequal)
+    string  test4("ABCDE123");     // Different key (almost same)
+    string  test5("uvwxyz987");    // Different key
+
+    EXPECT_TRUE(HashKey(test1, 1) == HashKey(test1, 1));   // Same key and class
+    EXPECT_FALSE(HashKey(test1, 1) == HashKey(test1, 2));  // Different class
+
+    EXPECT_TRUE(HashKey(test1, 2) == HashKey(test2, 2));   // Same value key/class
+    EXPECT_FALSE(HashKey(test1, 2) == HashKey(test2, 3));
+
+    EXPECT_TRUE(HashKey(test1, 3) == HashKey(test3, 3));   // Same key
+    EXPECT_FALSE(HashKey(test1, 3) == HashKey(test3, 4));
+
+    EXPECT_FALSE(HashKey(test1, 1) == HashKey(test4, 1));
+    EXPECT_FALSE(HashKey(test1, 1) == HashKey(test5, 1));
+}
+
 } // namespace nsas
 } // namespace isc

+ 40 - 112
src/lib/nsas/tests/hash_table_unittest.cc

@@ -23,87 +23,14 @@
 #include "hash_table.h"
 #include "hash_key.h"
 
+#include "nsas_entry_compare.h"
+#include "nsas_test.h"
+
+using namespace std;
 
 namespace isc {
 namespace nsas {
 
-
-/// \brief Dummy Class for Use in Testing
-///
-/// A class that has a name and a value.  The name is used as a key in the
-/// hash table, and the integer value used to check for the add/replace option.
-class DummyObject {
-public:
-
-    /// Constructor
-    ///
-    /// \param name Name of the object
-    /// \param class_code Class of the object
-    /// \param value Integer value
-    DummyObject(const char* name, uint16_t class_code, int value) :
-        name_(name), classCode_(class_code), value_(value)
-    {}
-
-    /// \return Name of the object
-    string getName() const {
-        return name_;
-    }
-
-    /// \return Value of the Object
-    int getValue() const {
-        return value_;
-    }
-
-    /// \return Class of the object
-    uint16_t getClass() const {
-        return classCode_;
-    }
-
-    /// \return Hash Key of the Object
-    HashKey getKey() {
-        return HashKey(name_.c_str(), name_.size(), classCode_);
-    }
-
-private:
-    string      name_;      ///< Object name
-    uint16_t    classCode_; ///< Object class
-    int         value_;     ///< Object value
-};
-
-/// \brief Comparison Class
-///
-/// Class to encapsulate the comparison of a DummyObject with a key and
-/// key length.
-class DummyObjectCompare : public HashTableCompare<DummyObject> {
-public:
-
-    /// \brief Comparison Operator
-    ///
-    /// Used to compare the object with a key name/length.
-    ///
-    /// \param object Pointer to the object being tested
-    /// \param key Key string
-    /// \param keylen Length of the key string
-    bool operator()(DummyObject* object, const HashKey& key) {
-        // Do a quick check on size first
-        if (key.keylen == object->getName().size()) {
-
-            // Size matches, does the class?
-            if (key.class_code == object->getClass()) {
-
-                // So does the memory?
-                return (memcmp(object->getName().c_str(), key.key,
-                    key.keylen) == 0);
-            }
-        }
-
-        // Size or class do not match.
-        return (false);
-    }
-};
-
-
-
 /// \brief Text Fixture Class
 ///
 /// Many of the tests are based on checking reference counts.  In all tests,
@@ -116,19 +43,19 @@ protected:
 
     // Constructor - initialize the objects
     HashTableTest() :
-        table_(new DummyObjectCompare()),
-        dummy1_(new DummyObject("test", 1, 42)),
-        dummy2_(new DummyObject("test", 1, 47)),
-        dummy3_(new DummyObject("Something_Else", 1, 1332)),
-        dummy4_(new DummyObject("test", 3, 42))
+        table_(new NsasEntryCompare<TestEntry>()),
+        dummy1_(new TestEntry("test", 1)),
+        dummy2_(new TestEntry("test", 1)),
+        dummy3_(new TestEntry("Something_Else", 1)),
+        dummy4_(new TestEntry("test", 3))
     {}
 
     // Members.
-    HashTable<DummyObject> table_;
-    boost::shared_ptr<DummyObject> dummy1_;
-    boost::shared_ptr<DummyObject> dummy2_;
-    boost::shared_ptr<DummyObject> dummy3_;
-    boost::shared_ptr<DummyObject> dummy4_;
+    HashTable<TestEntry> table_;
+    boost::shared_ptr<TestEntry> dummy1_;
+    boost::shared_ptr<TestEntry> dummy2_;
+    boost::shared_ptr<TestEntry> dummy3_;
+    boost::shared_ptr<TestEntry> dummy4_;
 };
 
 
@@ -136,12 +63,13 @@ protected:
 TEST_F(HashTableTest, Constructor) {
     
     // Default constructor
-    HashTable<DummyObject> table1(new DummyObjectCompare());
-    EXPECT_EQ(1009, table1.tableSize());
+    HashTable<TestEntry> table1(new NsasEntryCompare<TestEntry>());
+    EXPECT_EQ(HASHTABLE_DEFAULT_SIZE, table1.tableSize());
 
     // Non default constructor
-    HashTable<DummyObject> table2(new DummyObjectCompare(), 97);
-    EXPECT_EQ(97, table2.tableSize());
+    EXPECT_NE(42, HASHTABLE_DEFAULT_SIZE);
+    HashTable<TestEntry> table2(new NsasEntryCompare<TestEntry>(), 42);
+    EXPECT_EQ(42, table2.tableSize());
 }
 
 
@@ -155,19 +83,19 @@ TEST_F(HashTableTest, AddTest) {
     EXPECT_EQ(1, dummy2_.use_count());
 
     // Add first one to the hash table_
-    bool result = table_.add(dummy1_, dummy1_->getKey());
+    bool result = table_.add(dummy1_, dummy1_->hashKey());
     EXPECT_TRUE(result);
     EXPECT_EQ(2, dummy1_.use_count());
     EXPECT_EQ(1, dummy2_.use_count());
 
     // Attempt to add the second object with the same name and class fails.
-    result = table_.add(dummy2_, dummy2_->getKey());
+    result = table_.add(dummy2_, dummy2_->hashKey());
     EXPECT_FALSE(result);
     EXPECT_EQ(2, dummy1_.use_count());
     EXPECT_EQ(1, dummy2_.use_count());
 
     // Replacing an entry should work though
-    result = table_.add(dummy2_, dummy2_->getKey(), true);
+    result = table_.add(dummy2_, dummy2_->hashKey(), true);
     EXPECT_TRUE(result);
     EXPECT_EQ(1, dummy1_.use_count());
     EXPECT_EQ(2, dummy2_.use_count());
@@ -183,33 +111,33 @@ TEST_F(HashTableTest, RemoveTest) {
     EXPECT_EQ(1, dummy3_.use_count());
 
     // Add first one to the hash table_
-    bool result = table_.add(dummy1_, dummy1_->getKey());
+    bool result = table_.add(dummy1_, dummy1_->hashKey());
     EXPECT_TRUE(result);
     EXPECT_EQ(2, dummy1_.use_count());
     EXPECT_EQ(1, dummy3_.use_count());
 
     // Now remove it.
-    result = table_.remove(dummy1_->getKey());
+    result = table_.remove(dummy1_->hashKey());
     EXPECT_TRUE(result);
     EXPECT_EQ(1, dummy1_.use_count());
     EXPECT_EQ(1, dummy3_.use_count());
 
     // Attempt to remove it again.
-    result = table_.remove(dummy1_->getKey());
+    result = table_.remove(dummy1_->hashKey());
     EXPECT_FALSE(result);
     EXPECT_EQ(1, dummy1_.use_count());
     EXPECT_EQ(1, dummy3_.use_count());
 
     // Add both entries to table_, then remove one (checks that it will
     // remove the correct one).
-    result = table_.add(dummy1_, dummy1_->getKey());
+    result = table_.add(dummy1_, dummy1_->hashKey());
     EXPECT_TRUE(result);
-    result = table_.add(dummy3_, dummy3_->getKey());
+    result = table_.add(dummy3_, dummy3_->hashKey());
     EXPECT_TRUE(result);
     EXPECT_EQ(2, dummy1_.use_count());
     EXPECT_EQ(2, dummy3_.use_count());
 
-    result = table_.remove(dummy1_->getKey());
+    result = table_.remove(dummy1_->hashKey());
     EXPECT_TRUE(result);
     EXPECT_EQ(1, dummy1_.use_count());
     EXPECT_EQ(2, dummy3_.use_count());
@@ -225,25 +153,25 @@ TEST_F(HashTableTest, GetTest) {
     EXPECT_EQ(1, dummy3_.use_count());
 
     // Add both to the hash table
-    bool result = table_.add(dummy1_, dummy1_->getKey());
+    bool result = table_.add(dummy1_, dummy1_->hashKey());
     EXPECT_TRUE(result);
-    result = table_.add(dummy3_, dummy3_->getKey());
+    result = table_.add(dummy3_, dummy3_->hashKey());
     EXPECT_TRUE(result);
 
     // Lookup the first
-    boost::shared_ptr<DummyObject> value = table_.get(dummy1_->getKey());
+    boost::shared_ptr<TestEntry> value = table_.get(dummy1_->hashKey());
     EXPECT_EQ(value.get(), dummy1_.get());
 
     // ... and the second
-    value = table_.get(dummy3_->getKey());
+    value = table_.get(dummy3_->hashKey());
     EXPECT_EQ(value.get(), dummy3_.get());
 
     // Remove the first
-    result = table_.remove(dummy1_->getKey());
+    result = table_.remove(dummy1_->hashKey());
     EXPECT_TRUE(result);
 
     // ... and a lookup should return empty
-    value = table_.get(dummy1_->getKey());
+    value = table_.get(dummy1_->hashKey());
     EXPECT_TRUE(value.get() == NULL);
 }
 
@@ -257,22 +185,22 @@ TEST_F(HashTableTest, ClassTest) {
     EXPECT_EQ(1, dummy4_.use_count());
 
     // Add both to the hash table
-    bool result = table_.add(dummy1_, dummy1_->getKey());
+    bool result = table_.add(dummy1_, dummy1_->hashKey());
     EXPECT_TRUE(result);
     EXPECT_EQ(2, dummy1_.use_count());
 
-    result = table_.add(dummy4_, dummy4_->getKey());
+    result = table_.add(dummy4_, dummy4_->hashKey());
     EXPECT_TRUE(result);
     EXPECT_EQ(2, dummy4_.use_count());
 
     // Lookup the first
-    boost::shared_ptr<DummyObject> value1 = table_.get(dummy1_->getKey());
+    boost::shared_ptr<TestEntry> value1 = table_.get(dummy1_->hashKey());
     EXPECT_EQ(value1.get(), dummy1_.get());
     EXPECT_EQ(3, dummy1_.use_count());
     EXPECT_EQ(2, dummy4_.use_count());
 
     // ... and the second
-    boost::shared_ptr<DummyObject> value4 = table_.get(dummy4_->getKey());
+    boost::shared_ptr<TestEntry> value4 = table_.get(dummy4_->hashKey());
     EXPECT_EQ(value4.get(), dummy4_.get());
     EXPECT_EQ(3, dummy1_.use_count());
     EXPECT_EQ(3, dummy4_.use_count());
@@ -281,13 +209,13 @@ TEST_F(HashTableTest, ClassTest) {
     EXPECT_NE(dummy1_.get(), dummy4_.get());
 
     // Remove the first
-    result = table_.remove(dummy1_->getKey());
+    result = table_.remove(dummy1_->hashKey());
     EXPECT_TRUE(result);
     EXPECT_EQ(2, dummy1_.use_count());
     EXPECT_EQ(3, dummy4_.use_count());
 
     // ... and a lookup should return empty
-    boost::shared_ptr<DummyObject> value1a = table_.get(dummy1_->getKey());
+    boost::shared_ptr<TestEntry> value1a = table_.get(dummy1_->hashKey());
     EXPECT_TRUE(value1a.get() == NULL);
 }
 

+ 14 - 11
src/lib/nsas/tests/hash_unittest.cc

@@ -23,6 +23,8 @@
 
 #include "hash.h"
 
+#include "nsas_test.h"
+
 using namespace std;
 
 namespace isc {
@@ -37,9 +39,10 @@ static uint32_t CountUnique(const vector<uint32_t>& input) {
     // Check to see if values are unique.  Do this by sorting the values into
     // ascending order, removing duplicates, and checking the size again.
     //
-    // Note that unique only shifts elements around - it does not remove non-
-    // unique values, so it does change the size of the array.  The call to
-    // erase removes the elements left at the end of the array.
+    // Note that "unique" only shifts elements around - it does not remove non-
+    // unique values, so it does not change the size of the vector.  The call to
+    // erase removes the elements between the last unique element and the end
+    // of the vector, so shrinking the vector.
     sort(vcopy.begin(), vcopy.end());
     vcopy.erase(unique(vcopy.begin(), vcopy.end()), vcopy.end());
 
@@ -57,20 +60,20 @@ class HashTest : public ::testing::Test {
 TEST_F(HashTest, Constructor) {
     
     // Default constructor
-    Hash hash1(1009, 250);
-    EXPECT_EQ(1009, hash1.tableSize());
+    Hash hash1(HASHTABLE_DEFAULT_SIZE, 250);
+    EXPECT_EQ(HASHTABLE_DEFAULT_SIZE, hash1.tableSize());
     EXPECT_EQ(250, hash1.maxKeyLength());
 }
 
 // Test of the hash algorithm.  Without duplicating the code for the algorithm
 // here, testing is a bit awkward.  So the tests will check that a series of
-// names get hashed to different values.  (Choosing a 1009 element array should
+// names get hashed to different values.  (Choosing a HASHTABLE_DEFAULT_SIZE element array should
 // give minimal overlap; we'll allow for a maximum of 2 collisions with 50
 // similar names.  If there are more, perhaps the algorithm is at fault.
 
 TEST_F(HashTest, Algorithm) {
 
-    const int size = 1009;      // Size of the hash table
+    const int size = HASHTABLE_DEFAULT_SIZE;      // Size of the hash table
     Hash hash(size, 255, false);// Hashing algorithm object with seed
                                 // randomisation disabled
     string base = "alphabeta";  // Base of the names to behashed
@@ -96,7 +99,7 @@ TEST_F(HashTest, Algorithm) {
 
 TEST_F(HashTest, CaseMapping) {
 
-    Hash hash(1009, 255);
+    Hash hash(HASHTABLE_DEFAULT_SIZE, 255);
     
     // Check all unsigned characters
     for (int i = 0; i < 255; ++i) {
@@ -116,7 +119,7 @@ TEST_F(HashTest, MixedCase) {
     std::string test1 = "example1234.co.uk.";
     std::string test2 = "EXAmple1234.co.uk.";
 
-    Hash hash(1009, 255, false);    // Disable randomisation for testing
+    Hash hash(HASHTABLE_DEFAULT_SIZE, 255, false);    // Disable randomisation for testing
 
     // Case not ignored, hashes should be different
     uint32_t value1 = hash(HashKey(test1.c_str(), test1.size(), 0), false);
@@ -142,7 +145,7 @@ TEST_F(HashTest, MixedCase) {
 TEST_F(HashTest, ClassCodes) {
 
     std::string test1 = "example1234.co.uk.";
-    Hash hash(1009, 255, false);    // Disable randomisation for testing
+    Hash hash(HASHTABLE_DEFAULT_SIZE, 255, false);    // Disable randomisation for testing
 
     // Just try codes in the range 0 to 9 - more than covers the allocated
     // codes.
@@ -171,7 +174,7 @@ TEST_F(HashTest, Overlong) {
     std::string string1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
     std::string string2 = string1 + string(4096, 'x');
 
-    Hash hash(1009, string1.size());
+    Hash hash(HASHTABLE_DEFAULT_SIZE, string1.size());
 
     // Do two hashes
     uint32_t value1 = hash(HashKey(string1.c_str(), string1.size(), 0));

+ 161 - 161
src/lib/nsas/tests/lru_list_unittest.cc

@@ -14,6 +14,7 @@
 
 // $Id$
 
+#include <iostream>
 #include <algorithm>
 #include <string>
 #include <vector>
@@ -21,34 +22,25 @@
 #include <gtest/gtest.h>
 #include <boost/lexical_cast.hpp>
 
+#include "nsas_entry.h"
 #include "lru_list.h"
 
+#include "nsas_test.h"
+
 using namespace std;
 
 namespace isc {
 namespace nsas {
 
-/// \brief Element Class
-///
-/// This is an object that will be stored in the list.
-struct DataStore : public LruList<DataStore>::Element {
-    int         value_;
-    std::string text_;
-
-    /// \brief Constructor
-    DataStore(uint32_t value = 0, string text = "") : value_(value), text_(text)
-    {}
-};
-
-/// \brief Expired Functor Class
+/// \brief Dropped Functor Class
 ///
-/// Functor object is called when an object in the list becomes expired.
-/// To prove that it has run, this function does nothing more than negate the
-/// the value of the data store.
-class Expired : public LruList<DataStore>::Expired {
+/// Functor object is called when an object is dropped from the LRU list.
+/// To prove that it has run, this function does nothing more than set the
+/// MS bit on the 16-bit class value.
+class Dropped : public LruList<TestEntry>::Dropped {
 public:
-    virtual void operator()(boost::shared_ptr<DataStore>& element) {
-        element.get()->value_ = -element.get()->value_;
+    virtual void operator()(boost::shared_ptr<TestEntry>& entry) {
+        entry->setClass(entry->getClass() | 0x8000);
     }
 };
 
@@ -57,112 +49,118 @@ public:
 class LruListTest : public ::testing::Test {
 protected:
     LruListTest() :
-        element1_(new DataStore(1, "alpha")),
-        element2_(new DataStore(2, "beta")),
-        element3_(new DataStore(3, "gamma")),
-        element4_(new DataStore(4, "delta")),
-        element5_(new DataStore(5, "epsilon")),
-        element6_(new DataStore(6, "zeta")),
-        element7_(new DataStore(7, "eta"))
+        entry1_(new TestEntry("alpha", 1)),
+        entry2_(new TestEntry("beta", 2)),
+        entry3_(new TestEntry("gamma", 3)),
+        entry4_(new TestEntry("delta", 4)),
+        entry5_(new TestEntry("epsilon", 5)),
+        entry6_(new TestEntry("zeta", 6)),
+        entry7_(new TestEntry("eta", 7))
     {}
 
+    virtual ~LruListTest() 
+    {}
 
-    boost::shared_ptr<DataStore>    element1_;
-    boost::shared_ptr<DataStore>    element2_;
-    boost::shared_ptr<DataStore>    element3_;
-    boost::shared_ptr<DataStore>    element4_;
-    boost::shared_ptr<DataStore>    element5_;
-    boost::shared_ptr<DataStore>    element6_;
-    boost::shared_ptr<DataStore>    element7_;
+    boost::shared_ptr<TestEntry>    entry1_;
+    boost::shared_ptr<TestEntry>    entry2_;
+    boost::shared_ptr<TestEntry>    entry3_;
+    boost::shared_ptr<TestEntry>    entry4_;
+    boost::shared_ptr<TestEntry>    entry5_;
+    boost::shared_ptr<TestEntry>    entry6_;
+    boost::shared_ptr<TestEntry>    entry7_;
 };
 
 
 // Test of the constructor
 TEST_F(LruListTest, Constructor) {
-    LruList<DataStore>  lru(100);
+    LruList<TestEntry>  lru(100);
     EXPECT_EQ(100, lru.getMaxSize());
     EXPECT_EQ(0, lru.size());
 }
 
-// Test of Get/Set the maximum number of elements
+// Test of Get/Set the maximum number of entrys
 TEST_F(LruListTest, GetSet) {
-    LruList<DataStore>  lru(100);
+    LruList<TestEntry>  lru(100);
     EXPECT_EQ(100, lru.getMaxSize());
-
     lru.setMaxSize(42);
     EXPECT_EQ(42, lru.getMaxSize());
 }
 
-// Test that adding an element really does add an element
+// Test that adding an entry really does add an entry
 TEST_F(LruListTest, Add) {
-    LruList<DataStore>  lru(100);
+    LruList<TestEntry>  lru(100);
     EXPECT_EQ(0, lru.size());
 
-    lru.add(element1_);
+    lru.add(entry1_);
     EXPECT_EQ(1, lru.size());
 
-    lru.add(element2_);
+    lru.add(entry2_);
     EXPECT_EQ(2, lru.size());
 }
 
-// Test that removing an element really does remove it.
+// Test that removing an entry really does remove it.
 TEST_F(LruListTest, Remove) {
-    LruList<DataStore>  lru(100);
+    LruList<TestEntry>  lru(100);
     EXPECT_EQ(0, lru.size());
 
-    lru.add(element1_);
+    EXPECT_FALSE(entry1_->iteratorValid());
+    lru.add(entry1_);
+    EXPECT_TRUE(entry1_->iteratorValid());
     EXPECT_EQ(1, lru.size());
 
-    lru.add(element2_);
+    EXPECT_FALSE(entry2_->iteratorValid());
+    lru.add(entry2_);
+    EXPECT_TRUE(entry2_->iteratorValid());
     EXPECT_EQ(2, lru.size());
 
-    lru.remove(element1_);
+    lru.remove(entry1_);
+    EXPECT_FALSE(entry1_->iteratorValid());
     EXPECT_EQ(1, lru.size());
 }
 
-// Check that adding a new element to a limited size list does delete the
-// oldest element from the list.
+// Check that adding a new entry to a limited size list does delete the
+// oldest entry from the list.
 TEST_F(LruListTest, SizeLimit) {
-    LruList<DataStore>  lru(3);
+    LruList<TestEntry>  lru(3);
     EXPECT_EQ(0, lru.size());
 
-    // Add first element and check that the shared pointer's reference count
-    // has increased.  There will be two references: one from the "element1_"
+    // Add first entry and check that the shared pointer's reference count
+    // has increased.  There will be two references: one from the "entry1_"
     // member in the test fixture class, and one from the list.
-    EXPECT_EQ(1, element1_.use_count());
-    lru.add(element1_);
-    EXPECT_EQ(2, element1_.use_count());
+    EXPECT_EQ(1, entry1_.use_count());
+    lru.add(entry1_);
+    EXPECT_EQ(2, entry1_.use_count());
     EXPECT_EQ(1, lru.size());
 
-    // Same for element 2.
-    EXPECT_EQ(1, element2_.use_count());
-    lru.add(element2_);
-    EXPECT_EQ(2, element2_.use_count());
+    // Same for entry 2.
+    EXPECT_EQ(1, entry2_.use_count());
+    lru.add(entry2_);
+    EXPECT_EQ(2, entry2_.use_count());
     EXPECT_EQ(2, lru.size());
 
-    // Same for element 3.
-    EXPECT_EQ(1, element3_.use_count());
-    lru.add(element3_);
-    EXPECT_EQ(2, element3_.use_count());
+    // Same for entry 3.
+    EXPECT_EQ(1, entry3_.use_count());
+    lru.add(entry3_);
+    EXPECT_EQ(2, entry3_.use_count());
     EXPECT_EQ(3, lru.size());
 
-    // Adding element 4 should remove element 1 from the list.  This will
-    // delete the list's shared pointer to the element and will therefore
-    // drop the reference count back to one (from the "element1_" member in
+    // Adding entry 4 should remove entry 1 from the list.  This will
+    // delete the list's shared pointer to the entry and will therefore
+    // drop the reference count back to one (from the "entry1_" member in
     // the text fixture class).
-    EXPECT_EQ(2, element1_.use_count());
-    EXPECT_EQ(1, element4_.use_count());
-    lru.add(element4_);
-    EXPECT_EQ(1, element1_.use_count());
-    EXPECT_EQ(2, element4_.use_count());
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(1, entry4_.use_count());
+    lru.add(entry4_);
+    EXPECT_EQ(1, entry1_.use_count());
+    EXPECT_EQ(2, entry4_.use_count());
     EXPECT_EQ(3, lru.size());
 
-    // Adding element 5 should remove element 2 from the list.
-    EXPECT_EQ(2, element2_.use_count());
-    EXPECT_EQ(1, element5_.use_count());
-    lru.add(element5_);
-    EXPECT_EQ(1, element2_.use_count());
-    EXPECT_EQ(2, element5_.use_count());
+    // Adding entry 5 should remove entry 2 from the list.
+    EXPECT_EQ(2, entry2_.use_count());
+    EXPECT_EQ(1, entry5_.use_count());
+    lru.add(entry5_);
+    EXPECT_EQ(1, entry2_.use_count());
+    EXPECT_EQ(2, entry5_.use_count());
     EXPECT_EQ(3, lru.size());
 }
 
@@ -170,118 +168,120 @@ TEST_F(LruListTest, SizeLimit) {
 TEST_F(LruListTest, Touch) {
 
     // Create the list
-    LruList<DataStore>  lru(3);
+    LruList<TestEntry>  lru(3);
     EXPECT_EQ(0, lru.size());
-    lru.add(element1_);
-    lru.add(element2_);
-    lru.add(element3_);
-
-    // Check the reference counts of the elements and the list size
-    EXPECT_EQ(2, element1_.use_count());
-    EXPECT_EQ(2, element2_.use_count());
-    EXPECT_EQ(2, element3_.use_count());
-    EXPECT_EQ(1, element4_.use_count());
-    EXPECT_EQ(1, element5_.use_count());
-    EXPECT_EQ(1, element6_.use_count());
-    EXPECT_EQ(1, element7_.use_count());
+    lru.add(entry1_);
+    lru.add(entry2_);
+    lru.add(entry3_);
+
+    // Check the reference counts of the entrys and the list size
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(2, entry2_.use_count());
+    EXPECT_EQ(2, entry3_.use_count());
+    EXPECT_EQ(1, entry4_.use_count());
+    EXPECT_EQ(1, entry5_.use_count());
+    EXPECT_EQ(1, entry6_.use_count());
+    EXPECT_EQ(1, entry7_.use_count());
     EXPECT_EQ(3, lru.size());
 
-    // "Touch" the first element
-    lru.touch(element1_);
-
-    // Adding two more entries should not remove the touched element.
-    lru.add(element4_);
-    lru.add(element5_);
-
-    // Check the status of the elements and the list.
-    EXPECT_EQ(2, element1_.use_count());
-    EXPECT_EQ(1, element2_.use_count());
-    EXPECT_EQ(1, element3_.use_count());
-    EXPECT_EQ(2, element4_.use_count());
-    EXPECT_EQ(2, element5_.use_count());
-    EXPECT_EQ(1, element6_.use_count());
-    EXPECT_EQ(1, element7_.use_count());
+    // "Touch" the first entry
+    lru.touch(entry1_);
+
+    // Adding two more entries should not remove the touched entry.
+    lru.add(entry4_);
+    lru.add(entry5_);
+
+    // Check the status of the entrys and the list.
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(1, entry2_.use_count());
+    EXPECT_EQ(1, entry3_.use_count());
+    EXPECT_EQ(2, entry4_.use_count());
+    EXPECT_EQ(2, entry5_.use_count());
+    EXPECT_EQ(1, entry6_.use_count());
+    EXPECT_EQ(1, entry7_.use_count());
     EXPECT_EQ(3, lru.size());
 
-    // Now touch the element agin to move it to the back of the list.
-    // This checks that the iterator stored in the element as a result of the
+    // Now touch the entry agin to move it to the back of the list.
+    // This checks that the iterator stored in the entry as a result of the
     // last touch operation is valid.
-    lru.touch(element1_);
+    lru.touch(entry1_);
 
-    // Check this by adding two more elements and checking reference counts
+    // Check this by adding two more entrys and checking reference counts
     // to see what is stored.
-    lru.add(element6_);
-    lru.add(element7_);
-
-    EXPECT_EQ(2, element1_.use_count());
-    EXPECT_EQ(1, element2_.use_count());
-    EXPECT_EQ(1, element3_.use_count());
-    EXPECT_EQ(1, element4_.use_count());
-    EXPECT_EQ(1, element5_.use_count());
-    EXPECT_EQ(2, element6_.use_count());
-    EXPECT_EQ(2, element7_.use_count());
+    lru.add(entry6_);
+    lru.add(entry7_);
+
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(1, entry2_.use_count());
+    EXPECT_EQ(1, entry3_.use_count());
+    EXPECT_EQ(1, entry4_.use_count());
+    EXPECT_EQ(1, entry5_.use_count());
+    EXPECT_EQ(2, entry6_.use_count());
+    EXPECT_EQ(2, entry7_.use_count());
     EXPECT_EQ(3, lru.size());
 }
 
-// Expired functor tests: tests that the function object is called when an
+// Dropped functor tests: tests that the function object is called when an
 // object expires from the list.
-TEST_F(LruListTest, Expired) {
+TEST_F(LruListTest, Dropped) {
 
     // Create an object with an expiration handler.
-    LruList<DataStore> lru(3, new Expired());
+    LruList<TestEntry> lru(3, new Dropped());
 
     // Fill the list
-    lru.add(element1_);
-    lru.add(element2_);
-    lru.add(element3_);
-
-    EXPECT_EQ(1, element1_.get()->value_);
-    EXPECT_EQ(2, element2_.get()->value_);
-
-    // Add another element and check that the handler runs.
-    lru.add(element4_);
-    EXPECT_EQ(-1, element1_.get()->value_);
-
-    lru.add(element5_);
-    EXPECT_EQ(-2, element2_.get()->value_);
-
-    // Delete an element and check that the handler does not run. 
-    EXPECT_EQ(3, element3_.get()->value_);
-    lru.remove(element3_);
-    EXPECT_EQ(3, element3_.get()->value_);
+    lru.add(entry1_);
+    lru.add(entry2_);
+    lru.add(entry3_);
+
+    EXPECT_EQ(1, entry1_->getClass());
+    EXPECT_EQ(2, entry2_->getClass());
+
+    // Add another entry and check that the handler runs.
+    EXPECT_EQ(0, (entry1_->getClass() & 0x8000));
+    lru.add(entry4_);
+    EXPECT_NE(0, (entry1_->getClass() & 0x8000));
+
+    EXPECT_EQ(0, (entry2_->getClass() & 0x8000));
+    lru.add(entry5_);
+    EXPECT_NE(0, (entry2_->getClass() & 0x8000));
+
+    // Delete an entry and check that the handler does not run. 
+    EXPECT_EQ(0, (entry3_->getClass() & 0x8000));
+    lru.remove(entry3_);
+    EXPECT_EQ(0, (entry3_->getClass() & 0x8000));
 }
 
 // Miscellaneous tests - pathological conditions
 TEST_F(LruListTest, Miscellaneous) {
 
-    // Zero size list should not allow elements to be added
-    LruList<DataStore> lru_1(0);
-    lru_1.add(element1_);
+    // Zero size list should not allow entrys to be added
+    LruList<TestEntry> lru_1(0);
+    lru_1.add(entry1_);
     EXPECT_EQ(0, lru_1.size());
-    EXPECT_EQ(1, element1_.use_count());
+    EXPECT_EQ(1, entry1_.use_count());
 
-    // Removing an uninserted element should not affect the list.
-    LruList<DataStore> lru_2(100);
-    lru_2.add(element1_);
-    lru_2.add(element2_);
-    lru_2.add(element3_);
+    // Removing an uninserted entry should not affect the list.
+    LruList<TestEntry> lru_2(100);
+    lru_2.add(entry1_);
+    lru_2.add(entry2_);
+    lru_2.add(entry3_);
     EXPECT_EQ(3, lru_2.size());
 
-    lru_2.remove(element4_);
-    EXPECT_EQ(2, element1_.use_count());
-    EXPECT_EQ(2, element2_.use_count());
-    EXPECT_EQ(2, element3_.use_count());
-    EXPECT_EQ(1, element4_.use_count());
-    EXPECT_EQ(1, element5_.use_count());
+    lru_2.remove(entry4_);
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(2, entry2_.use_count());
+    EXPECT_EQ(2, entry3_.use_count());
+    EXPECT_EQ(1, entry4_.use_count());
+    EXPECT_EQ(1, entry5_.use_count());
     EXPECT_EQ(3, lru_2.size());
 
-    // Touching an uninserted element should not affect the list.
-    lru_2.touch(element5_);
-    EXPECT_EQ(2, element1_.use_count());
-    EXPECT_EQ(2, element2_.use_count());
-    EXPECT_EQ(2, element3_.use_count());
-    EXPECT_EQ(1, element4_.use_count());
-    EXPECT_EQ(1, element5_.use_count());
+    // Touching an uninserted entry should not affect the list.
+    lru_2.touch(entry5_);
+    EXPECT_EQ(2, entry1_.use_count());
+    EXPECT_EQ(2, entry2_.use_count());
+    EXPECT_EQ(2, entry3_.use_count());
+    EXPECT_EQ(1, entry4_.use_count());
+    EXPECT_EQ(1, entry5_.use_count());
     EXPECT_EQ(3, lru_2.size());
 }
 

+ 2 - 2
src/lib/nsas/tests/nameserver_entry_unittest.cc

@@ -31,7 +31,7 @@
 #include "address_entry.h"
 #include "nameserver_entry.h"
 
-#include "nsas_test_utilities.h"
+#include "nsas_test.h"
 
 using namespace asiolink;
 using namespace std;
@@ -99,7 +99,7 @@ protected:
     BasicRRset rrv4_;           ///< Standard RRSet - IN, A, lowercase name
     BasicRRset rrcase_;         ///< Mixed-case name
     BasicRRset rrch_;           ///< Non-IN RRset (Chaos in this case)
-    BasicRRset rrns_;           ///< Non-NS RRset (MX in this case)
+    BasicRRset rrns_;           ///< NS RRset
     BasicRRset rrv6_;           ///< Standard RRset, IN, AAAA, lowercase name
     BasicRRset rrnet_;          ///< example.net A RRset
 };

+ 59 - 0
src/lib/nsas/tests/nsas_entry_compare_unittest.cc

@@ -0,0 +1,59 @@
+// 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.
+
+// $Id$
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <boost/lexical_cast.hpp>
+
+#include "hash_key.h"
+#include "nsas_entry_compare.h"
+#include "nsas_test.h"
+
+using namespace std;
+
+namespace isc {
+namespace nsas {
+
+/// \brief Test Fixture Class
+class NsasEntryCompareTest : public ::testing::Test {
+};
+
+
+// Test of the comparison
+TEST_F(NsasEntryCompareTest, Compare) {
+
+    // Construct a couple of different objects
+    TestEntry entry1("test1", 42);
+    TestEntry entry2("test1", 24);
+    TestEntry entry3("test2", 42);
+
+    // Create corresponding hash key objects
+    HashKey key1(entry1.getName(), entry1.getClass());
+    HashKey key2(entry2.getName(), entry2.getClass());
+    HashKey key3(entry3.getName(), entry3.getClass());
+    
+    // Perform the comparison
+    NsasEntryCompare<TestEntry> compare;
+
+    EXPECT_TRUE(compare(&entry1, key1));
+    EXPECT_FALSE(compare(&entry1, key2));
+}
+
+} // namespace nsas
+} // namespace isc

+ 82 - 9
src/lib/nsas/tests/nsas_test_utilities.h

@@ -14,13 +14,13 @@
 
 // $Id$
 
-#ifndef __NSAS_TEST_UTILITIES_H
-#define __NSAS_TEST_UTILITIES_H
+#ifndef __NSAS_TEST_H
+#define __NSAS_TEST_H
 
 /// \file test_utilities.h
 ///
-/// Contains miscellaneous classes to help with the nameserver address store
-/// tests.
+/// Contains miscellaneous classes and other stuff to help with the nameserver
+/// address store tests.
 
 #include <string>
 
@@ -30,10 +30,11 @@
 #include "rdata.h"
 #include "rrtype.h"
 #include "messagerenderer.h"
+#include "nsas_entry.h"
 
 using namespace isc::dns::rdata;
 using namespace isc::dns;
-using namespace std;
+
 namespace isc {
 namespace dns {
 
@@ -83,7 +84,7 @@ public:
     ///
     /// \param v4address IPV4 address to store.  (The format of this address is
     /// not checked.)
-    RdataTest(const string& data) : data_(data)
+    RdataTest(const std::string& data) : data_(data)
     {}
 
     /// \brief Convert Rdata to string
@@ -118,7 +119,7 @@ public:
     //@}
 
 private:
-    string      data_;          ///< Rdata itself
+    std::string data_;          ///< Rdata itself
     T           type_;          ///< Identifies type of the Rdata
 };
 
@@ -135,9 +136,81 @@ int RdataTest<T>::compare(const Rdata& other UNUSED_PARAM) const {
     return 0;
 }
 
+} // namespace dns
+} // namespace isc
+
+namespace isc {
+namespace nsas {
+
+/// \brief Test Entry Class
+///
+/// This is an element that can be stored in both the hash table and the
+/// LRU list.
+
+class TestEntry : public NsasEntry<TestEntry> {
+public:
+
+    /// \brief Constructor
+    ///
+    /// \param name Name that will be used for the object.  This will form
+    /// part of the key.
+    /// \param class_code Class associated with the object.
+    TestEntry(std::string name, uint16_t class_code) :
+        name_(name), class_code_(class_code)
+    {}
+
+    /// \brief Virtual Destructor
+    virtual ~TestEntry()
+        {}
+
+    /// \brief Return Hash Key
+    ///
+    /// This must be overridden in all classes derived from NsasEntry, and
+    /// returns the hash key corresponding to the name and class.
+    virtual HashKey hashKey() const {
+        return HashKey(name_, class_code_);
+    }
+
+    /// \brief Get the Name
+    ///
+    /// \return Name given to this object
+    virtual std::string getName() const {
+        return name_;
+    }
+
+    /// \brief Set the Name
+    ///
+    /// \param name New name of the object
+    virtual void setName(const std::string& name) {
+        name_ = name;
+    }
+
+    /// \brief Get the Class
+    ///
+    /// \return Class code assigned to this object
+    virtual uint16_t getClass() const {
+        return class_code_;
+    }
+
+    /// \brief Set the Class
+    ///
+    /// \param class_code New class code of the object
+    virtual void setClass(uint16_t class_code) {
+        class_code_ = class_code;
+    }
+
+private:
+    std::string name_;          ///< Name of the object
+    uint16_t    class_code_;    ///< Class of the object
+};
+
+/// \brief isc::nsas Constants
+///
+/// Some constants used in the various tests.
+
+static const uint32_t HASHTABLE_DEFAULT_SIZE = 1009; ///< First prime above 1000
 
 } // namespace nsas
 } // namespace isc
 
-
-#endif // __NSAS_TEST_UTILITIES_H
+#endif // __NSAS_TEST_H

+ 4 - 2
src/lib/nsas/zone_entry.h

@@ -22,6 +22,7 @@
 #include <boost/thread.h>
 #include <boost/shared_ptr.h>
 
+#include "nsas_entry.h"
 #include "asiolink.h"
 
 class NameserverEntry;
@@ -35,14 +36,15 @@ class NameserverEntry;
 /// complicated, in that the class takes account of triggering fetches for
 /// addresses of nameservers when the address records expire.
 
-class ZoneEntry {
+class ZoneEntry : public NsasEntry<ZoneEntry> {
 public:
 
     /// \brief Constructor
     ///
     /// Creates a zone entry object with an RRset representing the nameservers,
     /// plus possibly additional RRsets holding address information.
-    ZoneEntry(AbstractRRset* nsrrset, const std::vector<AbstractRRSet*>& additional);
+    ZoneEntry(AbstractRRset* nsrrset,
+            const std::vector<AbstractRRSet*>& additional);
 
     /// \brief Lookup Address
     ///