Browse Source

Hmm, subversion works locally to subdir. Commit the rest of the tree as well

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac408@3764 e5f2f494-b856-4b98-b285-d166d9295462
Michal Vaner 14 years ago
parent
commit
2d7e8185d4

+ 15 - 5
src/lib/nsas/address_entry.h

@@ -37,7 +37,7 @@ public:
     /// \param address Address object representing this address
     /// \param address Address object representing this address
     /// \param rtt Initial round-trip time
     /// \param rtt Initial round-trip time
     AddressEntry(const asiolink::IOAddress& address, uint32_t rtt = 0) :
     AddressEntry(const asiolink::IOAddress& address, uint32_t rtt = 0) :
-        address_(address), rtt_(rtt)
+        address_(address), rtt_(rtt), dead_until_(0)
     {}
     {}
 
 
     /// \return Address object
     /// \return Address object
@@ -46,7 +46,12 @@ public:
     }
     }
 
 
     /// \return Current round-trip time
     /// \return Current round-trip time
-    uint32_t getRTT() const {
+    uint32_t getRTT() {
+        if(dead_until_ != 0 && time(NULL) >= dead_until_){
+            dead_until_ = 0;
+            rtt_ = 1; //reset the rtt to a small value so it has an opportunity to be updated
+        }
+
         return rtt_;
         return rtt_;
     }
     }
 
 
@@ -54,7 +59,11 @@ public:
     ///
     ///
     /// \param rtt New RTT to be associated with this address
     /// \param rtt New RTT to be associated with this address
     void setRTT(uint32_t rtt) {
     void setRTT(uint32_t rtt) {
-        rtt_ = rtt;     // TODO: Modify to use weighting formula
+        if(rtt == UNREACHABLE){
+            dead_until_ = time(NULL) + 5*60;//Cache the unreachable server for 5 minutes (RFC2308 sec7.2)
+        }
+
+        rtt_ = rtt;
     }
     }
 
 
     /// Mark address as unreachable.
     /// Mark address as unreachable.
@@ -65,8 +74,8 @@ public:
     /// Check if address is unreachable
     /// Check if address is unreachable
     ///
     ///
     /// \return true if the address is unreachable, false if not
     /// \return true if the address is unreachable, false if not
-    bool isUnreachable() const {
-        return (rtt_ == UNREACHABLE);
+    bool isUnreachable() {
+        return (getRTT() == UNREACHABLE); // The getRTT() will check the cache time for unreachable server
     }
     }
 
 
     /// \return true if the object is a V4 address
     /// \return true if the object is a V4 address
@@ -85,6 +94,7 @@ public:
 private:
 private:
     asiolink::IOAddress address_;       ///< Address
     asiolink::IOAddress address_;       ///< Address
     uint32_t        rtt_;               ///< Round-trip time
     uint32_t        rtt_;               ///< Round-trip time
+    time_t  dead_until_;                ///< Dead time for unreachable server
 };
 };
 
 
 }   // namespace dns
 }   // namespace dns

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

@@ -46,6 +46,10 @@ public:
     HashDeleter(HashTable<T>& hashtable) : hashtable_(hashtable)
     HashDeleter(HashTable<T>& hashtable) : hashtable_(hashtable)
     {}
     {}
 
 
+    /// \brief Destructor
+    ///
+    virtual ~HashDeleter(){}
+
     // The default copy constructor and assignment operator are correct for
     // The default copy constructor and assignment operator are correct for
     // this object.
     // this object.
 
 

+ 9 - 2
src/lib/nsas/hash_table.h

@@ -89,6 +89,11 @@ HashTableSlot<T>::HashTableSlot(const HashTableSlot<T>& unused UNUSED_PARAM) :
 template <typename T>
 template <typename T>
 class HashTableCompare {
 class HashTableCompare {
 public:
 public:
+    /// \brief Constructor
+    HashTableCompare(){}
+
+    /// \brief virtual Destructor
+    virtual ~HashTableCompare() {}
 
 
     /// \brief Comparison Function
     /// \brief Comparison Function
     ///
     ///
@@ -100,8 +105,6 @@ public:
     ///
     ///
     /// \return bool true of the name of the object is equal to the name given.
     /// \return bool true of the name of the object is equal to the name given.
     virtual bool operator()(T* object, const HashKey& key) const = 0;
     virtual bool operator()(T* object, const HashKey& key) const = 0;
-    /// \brief Virtual destructor
-    virtual ~ HashTableCompare() { }
 };
 };
 
 
 
 
