Commit db1f1207 authored by Stephen Morris's avatar Stephen Morris
Browse files

First block of Nameserver Address Store code for review

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac356@3272 e5f2f494-b856-4b98-b285-d166d9295462
parent 20ab020b
......@@ -506,6 +506,8 @@ AC_CONFIG_FILES([Makefile
src/lib/datasrc/Makefile
src/lib/datasrc/tests/Makefile
src/lib/xfr/Makefile
src/lib/nsas/Makefile
src/lib/nsas/tests/Makefile
])
AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
src/bin/cfgmgr/tests/b10-cfgmgr_test.py
......
SUBDIRS = exceptions dns cc config datasrc python xfr bench
SUBDIRS = exceptions dns cc config datasrc python xfr bench nsas
SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/nsas -I$(top_builddir)/src/lib/nsas
AM_CPPFLAGS += $(SQLITE_CFLAGS)
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_table.h
libnsas_la_SOURCES += lru_list.h
libnsas_la_SOURCES += nameserver_entry.cc nameserver_entry.h
libnsas_la_SOURCES += asiolink.h
CLEANFILES = *.gcno *.gcda
For an overview of the Nameserver Address Store, see the requirements and design
documents at http://bind10.isc.org/wiki/Resolver.
At the time of writing (19 October 2010), the file asiolink.h is present in this
directory only for the purposes of development. When the recursor's
asynchronous I/O code has been finished, this will be removed and the NSAS will
use the "real" code.
// 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$
/// \file address_entry.cc
///
/// This file exists to define the single constant \c AddressEntry::UNREACHABLE,
/// equal to the value \c UINT32_MAX.
///
/// Ideally we could use \c UINT32_MAX directly in the header file, but this
/// constant is defined in \c stdint.h only if the macro \c __STDC_LIMIT_MACROS
/// is defined first. (This apparently is the C89 standard.) Defining the
/// macro in \c address_entry.h before including \c stdint.h doesn't work as
/// it is possible that in a source file, \c stdint.h will be included before
/// \c address_entry.h. In that case, the \c stdint.h include sentinel will
/// prevent \c stdint.h being included a second time and the value won't be
/// defined.
///
/// The easiest solution is the one presented here: declare the value as a
/// static class constant, and define it in this source file. As we can control
/// the order of include files, this ensures that the value is defined.
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include "address_entry.h"
namespace isc {
namespace nsas {
const uint32_t AddressEntry::UNREACHABLE = UINT32_MAX;
}
}
// 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 __ADDRESS_ENTRY_H
#define __ADDRESS_ENTRY_H
/// \brief Address Entry
///
/// Lightweight class that couples an address with a RTT and provides some
/// convenience methods for accessing and updating the information.
#include <stdint.h>
#include "asiolink.h"
namespace isc {
namespace nsas {
class AddressEntry {
public:
/// Creates an address entry given IOAddress entry and RTT
/// This is the only constructor; the default copy constructor and
/// assignment operator are valid for this object.
///
/// \param address Address object representing this address
/// \param rtt Initial round-trip time
AddressEntry(const IOAddress& address, uint32_t rtt = 0) :
address_(address), rtt_(rtt)
{}
/// \return Address object
IOAddress getAddress() const {
return address_;
}
/// \return Current round-trip time
uint32_t getRTT() const {
return rtt_;
}
/// Set current RTT
///
/// \param rtt New RTT to be associated with this address
void setRTT(uint32_t rtt) {
rtt_ = rtt; // TODO: Modify to use weighting formula
}
/// Mark address as unreachable.
void setUnreachable() {
setRTT(UNREACHABLE); // Largest long number is code for unreachable
}
/// Check if address is unreachable
///
/// \return true if the address is unreachable, false if not
bool isUnreachable() const {
return (rtt_ == UNREACHABLE);
}
/// \return true if the object is a V4 address
bool isV4() const {
return (address_.getFamily() == AF_INET);
}
/// \return true if the object is a V6 address
bool isV6() const {
return (address_.getFamily() == AF_INET6);
}
// Next element is defined public for testing
static const uint32_t UNREACHABLE; ///< RTT indicating unreachable address
private:
IOAddress address_; ///< Address
uint32_t rtt_; ///< Round-trip time
};
} // namespace dns
} // namespace isc
#endif // __ADDRESS_ENTRY_H
// 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 __ASIOLINK_H
#define __ASIOLINK_H
#include <string>
#include <sys/socket.h>
/// \brief IO Address Dummy Class
///
/// As part of ther recursor, Evan has written the asiolink.h file, which
/// encapsulates some of the boost::asio classes. Until these are checked
/// into trunk and merged with this branch, these dummy classes should fulfill
/// their function.
class IOAddress {
public:
/// \param address_str String representing the address
IOAddress(const std::string& address_str) : address_(address_str)
{}
/// \return Textual representation of the address
std::string toText() const
{return address_;}
/// \return Address family of the address
virtual short getFamily() const {
return ((address_.find(".") != std::string::npos) ? AF_INET : AF_INET6);
}
/// \return true if two addresses are equal
bool equal(const IOAddress& address)
{return (toText() == address.toText());}
private:
std::string address_; ///< Address represented
};
#endif // __ASIOLINK_H
// 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$
/*! \file
* Some parts of this code were copied from BIND-9, which in turn was derived
* from universal hash function libraries of Rice University.
\section license UH Universal Hashing Library
Copyright ((c)) 2002, Rice University
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Rice University (RICE) nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
This software is provided by RICE and the contributors on an "as is"
basis, without any representations or warranties of any kind, express
or implied including, but not limited to, representations or
warranties of non-infringement, merchantability or fitness for a
particular purpose. In no event shall RICE or contributors be liable
for any direct, indirect, incidental, special, exemplary, or
consequential damages (including, but not limited to, procurement of
substitute goods or services; loss of use, data, or profits; or
business interruption) however caused and on any theory of liability,
whether in contract, strict liability, or tort (including negligence
or otherwise) arising in any way out of the use of this software, even
if advised of the possibility of such damage.
*/
#include <stdlib.h>
#include <algorithm>
#include <cassert>
#include <string>
#include "config.h"
#include "hash.h"
namespace isc {
namespace nsas {
// Constructor.
Hash::Hash(uint32_t tablesize, uint32_t maxkeylen, bool randomise) :
tablesize_(tablesize), maxkeylen_(maxkeylen)
{
// Check to see that we can cope with the maximum key length.
// (This code adapted from BIND-9)
//
// Overflow check. Since our implementation only does a modulo
// operation at the last stage of hash calculation, the accumulator
// must not overflow.
hash_accum_t overflow_limit =
1 << (((sizeof(hash_accum_t) - sizeof(hash_random_t))) * 8);
if (overflow_limit < (maxkeylen + 1) * 0xff) {
isc_throw(KeyLengthTooLong, "Hash key length too long for Hash class");
}
// Initialize the random number generator with the current time.
// TODO: Use something other than pseudo-random numbers.
union {
unsigned int seed;
time_t curtime;
} init_value;
if (randomise) {
init_value.curtime = time(NULL);
}
else {
init_value.seed = 0;
}
srandom(init_value.seed);
// Fill in the random vector.
randvec_.reserve(maxkeylen + 1);
for (uint32_t i = 0; i < (maxkeylen + 1); ++i) {
randvec_.push_back(static_cast<hash_random_t>(random() & 0xffff));
}
assert(sizeof(hash_random_t) == 2); // So that the "& 0xffff" is valid
// Finally, initialize the mapping table for uppercase to lowercase
// characters. A table is used as indexing a table is faster than calling
// the tolower() function.
casemap_.reserve(256);
for (int i = 0; i < 256; ++i) {
casemap_.push_back(i);
}
for (int i = 'A'; i <= 'Z'; ++i) {
casemap_[i] += ('a' - 'A');
}
}
uint32_t Hash::operator()(const char* key, uint32_t keylen, bool ignorecase) {
// Calculation as given in BIND-9.
hash_accum_t partial_sum = 0;
uint32_t i = 0; // Used after the end of the loop
// Perform the hashing. If the key length if more than the maximum we set
// up this hash for, ignore the excess.
if (ignorecase) {
for (i = 0; i < min(keylen, maxkeylen_); ++i) {
partial_sum += mapLower(key[i]) * randvec_[i];
}
} else {
for (i = 0; i < min(keylen, maxkeylen_); ++i) {
partial_sum += key[i] * randvec_[i];
}
}
partial_sum += randvec_[i];
// Determine the hash value
uint32_t value = partial_sum % prime32_;
// ... and round it to fit the table size
return (value % tablesize_);
}
} // namespace nsas
} // namespace isc
// 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_H
#define __HASH_H
#include <stdint.h>
#include <vector>
#include "exceptions/exceptions.h"
using namespace std;
namespace isc {
namespace nsas {
/// \brief Too Long Key Length
///
/// Thrown if the expected maximum key length is too long for the data types
/// declared in the class.
class KeyLengthTooLong : public isc::Exception {
public:
KeyLengthTooLong(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what)
{}
};
/// \brief Hash Calculation
///
/// Class abstracting the mechanics of the hash calculation.
class Hash {
public:
/// \brief Constructor
///
/// Constructs the hash table and initialises all data structures needed
/// for the hashing.
///
/// \param tablesize Size of the hash table. For best performance, this
/// should be a prime number.
/// \param maxkeylen Maximum length (in bytes) of a key to be hashed.
/// calculation will return a value between 0 and N-1. The default
/// value of 255 is the maximum size of a DNS name.
/// \param randomise If true (the default), the pseudo-random number generator
/// is seeded with the current time. Otherwise it is initialised to a known
/// sequence. This is principally for unit tests, where a random sequence
/// could lead to problems in checking results.
Hash(uint32_t tablesize, uint32_t maxkeylen = 255, bool randomise = true);
/// \brief Return Size
///
/// \return The hash table size with which this object was initialized
virtual uint32_t tableSize() const {
return tablesize_;
}
/// \brief Return Key Length
///
/// \return Maximum length of a key that this class can cope with.
virtual uint32_t maxKeyLength() const {
return maxkeylen_;
}
/// \brief Hash Value
///
/// \param key String value or array of bytes for which a hash is to be
/// calculated.
/// \param ketlen Number of characters in the string
/// \param ignorecase true for case to be ignored when calculating the
/// hash value, false for it to be taken into account.
///
/// \return Hash value, a number between 0 and N-1.
virtual uint32_t operator()(const char* key, uint32_t keylen, bool ignorecase = true);
/// \brief Map Lower Case to Upper Case
///
/// Equivalent of tolower(), but using a table lookup instead of a
/// function call. This should make the mapping faster.
///
/// \param inchar Input character
///
/// \return Mapped character
unsigned char mapLower(unsigned char inchar) {
return casemap_[inchar];
}
private:
/// \name Local Typedefs
///
/// Typedefs for use in the code. This makes it easier to compare the
/// hashing code with that in BIND-9.
//@{
typedef uint32_t hash_accum_t; ///< Accumulator
typedef uint16_t hash_random_t; ///< Random number used in hash
//@}
uint32_t tablesize_; ///< Size of the hash table
uint32_t maxkeylen_; ///< Maximum key length
vector<unsigned char> casemap_; ///< Case mapping table
vector<hash_random_t> randvec_; ///< Vector of random numbers
static const uint32_t prime32_ = 0xfffffffb; ///< 2^32 - 5
///< Specifies range of hash output
};
} // namspace nsas
} // namespace isc
#endif // __HASH_H
// 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_TABLE_H
#define __HASH_TABLE_H
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
#include <list>
#include "config.h"
#include "hash.h"
// Maximum key length if the maximum size of a DNS name
#define HASHTABLE_SIZE 1009
#define MAX_KEY_LENGTH 255
using namespace std;
using namespace boost::interprocess;
namespace isc {
namespace nsas {
/// \brief Hash Table Slot
///
/// Describes the entry for the hash table. This is non-copyable (because
/// the mutex is non-copyable), but we need to be able to copy it to initialize
/// a vector of hash table slots. As the copy is only needed for
/// initialization, and as there is no need to copy state when this happens, we
/// cheat: the copy constructor constructs a newly initialized HashTableSlot and
/// 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 Default Constructor
HashTableSlot()
{}
/// \brief Copy Constructor
///
/// ... which as noted in the class description does not copy. It is
/// 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;
};
// (Non)Copy Constructor
template <typename T>
HashTableSlot<T>::HashTableSlot(const HashTableSlot<T>& unused UNUSED_PARAM) :
mutex_(), list_()
{}
/// \brief Comparison Object Class
///
/// The base class for a comparison object; this object is used to compare
/// an object in the hash table with a key, and indicates whether the two
/// match. All objects used for comparison in hash tables should be derived
/// from this class.
template <typename T>
class HashTableCompare {
public:
/// \brief Comparison Function
///
/// Compares an object against a name in the hash table and reports if the
/// object's name is the same.
///
/// \param object Pointer to the object
/// \param key Pointer to the name of the object
/// \param keylen Length of the key
///
/// \return bool true of the name of the object is equal to the name given.
virtual bool operator()(T* object, const char* key, uint32_t keylen) = 0;
};
/// \brief Hash Table
///
/// This class is an implementation of a hash table in which the zones and
/// nameservers of the Nameserver Address Store are held.
///
/// A special class has been written (rather than use an existing hash table
/// class) to improve concurrency. Rather than lock the entire hash table when
/// an object is added/removed/looked up, only the entry for a particular hash
/// value is locked. To do this, each entry in the hash table is a pair of
/// mutex/STL List; the mutex protects that particular list.
///
/// \param T Class of object to be stored in the table.
template <typename T>
class HashTable {
public:
/// \brief Constructor
///
/// Initialises the hash table.
///