Commit d7267561 authored by Thomas Markwalder's avatar Thomas Markwalder

[master] Merge branch 'trac3059'

Adds initial implementation of D2UpdateMgr class to
src/bin/d2.
parents feeb79f5 0fc5b23e
......@@ -56,6 +56,7 @@ b10_dhcp_ddns_SOURCES += d2_config.cc d2_config.h
b10_dhcp_ddns_SOURCES += d2_cfg_mgr.cc d2_cfg_mgr.h
b10_dhcp_ddns_SOURCES += d2_queue_mgr.cc d2_queue_mgr.h
b10_dhcp_ddns_SOURCES += d2_update_message.cc d2_update_message.h
b10_dhcp_ddns_SOURCES += d2_update_mgr.cc d2_update_mgr.h
b10_dhcp_ddns_SOURCES += d2_zone.cc d2_zone.h
b10_dhcp_ddns_SOURCES += dns_client.cc dns_client.h
......@@ -69,7 +70,7 @@ b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/asiodns/libb10-asiodns.la
b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libb10-dhcp_ddns.la
b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
b10_dhcp_ddns_LDADD += $(top_builddir)/src/lib/hooks/libb10-hooks.la
......
......@@ -14,6 +14,7 @@
#include <d2/d2_log.h>
#include <d2/d2_cfg_mgr.h>
#include <util/encode/hex.h>
#include <boost/foreach.hpp>
......@@ -39,7 +40,7 @@ D2CfgContext::D2CfgContext(const D2CfgContext& rhs) : DCfgContextBase(rhs) {
reverse_mgr_->setDomains(rhs.reverse_mgr_->getDomains());
}
keys_ = rhs.keys_;
keys_ = rhs.keys_;
}
D2CfgContext::~D2CfgContext() {
......@@ -47,6 +48,10 @@ D2CfgContext::~D2CfgContext() {
// *********************** D2CfgMgr *************************
const char* D2CfgMgr::IPV4_REV_ZONE_SUFFIX = "in-addr.arpa.";
const char* D2CfgMgr::IPV6_REV_ZONE_SUFFIX = "ip6.arpa.";
D2CfgMgr::D2CfgMgr() : DCfgMgrBase(DCfgContextBasePtr(new D2CfgContext())) {
// TSIG keys need to parse before the Domains, so we can catch Domains
// that specify undefined keys. Create the necessary parsing order now.
......@@ -76,17 +81,79 @@ D2CfgMgr::matchForward(const std::string& fqdn, DdnsDomainPtr& domain) {
}
bool
D2CfgMgr::matchReverse(const std::string& fqdn, DdnsDomainPtr& domain) {
if (fqdn.empty()) {
// This is a programmatic error and should not happen.
isc_throw(D2CfgError, "matchReverse passed a null or empty fqdn");
}
D2CfgMgr::matchReverse(const std::string& ip_address, DdnsDomainPtr& domain) {
// Note, reverseIpAddress will throw if the ip_address is invalid.
std::string reverse_address = reverseIpAddress(ip_address);
// Fetch the reverse manager from the D2 context.
DdnsDomainListMgrPtr mgr = getD2CfgContext()->getReverseMgr();
// Call the manager's match method and return the result.
return (mgr->matchDomain(fqdn, domain));
return (mgr->matchDomain(reverse_address, domain));
}
std::string
D2CfgMgr::reverseIpAddress(const std::string& address) {
try {
// Convert string address into an IOAddress and invoke the
// appropriate reverse method.
isc::asiolink::IOAddress ioaddr(address);
if (ioaddr.isV4()) {
return (reverseV4Address(ioaddr));
}
return (reverseV6Address(ioaddr));
} catch (const isc::Exception& ex) {
isc_throw(D2CfgError, "D2CfgMgr cannot reverse address: "
<< address << " : " << ex.what());
}
}
std::string
D2CfgMgr::reverseV4Address(const isc::asiolink::IOAddress& ioaddr) {
if (!ioaddr.isV4()) {
isc_throw(D2CfgError, "D2CfgMgr address is not IPv4 address :"
<< ioaddr.toText());
}
// Get the address in byte vector form.
std::vector<uint8_t> bytes = ioaddr.toBytes();
// Walk backwards through vector outputting each octet and a dot.
std::ostringstream stream;
std::vector<uint8_t>::const_reverse_iterator rit;
for (rit = bytes.rbegin(); rit != bytes.rend(); ++rit) {
stream << static_cast<unsigned int>(*rit) << ".";
}
// Tack on the suffix and we're done.
stream << IPV4_REV_ZONE_SUFFIX;
return(stream.str());
}
std::string
D2CfgMgr::reverseV6Address(const isc::asiolink::IOAddress& ioaddr) {
if (!ioaddr.isV6()) {
isc_throw(D2CfgError, "D2Cfg address is not IPv6 address: "
<< ioaddr.toText());
}
// Turn the address into a string of digits.
std::vector<uint8_t> bytes = ioaddr.toBytes();
std::string digits;
digits = isc::util::encode::encodeHex(bytes);
// Walk backwards through string outputting each digits and a dot.
std::ostringstream stream;
std::string::const_reverse_iterator rit;
for (rit = digits.rbegin(); rit != digits.rend(); ++rit) {
stream << static_cast<char>(*rit) << ".";
}
// Tack on the suffix and we're done.
stream << IPV6_REV_ZONE_SUFFIX;
return(stream.str());
}
......@@ -99,10 +166,10 @@ D2CfgMgr::createConfigParser(const std::string& config_id) {
isc::dhcp::DhcpConfigParser* parser = NULL;
if ((config_id == "interface") ||
(config_id == "ip_address")) {
parser = new isc::dhcp::StringParser(config_id,
parser = new isc::dhcp::StringParser(config_id,
context->getStringStorage());
} else if (config_id == "port") {
parser = new isc::dhcp::Uint32Parser(config_id,
parser = new isc::dhcp::Uint32Parser(config_id,
context->getUint32Storage());
} else if (config_id == "forward_ddns") {
parser = new DdnsDomainListMgrParser("forward_mgr",
......
......@@ -105,6 +105,14 @@ typedef boost::shared_ptr<DdnsDomainListMgr> DdnsDomainListMgrPtr;
/// and retrieving the information on demand.
class D2CfgMgr : public DCfgMgrBase {
public:
/// @brief Reverse zone suffix added to IPv4 addresses for reverse lookups
/// @todo This should be configurable.
static const char* IPV4_REV_ZONE_SUFFIX;
/// @brief Reverse zone suffix added to IPv6 addresses for reverse lookups
/// @todo This should be configurable.
static const char* IPV6_REV_ZONE_SUFFIX;
/// @brief Constructor
D2CfgMgr();
......@@ -119,30 +127,84 @@ public:
}
/// @brief Matches a given FQDN to a forward domain.
///
///
/// This calls the matchDomain method of the forward domain manager to
/// match the given FQDN to a forward domain.
/// match the given FQDN to a forward domain.
///
/// @param fqdn is the name for which to look.
/// @param domain receives the matching domain. Note that it will be reset
/// upon entry and only set if a match is subsequently found.
///
/// @return returns true if a match is found, false otherwise.
/// @throw throws D2CfgError if given an invalid fqdn.
bool matchForward(const std::string& fqdn, DdnsDomainPtr &domain);
/// @throw throws D2CfgError if given an invalid fqdn.
bool matchForward(const std::string& fqdn, DdnsDomainPtr& domain);
/// @brief Matches a given FQDN to a reverse domain.
/// @brief Matches a given IP address to a reverse domain.
///
/// This calls the matchDomain method of the reverse domain manager to
/// match the given FQDN to a forward domain.
/// match the given IPv4 or IPv6 address to a reverse domain.
///
/// @param fqdn is the name for which to look.
/// @param ip_address is the name for which to look.
/// @param domain receives the matching domain. Note that it will be reset
/// upon entry and only set if a match is subsequently found.
///
/// @return returns true if a match is found, false otherwise.
/// @throw throws D2CfgError if given an invalid fqdn.
bool matchReverse(const std::string& fqdn, DdnsDomainPtr &domain);
/// @throw throws D2CfgError if given an invalid fqdn.
bool matchReverse(const std::string& ip_address, DdnsDomainPtr& domain);
/// @brief Generate a reverse order string for the given IP address
///
/// This method creates a string containing the given IP address
/// contents in reverse order. This format is used for matching
/// against reverse DDNS domains in DHCP_DDNS configuration.
/// After reversing the syllables of the address, it appends the
/// appropriate suffix.
///
/// @param address string containing a valid IPv4 or IPv6 address.
///
/// @return a std::string containing the reverse order address.
///
/// @throw D2CfgError if given an invalid address.
static std::string reverseIpAddress(const std::string& address);
/// @brief Generate a reverse order string for the given IP address
///
/// This method creates a string containing the given IP address
/// contents in reverse order. This format is used for matching
/// against reverse DDNS domains in DHCP_DDNS configuration.
/// After reversing the syllables of the address, it appends the
/// appropriate suffix.
///
/// Example:
/// input: 192.168.1.15
/// output: 15.1.168.192.in-addr.arpa.
///
/// @param ioaddr is the IPv4 IOaddress to convert
///
/// @return a std::string containing the reverse order address.
///
/// @throw D2CfgError if not given an IPv4 address.
static std::string reverseV4Address(const isc::asiolink::IOAddress& ioaddr);
/// @brief Generate a reverse order string for the given IP address
///
/// This method creates a string containing the given IPv6 address
/// contents in reverse order. This format is used for matching
/// against reverse DDNS domains in DHCP_DDNS configuration.
/// After reversing the syllables of the address, it appends the
/// appropriate suffix.
///
/// IPv6 example:
/// input: 2001:db8:302:99::
/// output:
///0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.9.0.0.2.0.3.0.8.B.D.0.1.0.0.2.ip6.arpa.
///
/// @param address string containing a valid IPv6 address.
///
/// @return a std::string containing the reverse order address.
///
/// @throw D2CfgError if not given an IPv6 address.
static std::string reverseV6Address(const isc::asiolink::IOAddress& ioaddr);
protected:
/// @brief Given an element_id returns an instance of the appropriate
......
......@@ -91,44 +91,67 @@ DdnsDomainListMgr::setDomains(DdnsDomainMapPtr domains) {
bool
DdnsDomainListMgr::matchDomain(const std::string& fqdn, DdnsDomainPtr& domain) {
// Clear the return parameter.
domain.reset();
// First check the case of one domain to rule them all.
if ((size() == 1) && (wildcard_domain_)) {
domain = wildcard_domain_;
return (true);
}
// Start with the longest version of the fqdn and search the list.
// Continue looking for shorter versions of fqdn so long as no match is
// found.
// @todo This can surely be optimized, time permitting.
std::string match_name = fqdn;
std::size_t start_pos = 0;
while (start_pos != std::string::npos) {
match_name = match_name.substr(start_pos, std::string::npos);
DdnsDomainMap::iterator gotit = domains_->find(match_name);
if (gotit != domains_->end()) {
domain = gotit->second;
return (true);
// Iterate over the domain map looking for the domain which matches
// the longest portion of the given fqdn.
size_t req_len = fqdn.size();
size_t match_len = 0;
DdnsDomainMapPair map_pair;
DdnsDomainPtr best_match;
BOOST_FOREACH (map_pair, *domains_) {
std::string domain_name = map_pair.first;
size_t dom_len = domain_name.size();
// If the domain name is longer than the fqdn, then it cant be match.
if (req_len < dom_len) {
continue;
}
start_pos = match_name.find_first_of(".");
if (start_pos != std::string::npos) {
++start_pos;
// If the lengths are identical and the names match we're done.
if (req_len == dom_len) {
if (fqdn == domain_name) {
// exact match, done
domain = map_pair.second;
return (true);
}
} else {
// The fqdn is longer than the domain name. Adjust the start
// point of comparison by the excess in length. Only do the
// comparison if the adjustment lands on a boundary. This
// prevents "onetwo.net" from matching "two.net".
size_t offset = req_len - dom_len;
if ((fqdn[offset - 1] == '.') &&
(fqdn.compare(offset, std::string::npos, domain_name) == 0)) {
// Fqdn contains domain name, keep it if its better than
// any we have matched so far.
if (dom_len > match_len) {
match_len = dom_len;
best_match = map_pair.second;
}
}
}
}
// There's no match. If they specified a wild card domain use it
// otherwise there's no domain for this entry.
if (wildcard_domain_) {
domain = wildcard_domain_;
return (true);
if (!best_match) {
// There's no match. If they specified a wild card domain use it
// otherwise there's no domain for this entry.
if (wildcard_domain_) {
domain = wildcard_domain_;
return (true);
}
LOG_WARN(dctl_logger, DHCP_DDNS_NO_MATCH).arg(fqdn);
return (false);
}
LOG_WARN(dctl_logger, DHCP_DDNS_NO_MATCH).arg(fqdn);
return (false);
domain = best_match;
return (true);
}
// *************************** PARSERS ***********************************
......
......@@ -321,8 +321,8 @@ typedef boost::shared_ptr<DnsServerInfoStorage> DnsServerInfoStoragePtr;
/// it. It's primary use is to map a domain to the DNS server(s) responsible
/// for it.
/// @todo Currently the name entry for a domain is just an std::string. It
/// may be worthwhile to change this to a dns::Name for purposes of better
/// validation and matching capabilities.
/// may be worthwhile to change this to a dns::Name for purposes of better
/// validation and matching capabilities.
class DdnsDomain {
public:
/// @brief Constructor
......@@ -385,7 +385,11 @@ typedef boost::shared_ptr<DdnsDomainMap> DdnsDomainMapPtr;
/// services. These services are used to match a FQDN to a domain. Currently
/// it supports a single matching service, which will return the matching
/// domain or a wild card domain if one is specified. The wild card domain is
/// specified as a domain whose name is "*".
/// specified as a domain whose name is "*". The wild card domain will match
/// any entry and is provided for flexibility in FQDNs If for instance, all
/// forward requests are handled by the same servers, the configuration could
/// specify the wild card domain as the only forward domain. All forward DNS
/// updates would be sent to that one list of servers, regardless of the FQDN.
/// As matching capabilities evolve this class is expected to expand.
class DdnsDomainListMgr {
public:
......@@ -410,8 +414,8 @@ public:
/// it will be returned immediately for any FQDN.
///
/// @param fqdn is the name for which to look.
/// @param domain receives the matching domain. Note that it will be reset
/// upon entry and only set if a match is subsequently found.
/// @param domain receives the matching domain. If no match is found its
/// contents will be unchanged.
///
/// @return returns true if a match is found, false otherwise.
/// @todo This is a very basic match method, which expects valid FQDNs
......
......@@ -112,6 +112,10 @@ service first starts.
This is an informational message issued when the controller is exiting
following a shut down (normal or otherwise) of the service.
% DHCP_DDNS_AT_MAX_TRANSACTIONS application has %1 queued requests but has reached maximum number of %2 concurrent transactions
This is a debug message that indicates that the application has DHCP_DDNS
requests in the queue but is working as many concurrent requests as allowed.
% DHCP_DDNS_COMMAND command directive received, command: %1 - args: %2
This is a debug message issued when the Dhcp-Ddns application command method
has been invoked.
......@@ -129,16 +133,35 @@ This is a debug message issued when the DHCP-DDNS application encountered an
error while decoding a response to DNS Update message. Typically, this error
will be encountered when a response message is malformed.
% DHCP_DDNS_NO_MATCH No DNS servers match FQDN: %1
% DHCP_DDNS_NO_ELIGIBLE_JOBS although there are queued requests, there are pending transactions for each Queue count: %1 Transaction count: %2
This is a debug messge issued when all of the queued requests represent clients
for which there is a an update already in progress. This may occur under
normal operations but should be temporary situation.
% DHCP_DDNS_NO_FWD_MATCH_ERROR the configured list of forward DDNS domains does not contain a match for FQDN %1 The request has been discarded.
This is an error message that indicates that DHCP_DDNS received a request to
update a the forward DNS information for the given FQDN but for which there are
no configured DDNS domains in the DHCP_DDNS configuration. Either the DHCP_DDNS
configuration needs to be updated or the source of the FQDN itself should be
investigated.
% DHCP_DDNS_NO_MATCH No DNS servers match FQDN %1
This is warning message issued when there are no domains in the configuration
which match the cited fully qualified domain name (FQDN). The DNS Update
request for the FQDN cannot be processed.
% DHCP_DDNS_NO_REV_MATCH_ERROR the configured list of reverse DDNS domains does not contain a match for FQDN %1 The request has been discarded.
This is an error message that indicates that DHCP_DDNS received a request to
update a the reverse DNS information for the given FQDN but for which there are
no configured DDNS domains in the DHCP_DDNS configuration. Either the DHCP_DDNS
configuration needs to be updated or the source of the FQDN itself should be
investigated.
% DHCP_DDNS_PROCESS_INIT application init invoked
This is a debug message issued when the Dhcp-Ddns application enters
its init method.
% DHCP_DDNS_QUEUE_MGR_QUEUE_FULL application request queue has reached maximum number of entries: %1
% DHCP_DDNS_QUEUE_MGR_QUEUE_FULL application request queue has reached maximum number of entries %1
This an error message indicating that DHCP-DDNS is receiving DNS update
requests faster than they can be processed. This may mean the maximum queue
needs to be increased, the DHCP-DDNS clients are simply generating too many
......
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <d2/d2_update_mgr.h>
#include <sstream>
#include <iostream>
#include <vector>
namespace isc {
namespace d2 {
const size_t D2UpdateMgr::MAX_TRANSACTIONS_DEFAULT;
D2UpdateMgr::D2UpdateMgr(D2QueueMgrPtr& queue_mgr, D2CfgMgrPtr& cfg_mgr,
isc::asiolink::IOService& io_service,
const size_t max_transactions)
:queue_mgr_(queue_mgr), cfg_mgr_(cfg_mgr), io_service_(io_service) {
if (!queue_mgr_) {
isc_throw(D2UpdateMgrError, "D2UpdateMgr queue manager cannot be null");
}
if (!cfg_mgr_) {
isc_throw(D2UpdateMgrError,
"D2UpdateMgr configuration manager cannot be null");
}
// Use setter to do validation.
setMaxTransactions(max_transactions);
}
D2UpdateMgr::~D2UpdateMgr() {
transaction_list_.clear();
}
void D2UpdateMgr::sweep() {
// cleanup finished transactions;
checkFinishedTransactions();
// if the queue isn't empty, find the next suitable job and
// start a transaction for it.
// @todo - Do we want to queue max transactions? The logic here will only
// start one new transaction per invocation. On the other hand a busy
// system will generate many IO events and this method will be called
// frequently. It will likely achieve max transactions quickly on its own.
if (getQueueCount() > 0) {
if (getTransactionCount() >= max_transactions_) {
LOG_DEBUG(dctl_logger, DBGLVL_TRACE_DETAIL_DATA,
DHCP_DDNS_AT_MAX_TRANSACTIONS).arg(getQueueCount())
.arg(getMaxTransactions());
return;
}
// We are not at maximum transactions, so pick and start the next job.
pickNextJob();
}
}
void
D2UpdateMgr::checkFinishedTransactions() {
// Cycle through transaction list and do whatever needs to be done
// for finished transactions.
// At the moment all we do is remove them from the list. This is likely
// to expand as DHCP_DDNS matures.
TransactionList::iterator it = transaction_list_.begin();
while (it != transaction_list_.end()) {
NameChangeTransactionPtr trans = (*it).second;
switch (trans->getNcrStatus()) {
case dhcp_ddns::ST_COMPLETED:
transaction_list_.erase(it);
break;
case dhcp_ddns::ST_FAILED:
transaction_list_.erase(it);
break;
default:
break;
}
++it;
}
}
void D2UpdateMgr::pickNextJob() {
// Start at the front of the queue, looking for the first entry for
// which no transaction is in progress. If we find an eligible entry
// remove it from the queue and make a transaction for it.
// Requests and transactions are associated by DHCID. If a request has
// the same DHCID as a transaction, they are presumed to be for the same
// "end user".
size_t queue_count = getQueueCount();
for (size_t index = 0; index < queue_count; ++index) {
dhcp_ddns::NameChangeRequestPtr found_ncr = queue_mgr_->peekAt(index);
if (!hasTransaction(found_ncr->getDhcid())) {
queue_mgr_->dequeueAt(index);
makeTransaction(found_ncr);
return;
}
}
// There were no eligible jobs. All of the current DHCIDs already have
// transactions pending.
LOG_DEBUG(dctl_logger, DBGLVL_TRACE_DETAIL_DATA, DHCP_DDNS_NO_ELIGIBLE_JOBS)
.arg(getQueueCount()).arg(getTransactionCount());
}
void
D2UpdateMgr::makeTransaction(dhcp_ddns::NameChangeRequestPtr& next_ncr) {
// First lets ensure there is not a transaction in progress for this
// DHCID. (pickNextJob should ensure this, as it is the only real caller
// but for safety's sake we'll check).
const TransactionKey& key = next_ncr->getDhcid();
if (findTransaction(key) != transactionListEnd()) {
// This is programmatic error. Caller(s) should be checking this.
isc_throw(D2UpdateMgrError, "Transaction already in progress for: "
<< key.toStr());
}
// If forward change is enabled, match to forward servers.
DdnsDomainPtr forward_domain;
if (next_ncr->isForwardChange()) {
bool matched = cfg_mgr_->matchForward(next_ncr->getFqdn(),
forward_domain);
// Could not find a match for forward DNS server. Log it and get out.
// This has the net affect of dropping the request on the floor.
if (!matched) {
LOG_ERROR(dctl_logger, DHCP_DDNS_NO_FWD_MATCH_ERROR)
.arg(next_ncr->getFqdn());
return;
}
}
// If reverse change is enabled, match to reverse servers.
DdnsDomainPtr reverse_domain;
if (next_ncr->isReverseChange()) {
bool matched = cfg_mgr_->matchReverse(next_ncr->getIpAddress(),
reverse_domain);
// Could not find a match for reverse DNS server. Log it and get out.
// This has the net affect of dropping the request on the floor.
if (!matched) {
LOG_ERROR(dctl_logger, DHCP_DDNS_NO_REV_MATCH_ERROR)
.arg(next_ncr->getIpAddress());
return;
}
}
// We matched to the required servers, so construct the transaction.
NameChangeTransactionPtr trans(new NameChangeTransaction(io_service_,
next_ncr,
forward_domain,
reverse_domain));
// Add the new transaction to the list.
transaction_list_[key] = trans;
}
TransactionList::iterator
D2UpdateMgr::findTransaction(const TransactionKey& key) {
return (transaction_list_.find(key));
}
bool
D2UpdateMgr::hasTransaction(const TransactionKey& key) {
return (findTransaction(key) != transactionListEnd());
}
void
D2UpdateMgr::removeTransaction(const TransactionKey& key) {
TransactionList::iterator pos = findTransaction(key);
if (pos != transactionListEnd()) {
transaction_list_.erase(pos);
}
}
TransactionList::iterator
D2UpdateMgr::transactionListEnd() {
return (transaction_list_.end());
}
void
D2UpdateMgr::clearTransactionList() {
// @todo for now this just wipes them out. We might need something
// more elegant, that allows a cancel first.
transaction_list_.clear();
}
void
D2UpdateMgr::setMaxTransactions(const size_t new_trans_max) {
// Obviously we need at room for at least one transaction.
if (new_trans_max < 1) {
isc_throw(D2UpdateMgrError, "D2UpdateMgr"
" maximum transactions limit must be greater than zero");
}
// Do not allow the list maximum to be set to less then current list size.
if (new_trans_max < getTransactionCount()) {
isc_throw(D2UpdateMgrError, "D2UpdateMgr maximum transaction limit "
"cannot be less than the current transaction count :"
<< getTransactionCount());
}
max_transactions_ = new_trans_max;
}
size_t
D2UpdateMgr::getQueueCount() const {
return (queue_mgr_->getQueueSize());
}
size_t