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

[1198] Checkpoint after updating internal documentation

parent 1bad76a6
......@@ -392,8 +392,7 @@ DatabaseClient::Finder::findNSECCover(const Name& name) {
DatabaseClient::Finder::DelegationSearchResult
DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
const FindOptions options)
{
const FindOptions options) {
// Result of search
isc::dns::ConstRRsetPtr result_rrset;
ZoneFinder::Result result_status = SUCCESS;
......@@ -405,53 +404,60 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
// Are we searching for glue?
const bool glue_ok((options & FIND_GLUE_OK) != 0);
// First, do we have any kind of delegation (NS/DNAME) here?
const Name origin(getOrigin());
const size_t origin_label_count(origin.getLabelCount());
// Number of labels in the last known non-empty domain
size_t last_known(origin_label_count);
const size_t current_label_count(name.getLabelCount());
// We want to search from the apex down. We are given the full domain
// name so we have to do some manipulation to ensure that when we start
// checking superdomains, we start from the right label:
//
// Set the number of labels in the origin (i.e. apex of the zone) and in
// the last known non-empty domain (which, at this point, is the origin).
const size_t origin_label_count = getOrigin().getLabelCount();
size_t last_known = origin_label_count;
// This is how many labels we remove to get origin
const size_t remove_labels(current_label_count - origin_label_count);
// Set how many labels we remove to get origin: this is the number of
// labels we have to process in our search.
const size_t remove_labels = name.getLabelCount() - origin_label_count;
// Go through all superdomains from the origin down searching for nodes
// that indicate a delegation (NS or DNAME).
for (int i = remove_labels; i > 0; --i) {
const Name superdomain(name.split(i));
// Note if this is the origin.
// Note if this is the origin. (We don't count NS records at the origin
// as a delegation so this controls whether NS RRs are included in
// the results of some searches.)
const bool not_origin = (i != remove_labels);
// Look if there's NS or DNAME (but ignore the NS in origin)
// Look if there's NS or DNAME at this point of the tree, but ignore the
// NS RRs at the apex of the zone.
const FoundRRsets found = getRRsets(superdomain.toText(),
DELEGATION_TYPES(), not_origin);
if (found.first) {
// It contains some RRs, so it exists.
// This node contains either NS or DNAME RRs so it does exist.
last_known = superdomain.getLabelCount();
const FoundIterator nsi(found.second.find(RRType::NS()));
const FoundIterator dni(found.second.find(RRType::DNAME()));
// In case we are in GLUE_OK mode, we want to store the
// highest encountered NS (but not apex)
if (glue_ok && !first_ns && not_origin && nsi != found.second.end()) {
// TODO: WHY?
if (glue_ok && !first_ns && not_origin &&
nsi != found.second.end()) {
first_ns = nsi->second;
} else if (!glue_ok && not_origin && nsi != found.second.end()) {
// Do a NS delegation, but ignore NS in glue_ok mode. Ignore
// delegation in apex
// Not in glue OK mode and we have found an NS RRset that is
// not at the apex. We have a delegation so return that fact.
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_FOUND_DELEGATION).
arg(accessor_->getDBName()).arg(superdomain);
result_rrset = nsi->second;
result_status = DELEGATION;
// No need to go lower, found
// No need to go further down the tree.
break;
} else if (dni != found.second.end()) {
// Very similar with DNAME
// We have found a DNAME so again return the fact.
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_FOUND_DNAME).
arg(accessor_->getDBName()).arg(superdomain);
......@@ -462,6 +468,8 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
" has " << result_rrset->getRdataCount() <<
" rdata, 1 expected");
}
// No need to go further down the tree.
break;
}
}
......@@ -475,14 +483,17 @@ DatabaseClient::Finder::findWildcardMatch(
const isc::dns::Name& name, const isc::dns::RRType& type,
const FindOptions options, const DelegationSearchResult& dresult)
{
// Result of search
// Result of search (status initialized to assume we don't find any
// matching RRsets).
isc::dns::ConstRRsetPtr result_rrset;
ZoneFinder::Result result_status = NXDOMAIN; // in case we don't find any
ZoneFinder::Result result_status = NXDOMAIN;
// Search options
const bool dnssec_data((options & FIND_DNSSEC) != 0);
// Other
// Note that during the search we are going to search not only for the
// requested type, but also for types that indicate a delegation -
// NS and DNAME.
WantedTypes final_types(FINAL_TYPES());
final_types.insert(type);
......@@ -583,33 +594,40 @@ DatabaseClient::Finder::findNoNameResult(const Name& name, const RRType& type,
FindOptions options,
const DelegationSearchResult& dresult)
{
const bool dnssec_data((options & FIND_DNSSEC) != 0);
const bool dnssec_data = ((options & FIND_DNSSEC) != 0);
// On entry to this method, we know that the database doesn't have any
// entry for this name. Before returning NXDOMAIN, we need to check
// for special cases.
// We know the database doesn't have any record for the given name.
// But check if something lives below this domain and if so,
// pretend something is here as well.
if (hasSubdomains(name.toText())) {
// Does the domain have a subdomain (i.e. is is an empty non-terminal)?
// If so, return NXRRSET instead of NXDOMAIN (as although the name does
// not exist in the zone, it does exist in the DNS tree).
// pretend something is here as well.
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_FOUND_EMPTY_NONTERMINAL).
arg(accessor_->getDBName()).arg(name);
return (FindResult(NXRRSET, dnssec_data ? findNSECCover(name) :
ConstRRsetPtr()));
} else if ((options & NO_WILDCARD) != 0) {
// If wildcard check is disabled, the search should terminate
// with NXDOMAIN.
return (FindResult(NXDOMAIN, dnssec_data ? findNSECCover(name) :
ConstRRsetPtr()));
} else {
// It's not an empty non-terminal so check for wildcards.
} else if ((options & NO_WILDCARD) == 0) {
// It's not an empty non-terminal and wildcard matching is not disabled,
// so check for wildcards.
const ZoneFinder::FindResult wresult =
findWildcardMatch(name, type, options, dresult);
if (wresult.code == NXDOMAIN && dnssec_data) {
// If the result is NXDOMAIN case and the caller wanted
// DNSSEC data, try getting the NSEC record.
// No match on a wildcard, so return the covering NSEC if DNSSEC
// data was requested.
return (FindResult(NXDOMAIN, findNSECCover(name)));
}
return (FindResult(wresult.code, wresult.rrset));
}
// All avenues to find a match are now exhausted, return NXDOMAIN (plus
// NSEC records if requested).
return (FindResult(NXDOMAIN, dnssec_data ? findNSECCover(name) :
ConstRRsetPtr()));
}
ZoneFinder::FindResult
......@@ -621,8 +639,8 @@ DatabaseClient::Finder::logAndCreateResult(const Name& name,
{
if (rrset) {
LOG_DEBUG(logger, DBG_TRACE_DETAILED, log_id).
arg(accessor_->getDBName()).arg(name).arg(getClass()).
arg(type).arg(*rrset);
arg(accessor_->getDBName()).arg(name).arg(type).arg(getClass()).
arg(*rrset);
} else {
LOG_DEBUG(logger, DBG_TRACE_DETAILED, log_id).
arg(accessor_->getDBName()).arg(name).arg(type).arg(getClass());
......@@ -634,61 +652,98 @@ ZoneFinder::FindResult
DatabaseClient::Finder::find(const isc::dns::Name& name,
const isc::dns::RRType& type,
isc::dns::RRsetList*,
const FindOptions options)
{
const FindOptions options) {
LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_DATABASE_FIND_RECORDS)
.arg(accessor_->getDBName()).arg(name).arg(type);
// First stage: go through all superdomains from the origin down,
// searching for nodes that indicate a delegation (NS or DNAME).
// First, go through all superdomains from the origin down, searching for
// nodes that indicate a delegation (i.e. NS or DNAME, ignoring NS records
// at the apex). If one is found, the search stops there.
//
// (In fact there could be RRs in the database corresponding to subdomains
// of the delegation. However as no search will find them, they are said
// to be occluded by the presence of the delegation.)
const DelegationSearchResult dresult = findDelegationPoint(name, options);
if (dresult.rrset) {
return (FindResult(dresult.code, dresult.rrset));
}
// Try getting the final result and extract it
// It is special if there's a CNAME or NS, DNAME is ignored here
// And we don't consider the NS in origin
// If there is no delegation in the page, look for the exact match to the
// request name/type/class. However, there are special cases:
// - Requested name has a singleton CNAME record associated with it
// - Requested name is a delegation point (NS only but not at the zone
// apex - DNAME is ignored here).
// TODO: Why is DNAME ignored?
const bool is_origin = (name == getOrigin());
WantedTypes final_types(FINAL_TYPES());
final_types.insert(type);
const FoundRRsets found(getRRsets(name.toText(), final_types, !is_origin));
const FoundRRsets found = getRRsets(name.toText(), final_types, !is_origin);
// NS records, CNAME record and Wanted Type records
// Get iterators for the different types of records we are interested in -
// CNAME, NS and Wanted types.
const FoundIterator nsi(found.second.find(RRType::NS()));
const FoundIterator cni(found.second.find(RRType::CNAME()));
const FoundIterator wti(found.second.find(type));
if (!is_origin && (options & FIND_GLUE_OK) == 0 &&
nsi != found.second.end()) { // delegation at the exact node
if (!is_origin && ((options & FIND_GLUE_OK) == 0) &&
nsi != found.second.end()) {
// A NS RRset was found at the domain we were searching for. As
// it is not at the origin of the zone, it is a delegation and
// indicates that this this zone is not authoritative for the data.
// Just return the delegation information.
return (logAndCreateResult(name, type, DELEGATION, nsi->second,
DATASRC_DATABASE_FOUND_DELEGATION_EXACT));
} else if (type != RRType::CNAME() && cni != found.second.end()) { // CNAME
} else if (type != RRType::CNAME() && cni != found.second.end()) {
// We are not searching for a CNAME but nevertheless we have found one
// at the name we are searching so we return it. (A resolver could have
// originated the query that caues this result. If so, it will restart
// the resolution process with the name that is the target of this
// CNAME.) First though, do a sanity check to ensure that there is
// only one RR in the CNAME RRset.
//
// TODO: Check that throwing an exception here is correct.
// Unless the exception is caught higher up (probably not, given the
// general nature of the exception), it is probably better to log
// and error and terminate the query with SERVFAIL instead of crashing
// the server. Although the CNAME is a singleton and multiple RRs
// in the RRset may indicate an error in the data, it does not mean
// that the entire database is corrupt.
if (cni->second->getRdataCount() != 1) {
isc_throw(DataSourceError, "CNAME with " <<
cni->second->getRdataCount() <<
" rdata at " << name << ", expected 1");
cni->second->getRdataCount() << " rdata at " << name <<
", expected 1");
}
return (logAndCreateResult(name, type, CNAME, cni->second,
DATASRC_DATABASE_FOUND_CNAME));
} else if (wti != found.second.end()) { // normal answer
} else if (wti != found.second.end()) {
// Found an RR matching the query, so return it. (Note that this
// includes the case where we were querying for a CNAME and found
// it. It also includes the case where we were querying for an NS
// RRset and found it at the apex of the zone.)
return (logAndCreateResult(name, type, SUCCESS, wti->second,
DATASRC_DATABASE_FOUND_RRSET));
} else if (!found.first) { // NXDOMAIN, empty name, wildcard
} else if (!found.first) {
// Did not find anything at all at the domain name, so check for
// subdomains or wildcards.
return (findNoNameResult(name, type, options, dresult));
} else {
// This is the "usual" NXRRSET case. So in case they want DNSSEC,
// provide the NSEC (which should be available already here)
if ((options & FIND_DNSSEC) != 0) {
const FoundIterator nci(found.second.find(RRType::NSEC()));
if (nci != found.second.end()) {
return (logAndCreateResult(name, type, NXRRSET, nci->second,
DATASRC_DATABASE_FOUND_NXRRSET_NSEC));
}
}
// If we get here, we have found something at the requested name but not
// one of the RR types we were interested in. This is the NXRRSET case so,
// if DNSSEC information was requested, provide the NSEC records.
if ((options & FIND_DNSSEC) != 0) {
const FoundIterator nci = found.second.find(RRType::NSEC());
if (nci != found.second.end()) {
return (logAndCreateResult(name, type, NXRRSET, nci->second,
DATASRC_DATABASE_FOUND_NXRRSET_NSEC));
}
return (logAndCreateResult(name, type, NXRRSET, ConstRRsetPtr(),
DATASRC_DATABASE_FOUND_NXRRSET));
}
return (logAndCreateResult(name, type, NXRRSET, ConstRRsetPtr(),
DATASRC_DATABASE_FOUND_NXRRSET));
}
Name
......
......@@ -817,6 +817,17 @@ public:
return (*accessor_);
}
private:
boost::shared_ptr<DatabaseAccessor> accessor_;
const int zone_id_;
const isc::dns::Name origin_;
//
/// \brief Shortcut name for the result of getRRsets
typedef std::pair<bool, std::map<dns::RRType, dns::RRsetPtr> >
FoundRRsets;
/// \brief Just shortcut for set of types
typedef std::set<dns::RRType> WantedTypes;
/// \brief Search result of \c findDelegationPoint().
///
/// This is a tuple combining the result of the search - a status code
......@@ -850,17 +861,6 @@ public:
const size_t last_known; ///< No. labels in last non-empty domain
};
private:
boost::shared_ptr<DatabaseAccessor> accessor_;
const int zone_id_;
const isc::dns::Name origin_;
//
/// \brief Shortcut name for the result of getRRsets
typedef std::pair<bool, std::map<dns::RRType, dns::RRsetPtr> >
FoundRRsets;
/// \brief Just shortcut for set of types
typedef std::set<dns::RRType> WantedTypes;
/**
* \brief Searches database for RRsets of one domain.
*
......@@ -892,112 +892,151 @@ public:
const WantedTypes& types, bool check_ns,
const std::string* construct_name = NULL);
/**
* \brief Find delegation point
*
* Given a name, searches through the superdomains from the origin
* down, searching for a point that indicates a delegation (i.e. an
* NS record or a DNAME).
*
* The method operates in two modes, non-glue-ok and glue-ok modes:
*
* In non-glue-ok mode, the search is made purely for the NS or DNAME
* RR. The zone is searched from the origin down looking for one
* of these RRTypes (and ignoring the NS records at the zone origin).
* A status is returned indicating what is found: DNAME, DELEGATION
* of SUCCESS, the last indicating that nothing was found, together
* with a pointer to the relevant RR.
*
* In glue-ok mode, the first NS encountered in the search (apart from
* the NS at the zone apex) is remembered but otherwise NS records are
* ignored and the search attempts to find a DNAME. The result is
* returned in the same format, along with a pointer to the first non-
* apex NS (if found).
*
* \param name The name to find
* \param options Options about how to search. See the documentation for
* ZoneFinder::FindOptions.
*
* \return Tuple holding the result of the search - the RRset of the
* delegation point and the type of the point (DELEGATION or
* DNAME) - and associated information. This latter item
* comprises two pieces of data: a pointer to the highest
* encountered NS, and the number of labels in the last known
* non-empty domain. The associated information is found as
* a natural part of the search for the delegation point and
* is used later in the find() processing; it is passed back
* to avoid the need to perform a second search to obtain it.
*/
/// \brief Find delegation point
///
/// Given a name, searches through the superdomains from the origin
/// down, searching for a point that indicates a delegation (i.e. an
/// NS record or a DNAME).
///
/// The method operates in two modes, non-glue-ok and glue-ok modes:
///
/// In non-glue-ok mode, the search is made purely for the NS or DNAME
/// RR. The zone is searched from the origin down looking for one
/// of these RRTypes (and ignoring the NS records at the zone origin).
/// A status is returned indicating what is found: DNAME, DELEGATION
/// of SUCCESS, the last indicating that nothing was found, together
/// with a pointer to the relevant RR.
///
/// In glue-ok mode, the first NS encountered in the search (apart from
/// the NS at the zone apex) is remembered but otherwise NS records are
/// ignored and the search attempts to find a DNAME. The result is
/// returned in the same format, along with a pointer to the first non-
/// apex NS (if found).
///
/// \param name The name to find
/// \param options Options about how to search. See the documentation
/// for ZoneFinder::FindOptions.
///
/// \return Tuple holding the result of the search - the RRset of the
/// delegation point and the type of the point (DELEGATION or
/// DNAME) - and associated information. This latter item
/// comprises two pieces of data: a pointer to the highest
/// encountered NS, and the number of labels in the last known
/// non-empty domain. The associated information is found as
/// a natural part of the search for the delegation point and
/// is used later in the find() processing; it is passed back
/// to avoid the need to perform a second search to obtain it.
DelegationSearchResult
findDelegationPoint(const isc::dns::Name& name,
const FindOptions options);
/**
* \brief Find wildcard match
*
* Having found that the name is not an empty non-terminal, this
* searches the zone for for wildcards that match the name.
*
* It searches superdomains of the name from the zone origin down
* looking for a wildcard in the zone that matches the name. There
* are several cases to consider:
*
* - If the previous search for a delegation point has found that
* there is an NS at the superdomain of the point at which the
* wildcard is found, the delegation is returned.
* - If there is a match to the name, an appropriate status is
* returned (match on requested type, delegation, cname, or just
* the indication of a match but no RRs relevant to the query).
* - If the match is to an non-empty non-terminal wildcard, a
* wildcard NXRRSET is returned.
*
* Note that if DNSSEC is enabled for the search and the zone uses
* NSEC for authenticated denial of existence, the search may
* return NSEC records.
*
* \param name The name to find
* \param type The RRType to find
* \param options Options about how to search. See the documentation
* for ZoneFinder::FindOptions.
* \param first_ns A pointer to the first NS found in a search for
* the name (will only be non-null in glue-ok mode).
* \param last_known the number of labels in the last known non-empty
* domain in the name.
*
* \return Tuple holding the result of the search - the RRset of the
* wildcard records matching the name, together with a status
* indicating the match type (e.g. CNAME at the wildcard
* match, no RRs of the requested type at the wildcard,
* success due to an exact match). Also returned if there
* is no match is an indication as to whether there was an
* NXDOMAIN or an NXRRSET.
*/
/// \brief Find wildcard match
///
/// Having found that the name is not an empty non-terminal, this
/// searches the zone for for wildcards that match the name.
///
/// It searches superdomains of the name from the zone origin down
/// looking for a wildcard in the zone that matches the name. There
/// are several cases to consider:
///
/// - If the previous search for a delegation point has found that
/// there is an NS at the superdomain of the point at which the
/// wildcard is found, the delegation is returned.
/// - If there is a match to the name, an appropriate status is
/// returned (match on requested type, delegation, cname, or just
/// the indication of a match but no RRs relevant to the query).
/// - If the match is to an non-empty non-terminal wildcard, a
/// wildcard NXRRSET is returned.
///
/// Note that if DNSSEC is enabled for the search and the zone uses
/// NSEC for authenticated denial of existence, the search may
/// return NSEC records.
///
/// \param name The name to find
/// \param type The RRType to find
/// \param options Options about how to search. See the documentation
/// for ZoneFinder::FindOptions.
/// \param dresult Result of the search through the zone for a
/// delegation.
///
/// \return Tuple holding the result of the search - the RRset of the
/// wildcard records matching the name, together with a status
/// indicating the match type (e.g. CNAME at the wildcard
/// match, no RRs of the requested type at the wildcard,
/// success due to an exact match). Also returned if there
/// is no match is an indication as to whether there was an
/// NXDOMAIN or an NXRRSET.
FindResult findWildcardMatch(
const isc::dns::Name& name,
const isc::dns::RRType& type, const FindOptions options,
const DelegationSearchResult& dresult);
/// To be documented.
/// \brief Handle no match for name
///
/// This is called when it is known that there is no delegation and
/// there is no exact match for the name (regardless of RR types
/// requested). Before returning NXDOMAIN, we need to check two
/// cases:
/// - Empty non-terminal: if the name has subdomains in the database,
/// flag the fact. An NXRRSET will be returned (along with the
/// NSEC record covering the requested domain name if DNSSEC data
/// is being returned).
/// - Wildcard: is there a wildcard record in the zone that matches
/// requested name? If so, return it. If not, return the relevant
/// NSEC records (if requested).
///
/// \param name The name to find
/// \param type The RRType to find
/// \param options Options about how to search. See the documentation
/// for ZoneFinder::FindOptions.
/// \param dresult Result of the search through the zone for a
/// delegation.
///
/// \return Tuple holding the result of the search - the RRset of the
/// wildcard records matching the name, together with a status
/// indicating the match type (e.g. CNAME at the wildcard
/// match, no RRs of the requested type at the wildcard,
/// success due to an exact match). Also returned if there
/// is no match is an indication as to whether there was an
/// NXDOMAIN or an NXRRSET.
FindResult findNoNameResult(const isc::dns::Name& name,
const isc::dns::RRType& type,
FindOptions options,
const DelegationSearchResult& dresult);
// To be documented.
/// Logs condition and creates result
///
/// A convenience function used by find(), it both creates the
/// FindResult object that find() will return to its caller as well
/// as logging a debug message for the information being returned.
///
/// \param name Domain name of the RR that was being sought.
/// \param type Type of RR being sought.
/// \param code Result of the find operation
/// \param rrset RRset found as a result of the find (which may be
/// null).
/// \param log_id ID of the message being logged. Up to five
/// parameters are available to the message: data source name,
/// requested domain name, requested class, requested type
/// and (but only if the search was successful and returned
/// an RRset) details of the RRset found.
///
/// \return FindResult object constructed from the code and rrset
/// arguments.
FindResult logAndCreateResult(const isc::dns::Name& name,
const isc::dns::RRType& type,
ZoneFinder::Result code,
isc::dns::ConstRRsetPtr rrset,
const isc::log::MessageID& log_id);
/**
* \brief Checks if something lives below this domain.
*
* This looks if there's any subdomain of the given name. It can be
* used to test if domain is empty non-terminal.
*
* \param name The domain to check.
*/
/// \brief Checks if something lives below this domain.
///
/// This looks if there's any subdomain of the given name. It can be
/// used to test if domain is empty non-terminal.
///
/// \param name The domain to check.
///
/// \return true if the name has subdomains, false if not.
bool hasSubdomains(const std::string& name);
/**
......
......@@ -79,7 +79,11 @@ an error, so we set it to the lowest value we found (but we don't modify the
database). The data in database should be checked and fixed.
% DATASRC_DATABASE_FOUND_CNAME search in datasource %1 for %2/%3/%4 resulted in CNAME %5
(TBD)
When searching the domain for a name a CNAME was found at that name. Even
though it was not the RR type being sought, it is returned. If the query
of the database was issued by a result searching for the name, the return of
the CNAME record will cause that resolver to issue another query for the
target of the CNAME.
% DATASRC_DATABASE_FOUND_DELEGATION Found delegation at %2 in %1
When searching for a domain, the program met a delegation to a different zone
......@@ -96,9 +100,10 @@ place in the domain space at the given domain name. It will return that one
instead.
% DATASRC_DATABASE_FOUND_EMPTY_NONTERMINAL empty non-terminal %2 in %1
The domain name doesn't have any RRs, so it doesn't exist in the database.
However, it has a subdomain, so it exists in the DNS address space. So we
return NXRRSET instead of NXDOMAIN.
The domain name does not have any RRs associated with it, so it doesn't
exist in the database. However, it has a subdomain, so it does exist
in the DNS address space. This type of domain is known an an "empty
non-terminal" and so we return NXRRSET instead of NXDOMAIN.
% DATASRC_DATABASE_FOUND_NXDOMAIN search in datasource %1 resulted in NXDOMAIN for %2/%3/%4
The data returned by the database backend did not contain any data for the given
......@@ -109,7 +114,9 @@ The data returned by the database backend contained data for the given domain
name and class, but not for the given type.
% DATASRC_DATABASE_FOUND_NXRRSET_NSEC search in datasource %1 for %2/%3/%4 resulted in RRset %5
(TBD)
A search in the database for RRs for the specified name, type and class has
located RRs that match the name and class but not the type. DNSSEC information
has been requested, but there is no NSEC record corresponding to the node.
% DATASRC_DATABASE_FOUND_RRSET search in datasource %1 resulted in RRset %2
The data returned by the database backend contained data for the given domain
......@@ -300,7 +307,7 @@ Debug information. The requested record was found.
% DATASRC_MEM_SUPER_STOP stopped at superdomain '%1', domain '%2' is empty
Debug information. The search stopped at a superdomain of the requested
domain.