@@ -146,6 +149,10 @@ public:
     /// in BIND-9 for its address database.
     /// in BIND-9 for its address database.
     HashTable(HashTableCompare<T>* cmp, uint32_t size = 1009);
     HashTable(HashTableCompare<T>* cmp, uint32_t size = 1009);
 
 
+    /// \brief Destructor
+    ///
+    virtual ~HashTable(){}
+
     /// \brief Get Entry
     /// \brief Get Entry
     ///
     ///
     /// Returns a shared_ptr object pointing to the table entry
     /// Returns a shared_ptr object pointing to the table entry

+ 5 - 2
src/lib/nsas/lru_list.h

@@ -58,6 +58,11 @@ public:
     /// will handle any additional operations needed.
     /// will handle any additional operations needed.
     class Dropped {
     class Dropped {
     public:
     public:
+        /// \brief Constructor
+        Dropped(){}
+
+        /// \brief Virtual Destructor
+        virtual ~Dropped(){}
 
 
         /// \brief Dropped Object Handler
         /// \brief Dropped Object Handler
         ///
         ///
@@ -66,8 +71,6 @@ public:
         ///
         ///
         /// \param drop Object being dropped.
         /// \param drop Object being dropped.
         virtual void operator()(T* drop) const = 0;
         virtual void operator()(T* drop) const = 0;
-        /// \brief Virtual destructor
-        virtual ~ Dropped() { }
     };
     };
 
 
     /// \brief Constructor
     /// \brief Constructor

+ 28 - 12
src/lib/nsas/nameserver_address.h

@@ -25,6 +25,17 @@
 namespace isc {
 namespace isc {
 namespace nsas {
 namespace nsas {
 
 
+/// \brief Empty \c NameserverEntry pointer exception
+///
+/// Thrown if the the \c NameservrEntry pointer in the \c boost::shared_ptr that passed
+/// into \c NameserverAddress' constructor is NULL
+class NullNameserverEntryPointer : public isc::Exception {
+public:
+    NullNameserverEntryPointer(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what)
+    {}
+};
+
 /// \brief Nameserver Address
 /// \brief Nameserver Address
 ///
 ///
 /// This class implements the object that returned from NSAS when the resolver
 /// This class implements the object that returned from NSAS when the resolver
@@ -45,8 +56,18 @@ public:
     /// the shared_ptr can avoid the NameserverEntry object being dropped while the
     /// the shared_ptr can avoid the NameserverEntry object being dropped while the
     /// request is processing.
     /// request is processing.
     /// \param index The address's index in NameserverEntry's addresses vector
     /// \param index The address's index in NameserverEntry's addresses vector
-    NameserverAddress(boost::shared_ptr<NameserverEntry>& nameserver, uint32_t index):
-        ns_(nameserver), index_(index)
+    /// \param family Address family, AF_INET or AF_INET6
+    NameserverAddress(boost::shared_ptr<NameserverEntry>& nameserver, uint32_t index, short family):
+        ns_(nameserver), index_(index), family_(family)
+    {
+        if(!ns_.get()) {
+            isc_throw(NullNameserverEntryPointer, "NULL NameserverEntry pointer.");
+        }
+    }
+
+    /// \brief Default Constructor
+    ///
+    NameserverAddress(): index_(0), family_(AF_INET)
     {
     {
     }
     }
 
 
@@ -54,14 +75,13 @@ public:
     ///
     ///
     /// Empty destructor.
     /// Empty destructor.
     ~NameserverAddress()
     ~NameserverAddress()
-    {}
+    {
+    }
 
 
     /// \brief Return address
     /// \brief Return address
     ///
     ///
     asiolink::IOAddress getAddress() const { 
     asiolink::IOAddress getAddress() const { 
-        NameserverEntry *ne = ns_.get();
-        assert(ne != NULL);
-        return ne->getAddressAtIndex(index_); 
+        return ns_.get()->getAddressAtIndex(index_, family_); 
     }
     }
 
 
     /// \brief Update Round-trip Time
     /// \brief Update Round-trip Time
@@ -70,17 +90,13 @@ public:
     /// update the address's RTT.
     /// update the address's RTT.
     /// \param rtt The new Round-Trip Time
     /// \param rtt The new Round-Trip Time
     void updateRTT(uint32_t rtt) { 
     void updateRTT(uint32_t rtt) { 
-        NameserverEntry* ne = ns_.get();
-        if(ne) ne->updateAddressRTTAtIndex(rtt, index_); 
+        ns_.get()->updateAddressRTTAtIndex(rtt, index_, family_); 
     }
     }
 private:
 private:
-    /// \brief Default Constructor
-    ///
-    /// A private default constructor to avoid creating an empty object.
-    NameserverAddress();
 
 
     boost::shared_ptr<NameserverEntry> ns_;  ///< Shared-pointer to NameserverEntry object
     boost::shared_ptr<NameserverEntry> ns_;  ///< Shared-pointer to NameserverEntry object
     uint32_t index_;                         ///< The address index in NameserverEntry
     uint32_t index_;                         ///< The address index in NameserverEntry
+    short family_;                           ///< Address family AF_INET or AF_INET6
 };
 };
 
 
 } // namespace nsas
 } // namespace nsas

+ 125 - 13
src/lib/nsas/nameserver_entry.cc

@@ -33,6 +33,7 @@
 #include <dns/question.h>
 #include <dns/question.h>
 
 
 #include "address_entry.h"
 #include "address_entry.h"
+#include "nameserver_address.h"
 #include "nameserver_entry.h"
 #include "nameserver_entry.h"
 #include "resolver_interface.h"
 #include "resolver_interface.h"
 
 
@@ -78,6 +79,9 @@ NameserverEntry::getAddresses(AddressVector& addresses,
 
 
     if (getState() == EXPIRED && !expired_ok) {
     if (getState() == EXPIRED && !expired_ok) {
         return EXPIRED;
         return EXPIRED;
+
+        // Update the address selector
+        updateAddressSelector(v4_addresses_, v4_address_selector_);
     }
     }
 
 
     switch (getState()) {
     switch (getState()) {
@@ -116,6 +120,9 @@ NameserverEntry::getAddresses(AddressVector& addresses,
         remove_copy_if(address_.begin(), address_.end(),
         remove_copy_if(address_.begin(), address_.end(),
             back_inserter(addresses), boost::bind(addressSelection, s_family,
             back_inserter(addresses), boost::bind(addressSelection, s_family,
             _1));
             _1));
+
+        // Update the address selector
+        updateAddressSelector(v6_addresses_, v6_address_selector_);
     }
     }
     if (getState() == EXPIRED && expired_ok) {
     if (getState() == EXPIRED && expired_ok) {
         return READY;
         return READY;
@@ -123,13 +130,41 @@ NameserverEntry::getAddresses(AddressVector& addresses,
     return getState();
     return getState();
 }
 }
 
 
-asiolink::IOAddress
-NameserverEntry::getAddressAtIndex(uint32_t index) const {
+// Return one address matching the given family
+bool NameserverEntry::getAddress(NameserverAddress& address, short family)
+{
     Lock lock(mutex_);
     Lock lock(mutex_);
 
 
-    assert(index < address_.size());
+// TODO Change to AddressFamily
+    // Get the shared_ptr object that point to "this" object
+    shared_ptr<NameserverEntry> shared_ptr_to_this = shared_from_this();
 
 
-    return address_[index].getAddress();
+    if(family == AF_INET){
+        if(v4_addresses_.size() == 0) return false;
+
+        address = NameserverAddress(shared_ptr_to_this, v4_address_selector_(), AF_INET);
+        return true;
+    } else if(family == AF_INET6){
+        if(v6_addresses_.size() == 0) return false;
+
+        //address = NameserverAddress(shared_from_this(), v6_address_selector_(), AF_INET6);
+        return true;
+    }
+    return false;
+}
+
+// Return the address corresponding to the family
+asiolink::IOAddress NameserverEntry::getAddressAtIndex(uint32_t index, short family) const
+{
+    Lock lock(mutex_);
+
+    const vector<AddressEntry> *addresses = &v4_addresses_;
+    if(family == AF_INET6){
+        addresses = &v6_addresses_;
+    }
+    assert(index < addresses->size());
+
+    return (*addresses)[index].getAddress();
 }
 }
 
 
 // Set the address RTT to a specific value
 // Set the address RTT to a specific value
@@ -138,23 +173,55 @@ NameserverEntry::setAddressRTT(const IOAddress& address, uint32_t rtt) {
     Lock lock(mutex_);
     Lock lock(mutex_);
 
 
     // Search through the list of addresses for a match
     // Search through the list of addresses for a match
-    for (AddressVectorIterator i = address_.begin(); i != address_.end(); ++i) {
+    for (AddressVectorIterator i = v4_addresses_.begin(); i != v4_addresses_.end(); ++i) {
+        if (i->getAddress().equal(address)) {
+            i->setRTT(rtt);
+
+            // Update the selector
+            updateAddressSelector(v4_addresses_, v4_address_selector_);
+            return;
+        }
+    }
+
+    // Search the v6 list
+    for (AddressVectorIterator i = v6_addresses_.begin(); i != v6_addresses_.end(); ++i) {
         if (i->getAddress().equal(address)) {
         if (i->getAddress().equal(address)) {
             i->setRTT(rtt);
             i->setRTT(rtt);
+
+            // Update the selector
+            updateAddressSelector(v6_addresses_, v6_address_selector_);
+            return;
         }
         }
     }
     }
 }
 }
 
 
 // Update the address's rtt 
 // Update the address's rtt 
-void
-NameserverEntry::updateAddressRTTAtIndex(uint32_t rtt, uint32_t index) {
+#define UPDATE_RTT_ALPHA 0.7
+void NameserverEntry::updateAddressRTTAtIndex(uint32_t rtt, uint32_t index, short family) {
     Lock lock(mutex_);
     Lock lock(mutex_);
 
 
-    //make sure it is a valid index
-    if(index >= address_.size()) return;
+    vector<AddressEntry>* addresses = &v4_addresses_;
+    if(family == AF_INET6){
+        addresses = &v6_addresses_;
+    }
 
 
-    //update the rtt
-    address_[index].setRTT(rtt);
+    //make sure it is a valid index
+    if(index >= addresses->size()) return;
+
+    // Smoothly update the rtt
+    // The algorithm is as the same as bind8/bind9:
+    //    new_rtt = old_rtt * alpha + new_rtt * (1 - alpha), where alpha is a float number in [0, 1.0]
+    // The default value for alpha is 0.7
+    uint32_t old_rtt = (*addresses)[index].getRTT();
+    uint32_t new_rtt = (int)(old_rtt * UPDATE_RTT_ALPHA + rtt * (1 - UPDATE_RTT_ALPHA));
+    (*addresses)[index].setRTT(new_rtt);
+
+    // Update the selector
+    if(family == AF_INET) { 
+        updateAddressSelector(v4_addresses_, v4_address_selector_);
+    } else if(family == AF_INET6) {
+        updateAddressSelector(v6_addresses_, v6_address_selector_);
+    }
 }
 }
 
 
 // Sets the address to be unreachable
 // Sets the address to be unreachable
@@ -169,6 +236,7 @@ NameserverEntry::setAddressUnreachable(const IOAddress& address) {
  * pointer to the entry so it is not destroyed too soon.
  * pointer to the entry so it is not destroyed too soon.
  */
  */
 class NameserverEntry::ResolverCallback : public ResolverInterface::Callback {
 class NameserverEntry::ResolverCallback : public ResolverInterface::Callback {
+    // TODO This needs to bring in some changes from the constructor
     public:
     public:
         ResolverCallback(shared_ptr<NameserverEntry> entry,
         ResolverCallback(shared_ptr<NameserverEntry> entry,
             AddressFamily family, const RRType& type) :
             AddressFamily family, const RRType& type) :
@@ -199,8 +267,7 @@ class NameserverEntry::ResolverCallback : public ResolverInterface::Callback {
                 // Try to find the original value and reuse its rtt
                 // Try to find the original value and reuse its rtt
                 string address(i->getCurrent().toText());
                 string address(i->getCurrent().toText());
                 int curr_rtt(-1);
                 int curr_rtt(-1);
-                BOOST_FOREACH(const AddressEntry& entry,
-                    entry_->previous_addresses_)
+                BOOST_FOREACH(AddressEntry& entry, entry_->previous_addresses_)
                 {
                 {
                     if (entry.getAddress().toText() == address) {
                     if (entry.getAddress().toText() == address) {
                         curr_rtt = entry.getRTT();
                         curr_rtt = entry.getRTT();
@@ -372,5 +439,50 @@ NameserverEntry::askIP(shared_ptr<ResolverInterface> resolver,
     }
     }
 }
 }
 
 
+// Update the address selector according to the RTTs
+//
+// Each address has a probability to be selected if multiple addresses are available
+// The weight factor is equal to 1/(rtt*rtt), then all the weight factors are normalized
+// to make the sum equal to 1.0
+void NameserverEntry::updateAddressSelector(std::vector<AddressEntry>& addresses, 
+        WeightedRandomIntegerGenerator& selector)
+{
+    Lock lock(mutex_);
+
+    vector<double> probabilities;
+    for(vector<AddressEntry>::iterator it = addresses.begin(); 
+            it != addresses.end(); ++it){
+        uint32_t rtt = (*it).getRTT();
+        if(rtt == 0) {
+            isc_throw(RTTIsZero, "The RTT is 0");
+        }
+
+        if(rtt == AddressEntry::UNREACHABLE) {
+            probabilities.push_back(0);
+        } else {
+            probabilities.push_back(1.0/(rtt*rtt));
+        }
+    }
+    // Calculate the sum
+    double sum = accumulate(probabilities.begin(), probabilities.end(), 0.0);
+
+    if(sum != 0) {
+        // Normalize the probabilities to make the sum equal to 1.0
+        for(vector<double>::iterator it = probabilities.begin(); 
+                it != probabilities.end(); ++it){
+            (*it) /= sum;
+        }
+    } else if(probabilities.size() > 0){
+        // If all the nameservers are unreachable, the sum will be 0
+        // So give each server equal opportunity to be selected.
+        for(vector<double>::iterator it = probabilities.begin(); 
+                it != probabilities.end(); ++it){
+            (*it) = 1.0/probabilities.size();
+        }
+    }
+
+    selector.reset(probabilities);
+}
+
 } // namespace dns
 } // namespace dns
 } // namespace isc
 } // namespace isc

+ 39 - 7
src/lib/nsas/nameserver_entry.h

@@ -28,16 +28,19 @@
 
 
 #include "address_entry.h"
 #include "address_entry.h"
 #include "asiolink.h"
 #include "asiolink.h"
-#include "nsas_entry.h"
 #include "nsas_types.h"
 #include "nsas_types.h"
 #include "hash_key.h"
 #include "hash_key.h"
 #include "lru_list.h"
 #include "lru_list.h"
 #include "fetchable.h"
 #include "fetchable.h"
 #include "resolver_interface.h"
 #include "resolver_interface.h"
+#include "nsas_entry.h"
+#include "random_number_generator.h"
 
 
 namespace isc {
 namespace isc {
 namespace nsas {
 namespace nsas {
 
 
+class NameserverAddress;
+
 /// \brief Inconsistent Owner Names
 /// \brief Inconsistent Owner Names
 ///
 ///
 /// Thrown if a NameserverEntry is constructed from both an A and AAAA RRset
 /// Thrown if a NameserverEntry is constructed from both an A and AAAA RRset
@@ -49,6 +52,16 @@ public:
     {}
     {}
 };
 };
 
 
+/// \brief RTT is zero
+///
+/// Thrown if a RTT related with an address is 0.
+class RTTIsZero : public Exception {
+public:
+    RTTIsZero(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what)
+    {}
+};
+
 /// \brief Inconsistent Class
 /// \brief Inconsistent Class
 ///
 ///
 /// Thrown if a NameserverEntry is constructed from both an A and AAAA RRset
 /// Thrown if a NameserverEntry is constructed from both an A and AAAA RRset
@@ -87,9 +100,7 @@ class ResolverInterface;
 ///
 ///
 /// It uses shared_from_this in its methods. It must live inside a shared_ptr.
 /// It uses shared_from_this in its methods. It must live inside a shared_ptr.
 
 
-class NameserverEntry : public NsasEntry<NameserverEntry>, public Fetchable,
-    public boost::enable_shared_from_this<NameserverEntry>
-{
+class NameserverEntry : public NsasEntry<NameserverEntry>, public Fetchable {
 public:
 public:
     /// List of addresses associated with this nameserver
     /// List of addresses associated with this nameserver
     typedef std::vector<AddressEntry>   AddressVector;
     typedef std::vector<AddressEntry>   AddressVector;
@@ -130,11 +141,19 @@ public:
         NameserverEntry::AddressVector& addresses,
         NameserverEntry::AddressVector& addresses,
         AddressFamily family = ANY_OK, bool expired_ok = false);
         AddressFamily family = ANY_OK, bool expired_ok = false);
 
 
-    // TODO Is this one of any use at all?
+    /// \brief Return one address
+    ///
+    /// Return one address corresponding to this nameserver
+    /// \param address NameserverAddress object used to receive the address
+    /// \param family The family of user request, AF_INET or AF_INET6
+    /// \return true if one address is found, false otherwise
+    virtual bool getAddress(NameserverAddress& address, short family);
+
     /// \brief Return Address that corresponding to the index
     /// \brief Return Address that corresponding to the index
     ///
     ///
     /// \param index The address index in the address vector
     /// \param index The address index in the address vector
-    asiolink::IOAddress getAddressAtIndex(uint32_t index) const;
+    /// \param family The address family, AF_INET or AF_INET6
+    asiolink::IOAddress getAddressAtIndex(uint32_t index, short family) const;
 
 
     /// \brief Update RTT
     /// \brief Update RTT
     ///
     ///
@@ -148,7 +167,8 @@ public:
     ///
     ///
     /// \param rtt Round-Trip Time
     /// \param rtt Round-Trip Time
     /// \param index The address's index in address vector
     /// \param index The address's index in address vector
-    void updateAddressRTTAtIndex(uint32_t rtt, uint32_t index);
+    /// \param family The address family, AF_INET or AF_INET6
+    void updateAddressRTTAtIndex(uint32_t rtt, uint32_t index, short family);
 
 
     /// \brief Set Address Unreachable
     /// \brief Set Address Unreachable
     ///
     ///
@@ -241,6 +261,18 @@ private:
     /// Call unlocked.
     /// Call unlocked.
     void askIP(boost::shared_ptr<ResolverInterface> resolver,
     void askIP(boost::shared_ptr<ResolverInterface> resolver,
         const isc::dns::RRType&, AddressFamily);
         const isc::dns::RRType&, AddressFamily);
+    /// \brief Update the address selector according to the RTTs of addresses
+    ///
+    /// \param addresses The address list
+    /// \param selector Weighted random generator
+    void updateAddressSelector(std::vector<AddressEntry>& addresses, 
+            WeightedRandomIntegerGenerator& selector);
+
+    // TODO Unite address_ and v?_addresses_
+    std::vector<AddressEntry> v4_addresses_;             ///< Set of V4 addresses
+    std::vector<AddressEntry> v6_addresses_;             ///< Set of V6 addresses
+    WeightedRandomIntegerGenerator v4_address_selector_; ///< Generate one integer according to different probability
+    WeightedRandomIntegerGenerator v6_address_selector_; ///< Generate one integer according to different probability
 };
 };
 
 
 }   // namespace dns
 }   // namespace dns

+ 5 - 3
src/lib/nsas/nsas_entry.h

@@ -17,6 +17,7 @@
 #ifndef __NSAS_ENTRY_H
 #ifndef __NSAS_ENTRY_H
 #define __NSAS_ENTRY_H
 #define __NSAS_ENTRY_H
 
 
+#include <boost/enable_shared_from_this.hpp>
 #include <iostream>
 #include <iostream>
 
 
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
@@ -39,7 +40,6 @@ public:
     {}
     {}
 };
 };
 
 
-
 /// \brief Element of NSAS Internal Lists
 /// \brief Element of NSAS Internal Lists
 ///
 ///
 /// This defines an element of the NSAS lists.  All elements stored in these
 /// This defines an element of the NSAS lists.  All elements stored in these
@@ -64,9 +64,11 @@ public:
 /// pointers, but a shared pointer to a base class is not a subclass of a
 /// 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
 /// shared pointer to a derived class.  For this reason, the type of element
 /// being stored is a template parameter.
 /// being stored is a template parameter.
-
+///
+/// This class is inherited from boost::enable_shared_from_this class
+/// So within a member function a shared_ptr to current object can be obtained
 template <typename T>
 template <typename T>
-class NsasEntry {
+class NsasEntry : public boost::enable_shared_from_this <T>  {
 public:
 public:
 
 
     /// \brief Default Constructor
     /// \brief Default Constructor

+ 166 - 0
src/lib/nsas/random_number_generator.h

@@ -0,0 +1,166 @@
+// 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_RANDOM_NUMBER_GENERATOR_H
+#define __NSAS_RANDOM_NUMBER_GENERATOR_H
+
+#include <cmath>
+#include <numeric>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/random/uniform_real.hpp>
+#include <boost/random/variate_generator.hpp>
+
+namespace isc {
+namespace nsas {
+
+/// \brief Uniform random integer generator
+///
+/// Generate uniformly distributed integers in range of [min, max]
+class UniformRandomIntegerGenerator{
+public:
+    /// \brief Constructor
+    ///
+    /// \param min The minimum number in the range
+    /// \param max The maximum number in the range
+    UniformRandomIntegerGenerator(int min, int max):
+        min_(min), max_(max), dist_(min, max), generator_(rng_, dist_)
+    {
+        // Init with the current time
+        rng_.seed(time(NULL));
+    }
+
+    /// \brief Generate uniformly distributed integer
+    int operator()() { return generator_(); }
+private:
+    /// Hide default and copy constructor
+    UniformRandomIntegerGenerator();///< Default constructor
+    UniformRandomIntegerGenerator(const UniformRandomIntegerGenerator&); ///< Copy constructor
+
+    int min_;                       ///< The minimum integer that can generate
+    int max_;                       ///< The maximum integer that can generate
+    boost::uniform_int<> dist_;     ///< Distribute uniformly.
+    boost::mt19937 rng_;            ///< Mersenne Twister: A 623-dimensionally equidistributed uniform pseudo-random number generator
+    boost::variate_generator<boost::mt19937&, boost::uniform_int<> > generator_; ///< Uniform generator
+};
+
+/// \brief Weighted random integer generator
+///
+/// Generate random integers according different probabilities
+class WeightedRandomIntegerGenerator{
+public:
+    /// \brief Constructor
+    ///
+    /// \param probabilities The probabies for all the integers, the probability must be 
+    /// between 0 and 1.0, the sum of probabilities must be equal to 1.
+    /// For example, if the probabilities contains the following values:
+    /// 0.5 0.3 0.2, the 1st integer will be generated more frequently than the
+    /// other integers and the probability is proportional to its value.
+    /// \param min The minimum integer that generated, other integers will be 
+    /// min, min + 1, ..., min + probabilities.size() - 1
+    WeightedRandomIntegerGenerator(const std::vector<double>& probabilities, int min = 0):
+        dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(min)
+    {
+        // The probabilities must be valid
+        assert(isProbabilitiesValid(probabilities));
+        // Calculate the partial sum of probabilities
+        std::partial_sum(probabilities.begin(), probabilities.end(),
+                                     std::back_inserter(cumulative_));
+        // Init with the current time
+        rng_.seed(time(NULL));
+    }
+    
+    /// \brief Default constructor
+    ///
+    WeightedRandomIntegerGenerator():
+        dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(0)
+    {
+    }
+
+    /// \brief Reset the probabilities
+    ///
+    /// Change the weights of each integers
+    /// \param probabilities The probabies for all the integers
+    /// \param min The minimum integer that generated
+    void reset(const std::vector<double>& probabilities, int min = 0)
+    {
+        // The probabilities must be valid
+        assert(isProbabilitiesValid(probabilities));
+
+        // Reset the cumulative sum
+        cumulative_.clear();
+
+        // Calculate the partial sum of probabilities
+        std::partial_sum(probabilities.begin(), probabilities.end(),
+                                     std::back_inserter(cumulative_));
+
+        // Reset the minimum integer
+        min_ = min;
+
+        // Reset the random number generator
+        rng_.seed(time(NULL));
+    }
+
+    /// \brief Generate weighted random integer
+    int operator()()
+    {
+        return std::lower_bound(cumulative_.begin(), cumulative_.end(), uniform_real_gen_()) 
+            - cumulative_.begin() + min_;
+    }
+
+    /// \brief Destroctor
+    ~WeightedRandomIntegerGenerator()
+    {
+    }
+
+private:
+    /// \brief Check the validation of probabilities vector
+    ///
+    /// The probability must be in range of [0, 1.0] and the sum must be equal to 1.0
+    /// Empty probabilities is also valid.
+    bool isProbabilitiesValid(const std::vector<double>& probabilities) const
+    {
+        typedef std::vector<double>::const_iterator Iterator;
+        double sum = probabilities.empty() ? 1.0 : 0.0;
+        for(Iterator it = probabilities.begin(); it != probabilities.end(); ++it){
+            //The probability must be in [0, 1.0]
+            if(*it < 0.0 || *it > 1.0) {
+                return false;
+            }
+
+            sum += *it;
+        }
+
+        double epsilon = 0.0001;
+        // The sum must be equal to 1
+        return fabs(sum - 1.0) < epsilon;
+    }
+
+    // Shortcut typedefs
+    typedef boost::variate_generator<boost::mt19937&, boost::uniform_real<> > UniformRealGenerator;
+
+    std::vector<double> cumulative_;            ///< The partial sum of the probabilities
+    boost::mt19937 rng_;                        ///< Mersenne Twister: A 623-dimensionally equidistributed uniform pseudo-random number generator 
+    boost::uniform_real<> dist_;                ///< Uniformly distributed real numbers
+    UniformRealGenerator uniform_real_gen_;     ///< Uniformly distributed random real numbers generator
+    int min_;                                   ///< The minimum integer that will be generated
+};
+
+}   // namespace dns
+}   // namespace isc
+
+
+#endif//__NSAS_RANDOM_NUMBER_GENERATOR_H

+ 1 - 3
src/lib/nsas/zone_entry.h

@@ -50,9 +50,7 @@ class AddressRequestCallback;
 ///
 ///
 /// It uses shared_from_this in its methods. It must live inside a shared_ptr.
 /// It uses shared_from_this in its methods. It must live inside a shared_ptr.
 
 
-class ZoneEntry : public NsasEntry<ZoneEntry>, public Fetchable,
-    public boost::enable_shared_from_this<ZoneEntry>
-{
+class ZoneEntry : public NsasEntry<ZoneEntry>, public Fetchable {
 public:
 public:
 
 
     /**
     /**