Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6078fad8ae | ||
|
|
c89fe7adb9 | ||
|
|
7c2eb9531a | ||
|
|
8a57e01c4c | ||
|
|
c604cf69d9 | ||
|
|
296ec40818 | ||
|
|
605fb0f1f1 | ||
|
|
be0837df1f | ||
|
|
87d29f48d4 | ||
|
|
47e89b637b | ||
|
|
274121e771 | ||
|
|
b6d4441e46 | ||
|
|
0e39e81039 | ||
|
|
4635b065d4 | ||
|
|
e30487c2b7 | ||
|
|
cbcefd172e | ||
|
|
ecfa5dd737 | ||
|
|
0f879219c5 | ||
|
|
4f3d003828 |
@@ -1,3 +1,7 @@
|
||||
6359. [bug] Reduce memory consumption of QP zone and cache
|
||||
databases by dynamically allocating nodenames.
|
||||
[GL #4614]
|
||||
|
||||
6358. [bug] Fix validate_dnskey_dsset when KSK is not signing,
|
||||
do not skip remainder of DS RRset. [GL #4625]
|
||||
|
||||
|
||||
+2
-3
@@ -90,7 +90,6 @@
|
||||
#include <dns/order.h>
|
||||
#include <dns/peer.h>
|
||||
#include <dns/private.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/rdataclass.h>
|
||||
#include <dns/rdatalist.h>
|
||||
#include <dns/rdataset.h>
|
||||
@@ -152,11 +151,11 @@
|
||||
#endif /* HAVE_LMDB */
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX ((size_t)-1)
|
||||
#define SIZE_MAX ((size_t) - 1)
|
||||
#endif /* ifndef SIZE_MAX */
|
||||
|
||||
#ifndef SIZE_AS_PERCENT
|
||||
#define SIZE_AS_PERCENT ((size_t)-2)
|
||||
#define SIZE_AS_PERCENT ((size_t) - 2)
|
||||
#endif /* ifndef SIZE_AS_PERCENT */
|
||||
|
||||
/* RFC7828 defines timeout as 16-bit value specified in units of 100
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
#include <dns/db.h>
|
||||
#include <dns/diff.h>
|
||||
#include <dns/enumclass.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/rdatalist.h>
|
||||
#include <dns/rdatastruct.h>
|
||||
#include <dns/soa.h>
|
||||
@@ -614,7 +613,7 @@ create_db(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
|
||||
isc_mem_attach(mctx, &sampledb->common.mctx);
|
||||
dns_name_init(&sampledb->common.origin, NULL);
|
||||
|
||||
CHECK(dns_name_dupwithoffsets(origin, mctx, &sampledb->common.origin));
|
||||
dns_name_dupwithoffsets(origin, mctx, &sampledb->common.origin);
|
||||
|
||||
isc_refcount_init(&sampledb->common.references, 1);
|
||||
|
||||
|
||||
+7
-31
@@ -171,7 +171,7 @@ AC_ARG_ENABLE([developer],
|
||||
|
||||
AS_IF([test "$enable_developer" = "yes"],
|
||||
[DEVELOPER_MODE=yes
|
||||
STD_CPPFLAGS="$STD_CPPFLAGS -DISC_MEM_DEFAULTFILL=1 -DISC_MEM_TRACKLINES=1 -DISC_LIST_CHECKINIT=1 -DISC_STATS_CHECKUNDERFLOW=1 -DDNS_RBTDB_STRONG_RWLOCK_CHECK=1 -DISC_MUTEX_ERROR_CHECK=1"
|
||||
STD_CPPFLAGS="$STD_CPPFLAGS -DISC_MEM_DEFAULTFILL=1 -DISC_MEM_TRACKLINES=1 -DISC_LIST_CHECKINIT=1 -DISC_STATS_CHECKUNDERFLOW=1 -DISC_MUTEX_ERROR_CHECK=1"
|
||||
test "${enable_fixed_rrset+set}" = set || enable_fixed_rrset=yes
|
||||
test "${enable_querytrace+set}" = set || enable_querytrace=yes
|
||||
test "${with_cmocka+set}" = set || with_cmocka=yes
|
||||
@@ -1570,34 +1570,14 @@ AS_IF([test -z "$DTRACE"],
|
||||
AC_SUBST([DTRACE])
|
||||
|
||||
#
|
||||
# Which should be the default zone database, RBTDB or QPZONE?
|
||||
# [pairwise: --with-zonedb=qp, --with-zonedb=rbt]
|
||||
# The default zone database is always QPZONE now.
|
||||
#
|
||||
AC_ARG_WITH([zonedb],
|
||||
[AS_HELP_STRING([--with-zonedb=detect],[specify default zone database type (default is "qpzone")])],
|
||||
[],[with_zonedb=qp])
|
||||
zonedb="qpzone"
|
||||
AS_CASE([$with_zonedb],
|
||||
[RBT*|rbt*],[zonedb="rbt"],
|
||||
[QP|qp],[],
|
||||
[AC_MSG_ERROR([Unknown zone database type])]
|
||||
)
|
||||
AC_DEFINE_UNQUOTED([ZONEDB_DEFAULT], ["$zonedb"], [Default zone database type])
|
||||
AC_DEFINE_UNQUOTED([ZONEDB_DEFAULT], ["qpzone"], [Default zone database type])
|
||||
|
||||
#
|
||||
# Which should be the default zone database, RBTDB or QPCACHE?
|
||||
# [pairwise: --with-cachedb=qp, --with-cachedb=rbt]
|
||||
# The default cache database is always QPCACHE now.
|
||||
#
|
||||
AC_ARG_WITH([cachedb],
|
||||
[AS_HELP_STRING([--with-cachedb=detect],[specify default cache database type (default is "qpcache")])],
|
||||
[],[with_cachedb=qp])
|
||||
cachedb="qpcache"
|
||||
AS_CASE([$with_cachedb],
|
||||
[RBT*|rbt*],[cachedb="rbt"],
|
||||
[QP*|qp*],[],
|
||||
[AC_MSG_ERROR([Unknown cache database type])]
|
||||
)
|
||||
AC_DEFINE_UNQUOTED([CACHEDB_DEFAULT], ["$cachedb"], [Default cache database type])
|
||||
AC_DEFINE_UNQUOTED([CACHEDB_DEFAULT], ["qpcache"], [Default cache database type])
|
||||
|
||||
#
|
||||
# Files to configure. These are listed here because we used to
|
||||
@@ -1697,12 +1677,8 @@ report() {
|
||||
if test "yes" = "$with_jemalloc"; then
|
||||
echo " Memory allocator: jemalloc"
|
||||
fi
|
||||
if test "yes" = "$enable_full_report" -o "rbt" = "$zonedb"; then
|
||||
echo " Default zone database type: $zonedb"
|
||||
fi
|
||||
if test "yes" = "$enable_full_report" -o "rbt" = "$zonedb"; then
|
||||
echo " Default cache database type: $cachedb"
|
||||
fi
|
||||
echo " Default zone database type: $zonedb"
|
||||
echo " Default cache database type: $cachedb"
|
||||
if test "yes" = "$enable_full_report" -o "standard" = "$with_locktype"; then
|
||||
echo " Mutex lock type: $with_locktype"
|
||||
fi
|
||||
|
||||
@@ -1,260 +0,0 @@
|
||||
<!--
|
||||
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
See the COPYRIGHT file distributed with this work for additional
|
||||
information regarding copyright ownership.
|
||||
-->
|
||||
|
||||
Red-Black Tree Implementation Notes
|
||||
|
||||
OVERVIEW
|
||||
|
||||
BIND9's basic name storage mechanism is to use a modified form of
|
||||
balanced binary tree known as a red-black tree. Red-black trees
|
||||
provide for relatively efficient storage, retrieval and removal of
|
||||
data while maintaining the lexical order of all stored keys, a
|
||||
necessary function for DNS security.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
A red-black tree is a balanced binary tree named for the coloring that
|
||||
is done in the tree, identifying each node as either red or black.
|
||||
There are two simple rules for maintaining the color of nodes:
|
||||
(1) A red node has only black children.
|
||||
(2) The path from the root to any leaf node always includes the
|
||||
same number of black nodes.
|
||||
|
||||
Whenever a key is added or removed, adjustments are made to adhere to
|
||||
those two rules. These adjustments are relatively cheap to make but
|
||||
maintain the balance of the tree, thus making for efficient addition,
|
||||
lookup and deletion operations, all of which are O(log N). The color
|
||||
of a node is not relevant to external users of the tree; it is needed
|
||||
only to maintain the balance of the tree.
|
||||
|
||||
For more information on basic red-black trees, see _Introduction to
|
||||
Algorithms_, Cormen, Leiserson, and Rivest, MIT Press / McGraw Hill,
|
||||
1990, ISBN 0-262-03141-8, chapter 14.
|
||||
|
||||
In BIND9, the red-black tree implementation uses DNS names as keys,
|
||||
and can store arbitrary data with each key value. "name" and "key"
|
||||
are used interchangeably in this document.
|
||||
|
||||
The basic red-black tree algorithm is further adapted for use in BIND9
|
||||
to incorporate the notion of hierarchy, creating a tree of red-black
|
||||
trees. Where there is more than one name with a common suffix, all
|
||||
names with that suffix are stored in their own red-black tree, with a
|
||||
down pointer from the suffix locating the subtree.
|
||||
|
||||
For example, consider storing the following names:
|
||||
a x.d.e.f o.w.y.d.e.f
|
||||
b z.d.e.f p.w.y.d.e.f
|
||||
c g.h q.w.y.d.e.f
|
||||
|
||||
No matter which order the keys were added, this would result in a tree
|
||||
that can be visualized as:
|
||||
|
||||
b
|
||||
/ \
|
||||
a d.e.f
|
||||
/|\
|
||||
c | g.h
|
||||
|
|
||||
w.y
|
||||
/|\
|
||||
x | z
|
||||
|
|
||||
p
|
||||
/ \
|
||||
o q
|
||||
|
||||
This tree shows that when there is no key for a particular label, and
|
||||
when there is only one known label for its immediate subordinate, then
|
||||
multiple labels can appear in a single node, such as at d.e.f and g.h.
|
||||
It also demonstrates that there can be more nodes in the tree of trees
|
||||
than there are actual keys (which degrades the O(log N) performance
|
||||
marginally); the nodes at d.e.f and w.y do not represent keys.
|
||||
|
||||
As an aside, remember that when ordering DNS names, labels are
|
||||
examined from the right, therefore w.y sorts after x and before z.
|
||||
|
||||
A split can occur not only on a regular label boundary, but also
|
||||
between any two bits in an EDNS bitstring label. The common-suffix
|
||||
rules will be applied to keep as many bits together as possible.
|
||||
|
||||
In the current implementation of the tree of trees, a node is
|
||||
considered to "formally" exist only if it has data associated with
|
||||
it. So if the above tree then had the key d.e.f added to it, the
|
||||
operation would succeed rather than getting an "already exists"
|
||||
error.
|
||||
|
||||
Along the same lines, if a key is added with a name which is a proper
|
||||
superdomain of the name stored in an existing node, the operation will
|
||||
succeed by splitting the existing node into one node that is the key
|
||||
and another node that is the remaining parts of the name. Adding e.f
|
||||
to the above tree results in the top level red-black tree having a
|
||||
node named e.f where the current d.e.f is, and a down pointer from
|
||||
d.e.f to a "tree" of a single node named d. The down pointer from d
|
||||
would be kept to the level which has x, w.y, and z.
|
||||
|
||||
A similar split of d.e.f would occur if the name k.e.f were added.
|
||||
The top level tree would have the node e.f with a down pointer to a
|
||||
level that had both d and k, and d would continue to have its down
|
||||
pointer to the x, w.y and z level.
|
||||
|
||||
It is guaranteed when splitting that external references to the node
|
||||
that is split will remain valid --- in the previous examples, anything
|
||||
that was pointing to the node that was d.e.f will still point to the
|
||||
node that is now just d.
|
||||
|
||||
When deleting keys, nodes can be rejoined. If both of p.w.y.d.e.f and
|
||||
q.w.y.d.e.f were removed from the example tree, the node named w.y
|
||||
would become o.w.y. Unlike splitting, it is _not_ guaranteed that
|
||||
external references remain consistent; sometimes they will, sometimes
|
||||
they won't. Also, note that deletion is not perfectly symmetric with
|
||||
addition. If you "undo" the last addition with a deletion of the same
|
||||
key then the tree of trees is not guaranteed to have exactly the same
|
||||
structure as it had prior to the addition. Sometimes, but not always.
|
||||
|
||||
Rejoining does not happen if it would violate any of the rules that
|
||||
cause a split. o would not be rejoined with w.y if w.y had data
|
||||
associated with the key; o would remain as a single node on its own
|
||||
level. This emphasizes the rule that a node is considered to formally
|
||||
exist only if data is associated with it, because even if w.y.d.e.f
|
||||
had been explicitly added as a key but with no data, then o would
|
||||
still be merged with the w.y node when p and q were deleted.
|
||||
|
||||
Searching for a node generally returns one of three possible results:
|
||||
either the key is found, a superdomain (partial match) of the key is
|
||||
found, or no part of the key is found. The first and last are rather
|
||||
obvious, and the second result basically means that a hierarchically
|
||||
enclosing name is found; e.g, searching for bb.rc.vix.com turned up
|
||||
rc.vix.com, but not the full name.
|
||||
|
||||
No locking is done within the RBT library. @@@
|
||||
|
||||
CHAINS
|
||||
|
||||
@@@
|
||||
|
||||
When a partial match is made, level_matches is set while the chain
|
||||
points to the partial match node that was found. Then the chain is
|
||||
adjusted to point to the DNSSEC predecessor node, which might not even
|
||||
be under the same top level domain as the name that was searched for.
|
||||
For example, consider a database that had only the names vix.com and
|
||||
isc.org. A search for uu.net would leave the chain pointed to
|
||||
vix.com, the DNSSEC predecessor. Though this might first appear to
|
||||
cause level_matches to be bogus because the chain has been unwound and
|
||||
sent down another path, note that the partial match node will always
|
||||
be in the chain of the predecessor, too --- and often the partial
|
||||
match node will be the predecessor itself. In the vix.com/isc.org
|
||||
example, the search for uu.net finds a partial match at ".", which is
|
||||
of course also in the path to the vix.com predecessor. A search for
|
||||
www.isc.org would find that isc.org is both the partial match and the
|
||||
predecessor.
|
||||
|
||||
EXTERNAL PROGRAMMATIC DETAILS
|
||||
|
||||
This section details the functions used to interact with the BIND9
|
||||
red-black tree library, or RBT for short.
|
||||
|
||||
A source file that will be using RBT will usually need to include
|
||||
<dns/rbt.h>. This header file automatically includes <isc/result.h),
|
||||
<isc/mem.h>, <dns/types.h>, and <dns/name.h>.
|
||||
|
||||
The rbt.h file has more complete descriptions of each of the functions
|
||||
named here, including what is required for each argument, what each
|
||||
function ensures (and might not ensure) will occur, and the full range
|
||||
of possible results for each call. Note well: if a function returns a
|
||||
dns_result_t rather than void, it definitely means there is something
|
||||
that can go possibly wrong in the function and it should be checked by
|
||||
the caller.
|
||||
|
||||
A new tree of trees must be initialized using:
|
||||
|
||||
dns_result_t dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
|
||||
void *deleter_arg, dns_rbt_t **rbtp);
|
||||
|
||||
The memory context, mctx, must be a non-null pointer that was
|
||||
initialized with isc_mem_create(). The deleter argument, if non-null,
|
||||
should point to a function that is responsible for cleaning up any
|
||||
memory associated with the data pointer of a node when the node is
|
||||
deleted. It is passed the deleted node's data pointer as its first
|
||||
argument and deleter_arg as its second argument.
|
||||
|
||||
After initializing an RBT manager, to add keys to the tree, use:
|
||||
|
||||
dns_result_t dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data);
|
||||
|
||||
The name _must_ be an absolute name. It is not required that the data
|
||||
pointer be non-null, but it is recommended that it point to something,
|
||||
even just invalid memory, because of the various searching and
|
||||
deletion issues described in the previous section. The RBT code will
|
||||
not attempt to dereference the pointer.
|
||||
|
||||
To find a key in the tree, use:
|
||||
|
||||
dns_result_t dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, void **data);
|
||||
|
||||
The data parameter must not be NULL, but *data must be NULL. The
|
||||
result will be either DNS_R_SUCCESS, DNS_R_PARTIALMATCH or
|
||||
DNS_R_NOTFOUND. In the first case, an exact match was found for the
|
||||
name and there was an associate data pointer, which is returned via
|
||||
the data parameter. A partial match results when the name has not
|
||||
been found but a superdomain name, with data, does exist; then the
|
||||
data for that name is returned in the data parameter. If no data is
|
||||
found for the name or a superdomain, *data will remain NULL.
|
||||
|
||||
|
||||
INTERNAL PROGRAMMATIC DETAILS
|
||||
|
||||
This section is mainly relevant to the RBT DB implementation. It is
|
||||
highly recommended that programmers using the RBT library stick to the
|
||||
functions named in the previous section.
|
||||
|
||||
The dns_rbt_addname and dns_rbt_findname functions named in the
|
||||
previous section are wrappers around dns_rbt_addnode and
|
||||
dns_rbt_findnode. The *node functions for the most part do not
|
||||
particularly care whether a node has an associated data pointer or
|
||||
not, whereas the *name functions do. The one exception to this is
|
||||
that when a PARTIALMATCH is returned for a search, the indicated node
|
||||
is the deepest match that has data, rather than just the deepest
|
||||
match. Even that behavior is selectable, however, using the boolean
|
||||
empty_data_ok argument to dns_rbt_findnode.
|
||||
|
||||
Each node in the tree of trees is represented by the following structure:
|
||||
|
||||
typedef struct dns_rbtnode {
|
||||
struct dns_rbtnode *left;
|
||||
struct dns_rbtnode *right;
|
||||
struct dns_rbtnode *down;
|
||||
/*
|
||||
* The following bitfields add up to a total bitwidth of 32.
|
||||
* The range of values necessary for each item is indicated,
|
||||
* but in the case of "attributes" the field is wider to accommodate
|
||||
* possible future expansion. "offsetlen" could be one bit
|
||||
* narrower by always adjusting its value by 1 to find the real
|
||||
* offsetlen, but doing so does not gain anything (except perhaps
|
||||
* another bit for "attributes", which doesn't yet need any more).
|
||||
*/
|
||||
unsigned int color:1; /* range is 0..1 */
|
||||
unsigned int attributes:6; /* range is 0..2 */
|
||||
unsigned int namelen:8; /* range is 1..255 */
|
||||
unsigned int offsetlen:8; /* range is 1..128 */
|
||||
unsigned int padbytes:9; /* range is 0..380 */
|
||||
/*
|
||||
* These values are used in the RBT DB implementation. The
|
||||
* appropriate node lock must be held before accessing them.
|
||||
*/
|
||||
void *data;
|
||||
unsigned int dirty:1;
|
||||
unsigned int locknum:DNS_RBT_LOCKLENGTH;
|
||||
unsigned int references:DNS_RBT_REFLENGTH;
|
||||
} dns_rbtnode_t;
|
||||
|
||||
@@@
|
||||
+1
-7
@@ -102,7 +102,6 @@ libdns_la_HEADERS = \
|
||||
include/dns/peer.h \
|
||||
include/dns/private.h \
|
||||
include/dns/qp.h \
|
||||
include/dns/rbt.h \
|
||||
include/dns/rcode.h \
|
||||
include/dns/rdata.h \
|
||||
include/dns/rdataclass.h \
|
||||
@@ -218,12 +217,7 @@ libdns_la_SOURCES = \
|
||||
qp_p.h \
|
||||
qpzone_p.h \
|
||||
qpzone.c \
|
||||
rbt.c \
|
||||
rbt-cachedb.c \
|
||||
rbt-zonedb.c \
|
||||
rbtdb.c \
|
||||
rbtdb_p.h \
|
||||
qpcache.c \
|
||||
qpcache.c \
|
||||
qpcache_p.h \
|
||||
rcode.c \
|
||||
rdata.c \
|
||||
|
||||
@@ -64,7 +64,6 @@ struct dns_dbimplementation {
|
||||
#include "db_p.h"
|
||||
#include "qpcache_p.h"
|
||||
#include "qpzone_p.h"
|
||||
#include "rbtdb_p.h"
|
||||
|
||||
unsigned int dns_pps = 0U;
|
||||
|
||||
@@ -72,7 +71,6 @@ static ISC_LIST(dns_dbimplementation_t) implementations;
|
||||
static isc_rwlock_t implock;
|
||||
static isc_once_t once = ISC_ONCE_INIT;
|
||||
|
||||
static dns_dbimplementation_t rbtimp;
|
||||
static dns_dbimplementation_t qpimp;
|
||||
static dns_dbimplementation_t qpzoneimp;
|
||||
|
||||
@@ -82,12 +80,6 @@ initialize(void) {
|
||||
|
||||
ISC_LIST_INIT(implementations);
|
||||
|
||||
rbtimp = (dns_dbimplementation_t){
|
||||
.name = "rbt",
|
||||
.create = dns__rbtdb_create,
|
||||
.link = ISC_LINK_INITIALIZER,
|
||||
};
|
||||
|
||||
qpimp = (dns_dbimplementation_t){
|
||||
.name = "qpcache",
|
||||
.create = dns__qpcache_create,
|
||||
@@ -100,7 +92,6 @@ initialize(void) {
|
||||
.link = ISC_LINK_INITIALIZER,
|
||||
};
|
||||
|
||||
ISC_LIST_APPEND(implementations, &rbtimp, link);
|
||||
ISC_LIST_APPEND(implementations, &qpimp, link);
|
||||
ISC_LIST_APPEND(implementations, &qpzoneimp, link);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <isc/urcu.h>
|
||||
|
||||
#include <dns/nsec3.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
#define RDATATYPE_NCACHEANY DNS_TYPEPAIR_VALUE(0, dns_rdatatype_any)
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include <dns/ecs.h>
|
||||
#include <dns/nsec.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/rdatatype.h>
|
||||
#include <dns/result.h>
|
||||
|
||||
@@ -1076,15 +1076,19 @@ isc_result_t
|
||||
dns_db_createiterator(dns_db_t *db, unsigned int options,
|
||||
dns_dbiterator_t **iteratorp);
|
||||
/*%<
|
||||
* Create an iterator for version 'version' of 'db'.
|
||||
* Create an iterator for 'db'.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* \li One or more of the following options can be set.
|
||||
* \li One or more of the following options can be set:
|
||||
*
|
||||
* #DNS_DB_RELATIVENAMES
|
||||
* #DNS_DB_NSEC3ONLY
|
||||
* #DNS_DB_NONSEC3
|
||||
*
|
||||
* (Note that it is not mandatory to implement these flags;
|
||||
* some databases will ignore them.)
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* \li 'db' is a valid database.
|
||||
|
||||
@@ -1078,7 +1078,7 @@ dns_name_dup(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target);
|
||||
*\li 'mctx' is a valid memory context.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_name_dupwithoffsets(const dns_name_t *source, isc_mem_t *mctx,
|
||||
dns_name_t *target);
|
||||
/*%<
|
||||
|
||||
@@ -1,854 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \file dns/rbt.h */
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <isc/assertions.h>
|
||||
#include <isc/crc64.h>
|
||||
#include <isc/lang.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/refcount.h>
|
||||
|
||||
#include <dns/types.h>
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
/*@{*/
|
||||
/*%
|
||||
* Option values for dns_rbt_findnode().
|
||||
* These are used to form a bitmask.
|
||||
*/
|
||||
#define DNS_RBTFIND_NOOPTIONS 0x00
|
||||
#define DNS_RBTFIND_EMPTYDATA 0x01
|
||||
#define DNS_RBTFIND_NOEXACT 0x02
|
||||
#define DNS_RBTFIND_NOPREDECESSOR 0x04
|
||||
/*@}*/
|
||||
|
||||
#define DNS_RBT_USEMAGIC 1
|
||||
|
||||
#define DNS_RBT_LOCKLENGTH (sizeof(((dns_rbtnode_t *)0)->locknum) * 8)
|
||||
|
||||
#define DNS_RBTNODE_MAGIC ISC_MAGIC('R', 'B', 'N', 'O')
|
||||
#if DNS_RBT_USEMAGIC
|
||||
#define DNS_RBTNODE_VALID(n) ISC_MAGIC_VALID(n, DNS_RBTNODE_MAGIC)
|
||||
#else /* if DNS_RBT_USEMAGIC */
|
||||
#define DNS_RBTNODE_VALID(n) true
|
||||
#endif /* if DNS_RBT_USEMAGIC */
|
||||
|
||||
/*%
|
||||
* This is the structure that is used for each node in the red/black
|
||||
* tree of trees. NOTE WELL: the implementation manages this as a variable
|
||||
* length structure, with the actual wire-format name and other data
|
||||
* appended to this structure. Allocating a contiguous block of memory for
|
||||
* multiple dns_rbtnode structures will not work.
|
||||
*/
|
||||
struct dns_rbtnode {
|
||||
#if DNS_RBT_USEMAGIC
|
||||
unsigned int magic;
|
||||
#endif /* if DNS_RBT_USEMAGIC */
|
||||
/*@{*/
|
||||
/*!
|
||||
* The following bitfields add up to a total bitwidth of 32.
|
||||
* The range of values necessary for each item is indicated.
|
||||
*
|
||||
* In each case below the "range" indicated is what's _necessary_ for
|
||||
* the bitfield to hold, not what it actually _can_ hold.
|
||||
*
|
||||
* Note: Tree lock must be held before modifying these
|
||||
* bit-fields.
|
||||
*
|
||||
* Note: The two "unsigned int :0;" unnamed bitfields on either
|
||||
* side of the bitfields below are scaffolding that border the
|
||||
* set of bitfields which are accessed after acquiring the tree
|
||||
* lock. Please don't insert any other bitfield members between
|
||||
* the unnamed bitfields unless they should also be accessed
|
||||
* after acquiring the tree lock.
|
||||
*/
|
||||
unsigned int : 0; /* start of bitfields c/o tree lock */
|
||||
unsigned int is_root : 1; /*%< range is 0..1 */
|
||||
unsigned int color : 1; /*%< range is 0..1 */
|
||||
unsigned int find_callback : 1; /*%< range is 0..1 */
|
||||
bool absolute : 1; /*%< node with absolute DNS name */
|
||||
unsigned int nsec : 2; /*%< range is 0..3 */
|
||||
unsigned int namelen : 8; /*%< range is 1..255 */
|
||||
unsigned int offsetlen : 8; /*%< range is 1..128 */
|
||||
unsigned int oldnamelen : 8; /*%< range is 1..255 */
|
||||
unsigned int : 0; /* end of bitfields c/o tree lock */
|
||||
/*@}*/
|
||||
|
||||
/*%
|
||||
* These are needed for hashing. The 'uppernode' points to the
|
||||
* node's superdomain node in the parent subtree, so that it can
|
||||
* be reached from a child that was found by a hash lookup.
|
||||
*/
|
||||
unsigned int hashval;
|
||||
dns_rbtnode_t *uppernode;
|
||||
dns_rbtnode_t *hashnext;
|
||||
|
||||
dns_rbtnode_t *parent;
|
||||
dns_rbtnode_t *left;
|
||||
dns_rbtnode_t *right;
|
||||
dns_rbtnode_t *down;
|
||||
|
||||
/*%
|
||||
* Used for LRU cache. This linked list is used to mark nodes which
|
||||
* have no data any longer, but we cannot unlink at that exact moment
|
||||
* because we did not or could not obtain a write lock on the tree.
|
||||
*/
|
||||
ISC_LINK(dns_rbtnode_t) deadlink;
|
||||
|
||||
/*@{*/
|
||||
/*!
|
||||
* These values are used in the RBT DB implementation. The appropriate
|
||||
* node lock must be held before accessing them.
|
||||
*
|
||||
* Note: The two "unsigned int :0;" unnamed bitfields on either
|
||||
* side of the bitfields below are scaffolding that border the
|
||||
* set of bitfields which are accessed after acquiring the node
|
||||
* lock. Please don't insert any other bitfield members between
|
||||
* the unnamed bitfields unless they should also be accessed
|
||||
* after acquiring the node lock.
|
||||
*
|
||||
* NOTE: Do not merge these fields into bitfields above, as
|
||||
* they'll all be put in the same qword that could be accessed
|
||||
* without the node lock as it shares the qword with other
|
||||
* members. Leave these members here so that they occupy a
|
||||
* separate region of memory.
|
||||
*/
|
||||
void *data;
|
||||
uint8_t : 0; /* start of bitfields c/o node lock */
|
||||
uint8_t dirty : 1;
|
||||
uint8_t wild : 1;
|
||||
uint8_t : 0; /* end of bitfields c/o node lock */
|
||||
uint16_t locknum; /* note that this is not in the bitfield */
|
||||
isc_refcount_t references;
|
||||
/*@}*/
|
||||
};
|
||||
|
||||
typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node,
|
||||
dns_name_t *name,
|
||||
void *callback_arg DNS__DB_FLARG);
|
||||
|
||||
typedef void (*dns_rbtdeleter_t)(void *, void *);
|
||||
|
||||
/*****
|
||||
***** Chain Info
|
||||
*****/
|
||||
|
||||
/*!
|
||||
* A chain is used to keep track of the sequence of nodes to reach any given
|
||||
* node from the root of the tree. Originally nodes did not have parent
|
||||
* pointers in them (for memory usage reasons) so there was no way to find
|
||||
* the path back to the root from any given node. Now that nodes have parent
|
||||
* pointers, chains might be going away in a future release, though the
|
||||
* movement functionality would remain.
|
||||
*
|
||||
* Chains may be used to iterate over a tree of trees. After setting up the
|
||||
* chain's structure using dns_rbtnodechain_init(), it needs to be initialized
|
||||
* to point to the lexically first or lexically last node in the tree of trees
|
||||
* using dns_rbtnodechain_first() or dns_rbtnodechain_last(), respectively.
|
||||
* Calling dns_rbtnodechain_next() or dns_rbtnodechain_prev() then moves the
|
||||
* chain over to the next or previous node, respectively.
|
||||
*
|
||||
* In any event, parent information, whether via parent pointers or chains, is
|
||||
* necessary information for iterating through the tree or for basic internal
|
||||
* tree maintenance issues (ie, the rotations that are done to rebalance the
|
||||
* tree when a node is added). The obvious implication of this is that for a
|
||||
* chain to remain valid, the tree has to be locked down against writes for the
|
||||
* duration of the useful life of the chain, because additions or removals can
|
||||
* change the path from the root to the node the chain has targeted.
|
||||
*
|
||||
* The dns_rbtnodechain_ functions _first, _last, _prev and _next all take
|
||||
* dns_name_t parameters for the name and the origin, which can be NULL. If
|
||||
* non-NULL, 'name' will end up pointing to the name data and offsets that are
|
||||
* stored at the node (and thus it will be read-only), so it should be a
|
||||
* regular dns_name_t that has been initialized with dns_name_init. When
|
||||
* 'origin' is non-NULL, it will get the name of the origin stored in it, so it
|
||||
* needs to have its own buffer space and offsets, which is most easily
|
||||
* accomplished with a dns_fixedname_t. It is _not_ necessary to reinitialize
|
||||
* either 'name' or 'origin' between calls to the chain functions.
|
||||
*
|
||||
* NOTE WELL: even though the name data at the root of the tree of trees will
|
||||
* be absolute (typically just "."), it will will be made into a relative name
|
||||
* with an origin of "." -- an empty name when the node is ".". This is
|
||||
* because a common on operation on 'name' and 'origin' is to use
|
||||
* dns_name_concatenate() on them to generate the complete name. An empty name
|
||||
* can be detected when dns_name_countlabels == 0, and is printed by
|
||||
* dns_name_totext()/dns_name_format() as "@", consistent with RFC1035's
|
||||
* definition of "@" as the current origin.
|
||||
*
|
||||
* dns_rbtnodechain_current is similar to the _first, _last, _prev and _next
|
||||
* functions but additionally can provide the node to which the chain points.
|
||||
*/
|
||||
|
||||
/*%
|
||||
* The number of level blocks to allocate at a time, same as the maximum
|
||||
* number of labels. Allocating space for 128 levels when the tree is
|
||||
* almost never that deep is wasteful, but it's not clear that it matters,
|
||||
* since the waste is only 1MB for 1000 concurrently active chains on a
|
||||
* system with 64-bit pointers.
|
||||
*/
|
||||
#define DNS_RBT_LEVELBLOCK 127
|
||||
|
||||
typedef struct dns_rbtnodechain {
|
||||
unsigned int magic;
|
||||
/*%
|
||||
* The terminal node of the chain. It is not in levels[].
|
||||
* This is ostensibly private ... but in a pinch it could be
|
||||
* used tell that the chain points nowhere without needing to
|
||||
* call dns_rbtnodechain_current().
|
||||
*/
|
||||
dns_rbtnode_t *end;
|
||||
/*%
|
||||
* Currently the maximum number of levels is allocated directly in
|
||||
* the structure, but future revisions of this code might have a
|
||||
* static initial block with dynamic growth.
|
||||
*/
|
||||
dns_rbtnode_t *levels[DNS_RBT_LEVELBLOCK];
|
||||
/*%
|
||||
* level_count indicates how deep the chain points into the
|
||||
* tree of trees, and is the index into the levels[] array.
|
||||
* Thus, levels[level_count - 1] is the last level node stored.
|
||||
* A chain that points to the top level of the tree of trees has
|
||||
* a level_count of 0, the first level has a level_count of 1, and
|
||||
* so on.
|
||||
*/
|
||||
unsigned int level_count;
|
||||
/*%
|
||||
* level_matches tells how many levels matched above the node
|
||||
* returned by dns_rbt_findnode(). A match (partial or exact) found
|
||||
* in the first level thus results in level_matches being set to 1.
|
||||
* This is used by the rbtdb to set the start point for a recursive
|
||||
* search of superdomains until the RR it is looking for is found.
|
||||
*/
|
||||
unsigned int level_matches;
|
||||
} dns_rbtnodechain_t;
|
||||
|
||||
/*****
|
||||
***** Public interfaces.
|
||||
*****/
|
||||
isc_result_t
|
||||
dns_rbt_create(isc_mem_t *mctx, dns_rbtdeleter_t deleter, void *deleter_arg,
|
||||
dns_rbt_t **rbtp);
|
||||
/*%<
|
||||
* Initialize a red-black tree of trees.
|
||||
*
|
||||
* Notes:
|
||||
*\li The deleter argument, if non-null, points to a function that is
|
||||
* responsible for cleaning up any memory associated with the data
|
||||
* pointer of a node when the node is deleted. It is passed the
|
||||
* deleted node's data pointer as its first argument and deleter_arg
|
||||
* as its second argument.
|
||||
*
|
||||
* Requires:
|
||||
* \li mctx is a pointer to a valid memory context.
|
||||
*\li rbtp != NULL && *rbtp == NULL
|
||||
*\li arg == NULL iff deleter == NULL
|
||||
*
|
||||
* Ensures:
|
||||
*\li If result is ISC_R_SUCCESS:
|
||||
* *rbtp points to a valid red-black tree manager
|
||||
*
|
||||
*\li If result is failure:
|
||||
* *rbtp does not point to a valid red-black tree manager.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS Success
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rbt_addnode(dns_rbt_t *rbt, const dns_name_t *name, dns_rbtnode_t **nodep);
|
||||
|
||||
/*%<
|
||||
* Add 'name' to the tree of trees. On success, return the address of
|
||||
* the newly added node. If 'name' already existed, return ISC_R_EXISTS
|
||||
* and the address of the pre-existing node.
|
||||
*
|
||||
* Requires:
|
||||
*\li rbt is a valid rbt structure.
|
||||
*\li dns_name_isabsolute(name) == TRUE
|
||||
*\li nodep != NULL && *nodep == NULL
|
||||
*
|
||||
* Ensures:
|
||||
*\li 'name' is not altered in any way.
|
||||
*
|
||||
*\li Any external references to nodes in the tree are unaffected by
|
||||
* node splits that are necessary to insert the new name.
|
||||
*
|
||||
*\li If result is ISC_R_SUCCESS:
|
||||
* 'name' is findable in the red/black tree of trees in O(log N).
|
||||
* *nodep is the node that was added for 'name'.
|
||||
*
|
||||
*\li If result is ISC_R_EXISTS:
|
||||
* The tree of trees is unaltered.
|
||||
* *nodep is the existing node for 'name'.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS Success
|
||||
*\li #ISC_R_EXISTS The name already exists, possibly without data.
|
||||
*\li #ISC_R_NOSPACE The name had more logical labels than are allowed.
|
||||
*/
|
||||
|
||||
#define dns_rbt_findnode(rbt, name, foundname, node, chain, options, callback, \
|
||||
callback_arg) \
|
||||
dns__rbt_findnode(rbt, name, foundname, node, chain, options, \
|
||||
callback, callback_arg DNS__DB_FILELINE)
|
||||
isc_result_t
|
||||
dns__rbt_findnode(dns_rbt_t *rbt, const dns_name_t *name, dns_name_t *foundname,
|
||||
dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
|
||||
unsigned int options, dns_rbtfindcallback_t callback,
|
||||
void *callback_arg DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Find the node for 'name'.
|
||||
*
|
||||
* Notes:
|
||||
*\li A node that has no data is considered not to exist for this function,
|
||||
* unless the DNS_RBTFIND_EMPTYDATA option is set. This applies to both
|
||||
* exact matches and partial matches.
|
||||
*
|
||||
*\li If the chain parameter is non-NULL, then the path through the tree
|
||||
* to the DNSSEC predecessor of the searched for name is maintained,
|
||||
* unless the DNS_RBTFIND_NOPREDECESSOR or DNS_RBTFIND_NOEXACT option
|
||||
* is used. (For more details on those options, see below.)
|
||||
*
|
||||
*\li If there is no predecessor, then the chain will point to nowhere, as
|
||||
* indicated by chain->end being NULL or dns_rbtnodechain_current
|
||||
* returning ISC_R_NOTFOUND. Note that in a normal Internet DNS RBT
|
||||
* there will always be a predecessor for all names except the root
|
||||
* name, because '.' will exist and '.' is the predecessor of
|
||||
* everything. But you can certainly construct a trivial tree and a
|
||||
* search for it that has no predecessor.
|
||||
*
|
||||
*\li Within the chain structure, the 'levels' member of the structure holds
|
||||
* the root node of each level except the first.
|
||||
*
|
||||
*\li The 'level_count' of the chain indicates how deep the chain to the
|
||||
* predecessor name is, as an index into the 'levels[]' array. It does
|
||||
* not count name elements, per se, but only levels of the tree of trees,
|
||||
* the distinction arising because multiple labels from a name can be
|
||||
* stored on only one level. It is also does not include the level
|
||||
* that has the node, since that level is not stored in levels[].
|
||||
*
|
||||
*\li The chain's 'level_matches' is not directly related to the predecessor.
|
||||
* It is the number of levels above the level of the found 'node',
|
||||
* regardless of whether it was a partial match or exact match. When
|
||||
* the node is found in the top level tree, or no node is found at all,
|
||||
* level_matches is 0.
|
||||
*
|
||||
*\li When DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
|
||||
* returned (also subject to DNS_RBTFIND_EMPTYDATA), even when
|
||||
* there is an exact match in the tree. In this case, the chain
|
||||
* will not point to the DNSSEC predecessor, but will instead point
|
||||
* to the exact match, if there was any. Thus the preceding paragraphs
|
||||
* should have "exact match" substituted for "predecessor" to describe
|
||||
* how the various elements of the chain are set. This was done to
|
||||
* ensure that the chain's state was sane, and to prevent problems that
|
||||
* occurred when running the predecessor location code under conditions
|
||||
* it was not designed for. It is not clear *where* the chain should
|
||||
* point when DNS_RBTFIND_NOEXACT is set, so if you end up using a chain
|
||||
* with this option because you want a particular node, let us know
|
||||
* where you want the chain pointed, so this can be made more firm.
|
||||
*
|
||||
* Requires:
|
||||
*\li rbt is a valid rbt manager.
|
||||
*\li dns_name_isabsolute(name) == TRUE.
|
||||
*\li node != NULL && *node == NULL.
|
||||
*\li #DNS_RBTFIND_NOEXACT and DNS_RBTFIND_NOPREDECESSOR are mutually
|
||||
* exclusive.
|
||||
*
|
||||
* Ensures:
|
||||
*\li 'name' and the tree are not altered in any way.
|
||||
*
|
||||
*\li If result is ISC_R_SUCCESS:
|
||||
*\verbatim
|
||||
* *node is the terminal node for 'name'.
|
||||
*
|
||||
* 'foundname' and 'name' represent the same name (though not
|
||||
* the same memory).
|
||||
*
|
||||
* 'chain' points to the DNSSEC predecessor, if any, of 'name'.
|
||||
*
|
||||
* chain->level_matches and chain->level_count are equal.
|
||||
*\endverbatim
|
||||
*
|
||||
* If result is DNS_R_PARTIALMATCH:
|
||||
*\verbatim
|
||||
* *node is the data associated with the deepest superdomain
|
||||
* of 'name' which has data.
|
||||
*
|
||||
* 'foundname' is the name of deepest superdomain (which has
|
||||
* data, unless the DNS_RBTFIND_EMPTYDATA option is set).
|
||||
*
|
||||
* 'chain' points to the DNSSEC predecessor, if any, of 'name'.
|
||||
*\endverbatim
|
||||
*
|
||||
*\li If result is ISC_R_NOTFOUND:
|
||||
*\verbatim
|
||||
* Neither the name nor a superdomain was found. *node is NULL.
|
||||
*
|
||||
* 'chain' points to the DNSSEC predecessor, if any, of 'name'.
|
||||
*
|
||||
* chain->level_matches is 0.
|
||||
*\endverbatim
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS Success
|
||||
*\li #DNS_R_PARTIALMATCH Superdomain found with data
|
||||
*\li #ISC_R_NOTFOUND No match, or superdomain with no data
|
||||
*\li #ISC_R_NOSPACE Concatenating nodes to form foundname failed
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, bool recurse);
|
||||
/*%<
|
||||
* Delete 'node' from the tree of trees.
|
||||
*
|
||||
* Notes:
|
||||
*\li When 'node' is removed, if recurse is true then all nodes
|
||||
* in levels down from it are removed too.
|
||||
*
|
||||
* Requires:
|
||||
*\li rbt is a valid rbt manager.
|
||||
*\li node != NULL.
|
||||
*
|
||||
* Ensures:
|
||||
*\li Does NOT ensure that any external references to nodes in the tree
|
||||
* are unaffected by node joins.
|
||||
*
|
||||
*\li If result is ISC_R_SUCCESS:
|
||||
* 'node' does not appear in the tree with data; however,
|
||||
* the node might still exist if it serves as a pointer to
|
||||
* a lower tree level as long as 'recurse' was false, hence
|
||||
* the node could can be found with dns_rbt_findnode when
|
||||
* that function's empty_data_ok parameter is true.
|
||||
*
|
||||
*\li If result is ISC_R_NOSPACE:
|
||||
* The node was deleted, but the tree structure was not
|
||||
* optimized.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS Success
|
||||
*\li #ISC_R_NOSPACE dns_name_concatenate failed when joining nodes.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name);
|
||||
/*%<
|
||||
* Convert the sequence of labels stored at 'node' into a 'name'.
|
||||
*
|
||||
* Notes:
|
||||
*\li This function does not return the full name, from the root, but
|
||||
* just the labels at the indicated node.
|
||||
*
|
||||
*\li The name data pointed to by 'name' is the information stored
|
||||
* in the node, not a copy. Altering the data at this pointer
|
||||
* will likely cause grief.
|
||||
*
|
||||
* Requires:
|
||||
* \li name->offsets == NULL
|
||||
*
|
||||
* Ensures:
|
||||
* \li 'name' is readonly.
|
||||
*
|
||||
* \li 'name' will point directly to the labels stored after the
|
||||
* dns_rbtnode_t struct.
|
||||
*
|
||||
* \li 'name' will have offsets that also point to the information stored
|
||||
* as part of the node.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name);
|
||||
/*%<
|
||||
* Like dns_rbt_namefromnode, but returns the full name from the root.
|
||||
*
|
||||
* Notes:
|
||||
* \li Unlike dns_rbt_namefromnode, the name will not point directly
|
||||
* to node data. Rather, dns_name_concatenate will be used to copy
|
||||
* the name data from each node into the 'name' argument.
|
||||
*
|
||||
* Requires:
|
||||
* \li name != NULL
|
||||
* \li name has a dedicated buffer.
|
||||
*
|
||||
* Returns:
|
||||
* \li ISC_R_SUCCESS
|
||||
* \li ISC_R_NOSPACE (possible via dns_name_concatenate)
|
||||
* \li DNS_R_NAMETOOLONG (possible via dns_name_concatenate)
|
||||
*/
|
||||
|
||||
char *
|
||||
dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, unsigned int size);
|
||||
/*%<
|
||||
* Format the full name of a node for printing, using dns_name_format().
|
||||
*
|
||||
* Notes:
|
||||
* \li 'size' is the length of the printname buffer. This should be
|
||||
* DNS_NAME_FORMATSIZE or larger.
|
||||
*
|
||||
* Requires:
|
||||
* \li node and printname are not NULL.
|
||||
*
|
||||
* Returns:
|
||||
* \li The 'printname' pointer.
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
dns_rbt_nodecount(dns_rbt_t *rbt);
|
||||
/*%<
|
||||
* Obtain the number of nodes in the tree of trees.
|
||||
*
|
||||
* Requires:
|
||||
* \li rbt is a valid rbt manager.
|
||||
*/
|
||||
|
||||
size_t
|
||||
dns_rbt_hashsize(dns_rbt_t *rbt);
|
||||
/*%<
|
||||
* Obtain the current number of buckets in the 'rbt' hash table.
|
||||
*
|
||||
* Requires:
|
||||
* \li rbt is a valid rbt manager.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rbt_destroy(dns_rbt_t **rbtp, unsigned int quantum);
|
||||
/*%<
|
||||
* Stop working with a red-black tree of trees.
|
||||
* If 'quantum' is zero then the entire tree will be destroyed.
|
||||
* If 'quantum' is non zero then up to 'quantum' nodes will be destroyed
|
||||
* allowing the rbt to be incrementally destroyed by repeated calls to
|
||||
* dns_rbt_destroy2(). Once dns_rbt_destroy2() has been called no other
|
||||
* operations than dns_rbt_destroy()/dns_rbt_destroy2() should be
|
||||
* performed on the tree of trees.
|
||||
*
|
||||
* Requires:
|
||||
* \li *rbt is a valid rbt manager.
|
||||
*
|
||||
* Ensures on ISC_R_SUCCESS:
|
||||
* \li All space allocated by the RBT library has been returned.
|
||||
*
|
||||
* \li *rbt is invalidated as an rbt manager.
|
||||
*
|
||||
* Returns:
|
||||
* \li ISC_R_SUCCESS
|
||||
* \li ISC_R_QUOTA if 'quantum' nodes have been destroyed.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_rbt_printtext(dns_rbt_t *rbt, void (*data_printer)(FILE *, void *),
|
||||
FILE *f);
|
||||
/*%<
|
||||
* Print an ASCII representation of the internal structure of the red-black
|
||||
* tree of trees to the passed stream.
|
||||
*
|
||||
* data_printer is a callback function that is called to print the data
|
||||
* in a node. It should print it to the passed FILE stream.
|
||||
*
|
||||
* Notes:
|
||||
* \li The name stored at each node, along with the node's color, is printed.
|
||||
* Then the down pointer, left and right pointers are displayed
|
||||
* recursively in turn. NULL down pointers are silently omitted;
|
||||
* NULL left and right pointers are printed.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_rbt_printdot(dns_rbt_t *rbt, bool show_pointers, FILE *f);
|
||||
/*%<
|
||||
* Print a GraphViz dot representation of the internal structure of the
|
||||
* red-black tree of trees to the passed stream.
|
||||
*
|
||||
* If show_pointers is TRUE, pointers are also included in the generated
|
||||
* graph.
|
||||
*
|
||||
* Notes:
|
||||
* \li The name stored at each node, along with the node's color is displayed.
|
||||
* Then the down pointer, left and right pointers are displayed
|
||||
* recursively in turn. NULL left, right and down pointers are
|
||||
* silently omitted.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_rbt_printnodeinfo(dns_rbtnode_t *n, FILE *f);
|
||||
/*%<
|
||||
* Print out various information about a node
|
||||
*
|
||||
* Requires:
|
||||
*\li 'n' is a valid pointer.
|
||||
*
|
||||
*\li 'f' points to a valid open FILE structure that allows writing.
|
||||
*/
|
||||
|
||||
size_t
|
||||
dns__rbt_getheight(dns_rbt_t *rbt);
|
||||
/*%<
|
||||
* Return the maximum height of sub-root nodes found in the red-black
|
||||
* forest.
|
||||
*
|
||||
* The height of a node is defined as the number of nodes in the longest
|
||||
* path from the node to a leaf. For each subtree in the forest, this
|
||||
* function determines the height of its root node. Then it returns the
|
||||
* maximum such height in the forest.
|
||||
*
|
||||
* Note: This function exists for testing purposes. Non-test code must
|
||||
* not use it.
|
||||
*
|
||||
* Requires:
|
||||
* \li rbt is a valid rbt manager.
|
||||
*/
|
||||
|
||||
bool
|
||||
dns__rbt_checkproperties(dns_rbt_t *rbt);
|
||||
/*%<
|
||||
* Check red-black properties of the forest.
|
||||
*
|
||||
* Note: This function exists for testing purposes. Non-test code must
|
||||
* not use it.
|
||||
*
|
||||
* Requires:
|
||||
* \li rbt is a valid rbt manager.
|
||||
*/
|
||||
|
||||
size_t
|
||||
dns__rbtnode_getdistance(dns_rbtnode_t *node);
|
||||
/*%<
|
||||
* Return the distance (in nodes) from the node to its upper node of its
|
||||
* subtree. The root node has a distance of 1. A child of the root node
|
||||
* has a distance of 2.
|
||||
*/
|
||||
|
||||
/*****
|
||||
***** Chain Functions
|
||||
*****/
|
||||
|
||||
void
|
||||
dns_rbtnodechain_init(dns_rbtnodechain_t *chain);
|
||||
/*%<
|
||||
* Initialize 'chain'.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'chain' is a valid pointer.
|
||||
*
|
||||
* Ensures:
|
||||
*\li 'chain' is suitable for use.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_rbtnodechain_reset(dns_rbtnodechain_t *chain);
|
||||
/*%<
|
||||
* Free any dynamic storage associated with 'chain', and then reinitialize
|
||||
* 'chain'.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'chain' is a valid pointer.
|
||||
*
|
||||
* Ensures:
|
||||
*\li 'chain' is suitable for use, and uses no dynamic storage.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain);
|
||||
/*%<
|
||||
* Free any dynamic storage associated with 'chain', and then invalidates it.
|
||||
*
|
||||
* Notes:
|
||||
*\li Future calls to any dns_rbtnodechain_ function will need to call
|
||||
* dns_rbtnodechain_init on the chain first (except, of course,
|
||||
* dns_rbtnodechain_init itself).
|
||||
*
|
||||
* Requires:
|
||||
*\li 'chain' is a valid chain.
|
||||
*
|
||||
* Ensures:
|
||||
*\li 'chain' is no longer suitable for use, and uses no dynamic storage.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
|
||||
dns_name_t *origin, dns_rbtnode_t **node);
|
||||
/*%<
|
||||
* Provide the name, origin and node to which the chain is currently pointed.
|
||||
*
|
||||
* Notes:
|
||||
*\li The tree need not have be locked against additions for the chain
|
||||
* to remain valid, however there are no guarantees if any deletion
|
||||
* has been made since the chain was established.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'chain' is a valid chain.
|
||||
*
|
||||
* Ensures:
|
||||
*\li 'node', if non-NULL, is the node to which the chain was pointed
|
||||
* by dns_rbt_findnode, dns_rbtnodechain_first or dns_rbtnodechain_last.
|
||||
* If none were called for the chain since it was initialized or reset,
|
||||
* or if the was no predecessor to the name searched for with
|
||||
* dns_rbt_findnode, then '*node' is NULL and ISC_R_NOTFOUND is returned.
|
||||
*
|
||||
*\li 'name', if non-NULL, is the name stored at the terminal level of
|
||||
* the chain. This is typically a single label, like the "www" of
|
||||
* "www.isc.org", but need not be so. At the root of the tree of trees,
|
||||
* if the node is "." then 'name' is ".", otherwise it is relative to ".".
|
||||
* (Minimalist and atypical case: if the tree has just the name
|
||||
* "isc.org." then the root node's stored name is "isc.org." but 'name'
|
||||
* will be "isc.org".)
|
||||
*
|
||||
*\li 'origin', if non-NULL, is the sequence of labels in the levels
|
||||
* above the terminal level, such as "isc.org." in the above example.
|
||||
* 'origin' is always "." for the root node.
|
||||
*
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS name, origin & node were successfully set.
|
||||
*\li #ISC_R_NOTFOUND The chain does not point to any node.
|
||||
*\li <something_else> Any error return from dns_name_concatenate.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
|
||||
dns_name_t *name, dns_name_t *origin);
|
||||
/*%<
|
||||
* Set the chain to the lexically first node in the tree of trees.
|
||||
*
|
||||
* Notes:
|
||||
*\li By the definition of ordering for DNS names, the root of the tree of
|
||||
* trees is the very first node, since everything else in the megatree
|
||||
* uses it as a common suffix.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'chain' is a valid chain.
|
||||
*\li 'rbt' is a valid rbt manager.
|
||||
*
|
||||
* Ensures:
|
||||
*\li The chain points to the very first node of the tree.
|
||||
*
|
||||
*\li 'name' and 'origin', if non-NULL, are set as described for
|
||||
* dns_rbtnodechain_current. Thus 'origin' will always be ".".
|
||||
*
|
||||
* Returns:
|
||||
*\li #DNS_R_NEWORIGIN The name & origin were successfully set.
|
||||
*\li <something_else> Any error result from dns_rbtnodechain_current.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
|
||||
dns_name_t *name, dns_name_t *origin);
|
||||
/*%<
|
||||
* Set the chain to the lexically last node in the tree of trees.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'chain' is a valid chain.
|
||||
*\li 'rbt' is a valid rbt manager.
|
||||
*
|
||||
* Ensures:
|
||||
*\li The chain points to the very last node of the tree.
|
||||
*
|
||||
*\li 'name' and 'origin', if non-NULL, are set as described for
|
||||
* dns_rbtnodechain_current.
|
||||
*
|
||||
* Returns:
|
||||
*\li #DNS_R_NEWORIGIN The name & origin were successfully set.
|
||||
*\li <something_else> Any error result from dns_name_concatenate.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
|
||||
dns_name_t *origin);
|
||||
/*%<
|
||||
* Adjusts chain to point the DNSSEC predecessor of the name to which it
|
||||
* is currently pointed.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'chain' is a valid chain.
|
||||
*\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
|
||||
* dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
|
||||
* dns_rbt_findnode is not guaranteed to point the chain somewhere,
|
||||
* since there may have been no predecessor to the searched for name.
|
||||
*
|
||||
* Ensures:
|
||||
*\li The chain is pointed to the predecessor of its current target.
|
||||
*
|
||||
*\li 'name' and 'origin', if non-NULL, are set as described for
|
||||
* dns_rbtnodechain_current.
|
||||
*
|
||||
*\li 'origin' is only if a new origin was found.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS The predecessor was found and 'name' was set.
|
||||
*\li #DNS_R_NEWORIGIN The predecessor was found with a
|
||||
* different origin and 'name' and 'origin' were set. \li #ISC_R_NOMORE There
|
||||
* was no predecessor. \li <something_else> Any error result from
|
||||
* dns_rbtnodechain_current.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
|
||||
dns_name_t *origin);
|
||||
/*%<
|
||||
* Adjusts chain to point the DNSSEC successor of the name to which it
|
||||
* is currently pointed.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'chain' is a valid chain.
|
||||
*\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
|
||||
* dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
|
||||
* dns_rbt_findnode is not guaranteed to point the chain somewhere,
|
||||
* since there may have been no predecessor to the searched for name.
|
||||
*
|
||||
* Ensures:
|
||||
*\li The chain is pointed to the successor of its current target.
|
||||
*
|
||||
*\li 'name' and 'origin', if non-NULL, are set as described for
|
||||
* dns_rbtnodechain_current.
|
||||
*
|
||||
*\li 'origin' is only if a new origin was found.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS The successor was found and 'name' was set.
|
||||
*\li #DNS_R_NEWORIGIN The successor was found with a different
|
||||
* origin and 'name' and 'origin' were set.
|
||||
*\li #ISC_R_NOMORE There was no successor.
|
||||
*\li <something_else> Any error result from dns_name_concatenate.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name,
|
||||
dns_name_t *origin);
|
||||
/*%<
|
||||
* Descend down if possible.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name);
|
||||
/*%<
|
||||
* Find the next node at the current depth in DNSSEC order.
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
dns__rbtnode_namelen(dns_rbtnode_t *node);
|
||||
/*%<
|
||||
* Returns the length of the full name of the node. Used only internally
|
||||
* and in unit tests.
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
dns__rbtnode_getsize(dns_rbtnode_t *node);
|
||||
/*
|
||||
* Return allocated size for a node.
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
@@ -117,12 +117,7 @@ struct dns_slabheader {
|
||||
|
||||
dns_db_t *db;
|
||||
dns_dbnode_t *node;
|
||||
/*%<
|
||||
* The database and database node objects containing
|
||||
* this rdataset, if any.
|
||||
*/
|
||||
|
||||
isc_stdtime_t last_used;
|
||||
ISC_LINK(struct dns_slabheader) link;
|
||||
|
||||
/*%
|
||||
|
||||
@@ -148,13 +148,11 @@ typedef struct dns_request dns_request_t;
|
||||
typedef struct dns_requestmgr dns_requestmgr_t;
|
||||
typedef struct dns_resolver dns_resolver_t;
|
||||
typedef struct dns_rpsdb dns_rpsdb_t;
|
||||
typedef struct dns_qpdata dns_qpdata_t;
|
||||
typedef ISC_LIST(dns_qpdata_t) dns_qpdatalist_t;
|
||||
typedef struct dns_qpnode dns_qpnode_t;
|
||||
typedef uint8_t dns_secalg_t;
|
||||
typedef uint8_t dns_secproto_t;
|
||||
typedef struct dns_signature dns_signature_t;
|
||||
typedef struct dns_slabheader dns_slabheader_t;
|
||||
typedef struct dns_qpnode dns_qpnode_t;
|
||||
typedef uint8_t dns_secalg_t;
|
||||
typedef uint8_t dns_secproto_t;
|
||||
typedef struct dns_signature dns_signature_t;
|
||||
typedef struct dns_slabheader dns_slabheader_t;
|
||||
typedef ISC_LIST(dns_slabheader_t) dns_slabheaderlist_t;
|
||||
typedef struct dns_sortlist_arg dns_sortlist_arg_t;
|
||||
typedef struct dns_ssurule dns_ssurule_t;
|
||||
|
||||
+2
-4
@@ -1784,7 +1784,7 @@ dns_name_dup(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_name_dupwithoffsets(const dns_name_t *source, isc_mem_t *mctx,
|
||||
dns_name_t *target) {
|
||||
/*
|
||||
@@ -1819,8 +1819,6 @@ dns_name_dupwithoffsets(const dns_name_t *source, isc_mem_t *mctx,
|
||||
} else {
|
||||
set_offsets(target, target->offsets, NULL);
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1999,7 +1997,7 @@ dns_name_fromstring(dns_name_t *target, const char *src,
|
||||
}
|
||||
|
||||
if (name != target) {
|
||||
result = dns_name_dupwithoffsets(name, mctx, target);
|
||||
dns_name_dupwithoffsets(name, mctx, target);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1059,7 +1059,7 @@ dns_qpmulti_memusage(dns_qpmulti_t *multi) {
|
||||
|
||||
dns_qp_memusage_t memusage = dns_qp_memusage(qp);
|
||||
|
||||
if (qp->transaction_mode == QP_UPDATE) {
|
||||
if (qp->transaction_mode == QP_UPDATE && qp->usage != NULL) {
|
||||
memusage.bytes -= QP_CHUNK_BYTES;
|
||||
memusage.bytes += qp->usage[qp->bump].used *
|
||||
sizeof(dns_qpnode_t);
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/qp.h>
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* interior node basics
|
||||
|
||||
+552
-1569
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,6 @@
|
||||
|
||||
#include <dns/nsec3.h>
|
||||
#include <dns/qp.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
/*****
|
||||
|
||||
+61
-134
@@ -45,6 +45,7 @@
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/log.h>
|
||||
#include <dns/masterdump.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/nsec.h>
|
||||
#include <dns/nsec3.h>
|
||||
#include <dns/qp.h>
|
||||
@@ -150,8 +151,7 @@ struct qpdb_version {
|
||||
typedef ISC_LIST(qpdb_version_t) qpdb_versionlist_t;
|
||||
|
||||
struct qpdata {
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *name;
|
||||
dns_name_t name;
|
||||
isc_mem_t *mctx;
|
||||
isc_refcount_t references;
|
||||
isc_refcount_t erefs;
|
||||
@@ -235,9 +235,9 @@ static dns_dbmethods_t qpdb_zonemethods;
|
||||
#define qpdata_attach(ptr, ptrp) \
|
||||
qpdata__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
|
||||
#define qpdata_detach(ptrp) qpdata__detach(ptrp, __func__, __FILE__, __LINE__)
|
||||
ISC_REFCOUNT_TRACE_DECL(qpdata);
|
||||
ISC_REFCOUNT_STATIC_TRACE_DECL(qpdata);
|
||||
#else
|
||||
ISC_REFCOUNT_DECL(qpdata);
|
||||
ISC_REFCOUNT_STATIC_DECL(qpdata);
|
||||
#endif
|
||||
|
||||
/* QP trie methods */
|
||||
@@ -501,29 +501,20 @@ free_db_rcu(struct rcu_head *rcu_head) {
|
||||
|
||||
static void
|
||||
free_qpdb(qpzonedb_t *qpdb, bool log) {
|
||||
REQUIRE(qpdb->current_version != NULL || EMPTY(qpdb->open_versions));
|
||||
REQUIRE(qpdb->future_version == NULL);
|
||||
|
||||
if (qpdb->current_version != NULL) {
|
||||
isc_refcount_decrementz(&qpdb->current_version->references);
|
||||
isc_refcount_decrementz(&qpdb->current_version->references);
|
||||
|
||||
isc_refcount_destroy(&qpdb->current_version->references);
|
||||
UNLINK(qpdb->open_versions, qpdb->current_version, link);
|
||||
cds_wfs_destroy(&qpdb->current_version->glue_stack);
|
||||
isc_rwlock_destroy(&qpdb->current_version->rwlock);
|
||||
isc_mem_put(qpdb->common.mctx, qpdb->current_version,
|
||||
sizeof(*qpdb->current_version));
|
||||
}
|
||||
isc_refcount_destroy(&qpdb->current_version->references);
|
||||
UNLINK(qpdb->open_versions, qpdb->current_version, link);
|
||||
cds_wfs_destroy(&qpdb->current_version->glue_stack);
|
||||
isc_rwlock_destroy(&qpdb->current_version->rwlock);
|
||||
isc_mem_put(qpdb->common.mctx, qpdb->current_version,
|
||||
sizeof(*qpdb->current_version));
|
||||
|
||||
if (qpdb->tree != NULL) {
|
||||
dns_qpmulti_destroy(&qpdb->tree);
|
||||
}
|
||||
if (qpdb->nsec != NULL) {
|
||||
dns_qpmulti_destroy(&qpdb->nsec);
|
||||
}
|
||||
if (qpdb->nsec3 != NULL) {
|
||||
dns_qpmulti_destroy(&qpdb->nsec3);
|
||||
}
|
||||
dns_qpmulti_destroy(&qpdb->tree);
|
||||
dns_qpmulti_destroy(&qpdb->nsec);
|
||||
dns_qpmulti_destroy(&qpdb->nsec3);
|
||||
|
||||
if (log) {
|
||||
char buf[DNS_NAME_FORMATSIZE];
|
||||
@@ -606,11 +597,11 @@ static qpdata_t *
|
||||
new_qpdata(qpzonedb_t *qpdb, const dns_name_t *name) {
|
||||
qpdata_t *newdata = isc_mem_get(qpdb->common.mctx, sizeof(*newdata));
|
||||
*newdata = (qpdata_t){
|
||||
.name = DNS_NAME_INITEMPTY,
|
||||
.references = ISC_REFCOUNT_INITIALIZER(1),
|
||||
};
|
||||
newdata->locknum = dns_name_hash(name) % qpdb->node_lock_count;
|
||||
newdata->name = dns_fixedname_initname(&newdata->fn);
|
||||
dns_name_copy(name, newdata->name);
|
||||
dns_name_dupwithoffsets(name, qpdb->common.mctx, &newdata->name);
|
||||
isc_mem_attach(qpdb->common.mctx, &newdata->mctx);
|
||||
|
||||
#if DNS_DB_NODETRACE
|
||||
@@ -705,16 +696,18 @@ dns__qpzone_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
|
||||
/*
|
||||
* Make a copy of the origin name.
|
||||
*/
|
||||
result = dns_name_dupwithoffsets(origin, mctx, &qpdb->common.origin);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
free_qpdb(qpdb, false);
|
||||
return (result);
|
||||
}
|
||||
dns_name_dupwithoffsets(origin, mctx, &qpdb->common.origin);
|
||||
|
||||
dns_qpmulti_create(mctx, &qpmethods, qpdb, &qpdb->tree);
|
||||
dns_qpmulti_create(mctx, &qpmethods, qpdb, &qpdb->nsec);
|
||||
dns_qpmulti_create(mctx, &qpmethods, qpdb, &qpdb->nsec3);
|
||||
|
||||
/*
|
||||
* Version initialization.
|
||||
*/
|
||||
qpdb->current_version = allocate_version(mctx, 1, 1, false);
|
||||
qpdb->current_version->qpdb = qpdb;
|
||||
|
||||
/*
|
||||
* In order to set the node callback bit correctly in zone databases,
|
||||
* we need to know if the node has the origin name of the zone.
|
||||
@@ -756,12 +749,6 @@ dns__qpzone_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Version Initialization.
|
||||
*/
|
||||
qpdb->current_version = allocate_version(mctx, 1, 1, false);
|
||||
qpdb->current_version->qpdb = qpdb;
|
||||
|
||||
/*
|
||||
* Keep the current version in the open list so that list operation
|
||||
* won't happen in normal lookup operations.
|
||||
@@ -1313,10 +1300,8 @@ resigndelete(qpzonedb_t *qpdb, qpdb_version_t *version,
|
||||
isc_heap_delete(qpdb->heaps[HEADERNODE(header)->locknum],
|
||||
header->heap_index);
|
||||
header->heap_index = 0;
|
||||
if (version != NULL) {
|
||||
newref(qpdb, HEADERNODE(header) DNS__DB_FLARG_PASS);
|
||||
ISC_LIST_APPEND(version->resigned_list, header, link);
|
||||
}
|
||||
newref(qpdb, HEADERNODE(header) DNS__DB_FLARG_PASS);
|
||||
ISC_LIST_APPEND(version->resigned_list, header, link);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1839,7 +1824,7 @@ maybe_update_recordsandsize(bool add, qpdb_version_t *version,
|
||||
unsigned char *hdr = (unsigned char *)header;
|
||||
size_t hdrsize = sizeof(*header);
|
||||
|
||||
if (version == NULL || NONEXISTENT(header)) {
|
||||
if (NONEXISTENT(header)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2532,7 +2517,7 @@ getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
|
||||
rdataset DNS__DB_FLARG_PASS);
|
||||
|
||||
if (foundname != NULL) {
|
||||
dns_name_copy(HEADERNODE(header)->name, foundname);
|
||||
dns_name_copy(&HEADERNODE(header)->name, foundname);
|
||||
}
|
||||
|
||||
NODE_UNLOCK(&qpdb->node_locks[locknum].lock, &nlocktype);
|
||||
@@ -2933,7 +2918,7 @@ find_wildcard(qpdb_search_t *search, qpdata_t **nodep,
|
||||
* Construct the wildcard name for this level.
|
||||
*/
|
||||
result = dns_name_concatenate(dns_wildcardname,
|
||||
node->name, wname, NULL);
|
||||
&node->name, wname, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
@@ -3366,7 +3351,7 @@ check_zonecut(qpdata_t *node, void *arg DNS__DB_FLARG) {
|
||||
* is, we need to remember the node name.
|
||||
*/
|
||||
zcname = dns_fixedname_name(&search->zonecut_name);
|
||||
dns_name_copy(node->name, zcname);
|
||||
dns_name_copy(&node->name, zcname);
|
||||
search->copy_name = true;
|
||||
}
|
||||
} else {
|
||||
@@ -3904,7 +3889,7 @@ tree_exit:
|
||||
|
||||
static isc_result_t
|
||||
allrdatasets(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
unsigned int options, isc_stdtime_t now,
|
||||
unsigned int options, isc_stdtime_t now ISC_ATTR_UNUSED,
|
||||
dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpdata_t *node = (qpdata_t *)dbnode;
|
||||
@@ -3913,39 +3898,26 @@ allrdatasets(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
|
||||
iterator = isc_mem_get(qpdb->common.mctx, sizeof(*iterator));
|
||||
|
||||
if ((db->attributes & DNS_DBATTR_CACHE) == 0) {
|
||||
now = 0;
|
||||
if (version == NULL) {
|
||||
currentversion(db,
|
||||
(dns_dbversion_t **)(void *)(&version));
|
||||
} else {
|
||||
INSIST(version->qpdb == qpdb);
|
||||
|
||||
(void)isc_refcount_increment(&version->references);
|
||||
}
|
||||
if (version == NULL) {
|
||||
currentversion(db, (dns_dbversion_t **)(void *)(&version));
|
||||
} else {
|
||||
if (now == 0) {
|
||||
now = isc_stdtime_now();
|
||||
}
|
||||
version = NULL;
|
||||
INSIST(version->qpdb == qpdb);
|
||||
isc_refcount_increment(&version->references);
|
||||
}
|
||||
|
||||
iterator->common.magic = DNS_RDATASETITER_MAGIC;
|
||||
iterator->common.methods = &rdatasetiter_methods;
|
||||
iterator->common.db = db;
|
||||
iterator->common.node = node;
|
||||
iterator->common.version = (dns_dbversion_t *)version;
|
||||
iterator->common.options = options;
|
||||
iterator->common.now = now;
|
||||
iterator = isc_mem_get(qpdb->common.mctx, sizeof(*iterator));
|
||||
*iterator = (qpdb_rdatasetiter_t){
|
||||
.common.methods = &rdatasetiter_methods,
|
||||
.common.db = db,
|
||||
.common.node = node,
|
||||
.common.version = (dns_dbversion_t *)version,
|
||||
.common.options = options,
|
||||
.common.magic = DNS_RDATASETITER_MAGIC,
|
||||
};
|
||||
|
||||
newref(qpdb, node DNS__DB_FLARG_PASS);
|
||||
|
||||
iterator->current = NULL;
|
||||
|
||||
*iteratorp = (dns_rdatasetiter_t *)iterator;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -4485,10 +4457,9 @@ dbiterator_seek(dns_dbiterator_t *iterator,
|
||||
qpdbiter->current, NULL,
|
||||
(void **)&qpdbiter->node, NULL);
|
||||
if (result == DNS_R_PARTIALMATCH) {
|
||||
dns_qpdata_t *node = NULL;
|
||||
tresult = dns_qp_lookup(qpdbiter->nsnap, name, NULL,
|
||||
&qpdbiter->nsec3iter, NULL,
|
||||
(void **)&node, NULL);
|
||||
NULL, NULL);
|
||||
if (tresult == ISC_R_SUCCESS) {
|
||||
qpdbiter->current = &qpdbiter->nsec3iter;
|
||||
result = tresult;
|
||||
@@ -4628,7 +4599,7 @@ dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
|
||||
REQUIRE(qpdbiter->node != NULL);
|
||||
|
||||
if (name != NULL) {
|
||||
dns_name_copy(qpdbiter->node->name, name);
|
||||
dns_name_copy(&qpdbiter->node->name, name);
|
||||
}
|
||||
|
||||
newref(qpdb, node DNS__DB_FLARG_PASS);
|
||||
@@ -4773,8 +4744,8 @@ cleanup:
|
||||
|
||||
static isc_result_t
|
||||
addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
|
||||
dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
|
||||
isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset,
|
||||
unsigned int options, dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
|
||||
isc_result_t result;
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpdata_t *node = (qpdata_t *)dbnode;
|
||||
@@ -4787,7 +4758,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
dns_qp_t *nsec = NULL;
|
||||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
INSIST(version == NULL || version->qpdb == qpdb);
|
||||
INSIST(version->qpdb == qpdb);
|
||||
|
||||
/*
|
||||
* SOA records are only allowed at top of zone.
|
||||
@@ -4803,33 +4774,24 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
rdataset->type != dns_rdatatype_nsec3 &&
|
||||
rdataset->covers != dns_rdatatype_nsec3)));
|
||||
|
||||
if (version == NULL) {
|
||||
if (now == 0) {
|
||||
now = isc_stdtime_now();
|
||||
}
|
||||
} else {
|
||||
now = 0;
|
||||
}
|
||||
|
||||
result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx,
|
||||
®ion, sizeof(dns_slabheader_t));
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
dns_name_copy(node->name, name);
|
||||
dns_name_copy(&node->name, name);
|
||||
dns_rdataset_getownercase(rdataset, name);
|
||||
|
||||
newheader = (dns_slabheader_t *)region.base;
|
||||
*newheader = (dns_slabheader_t){
|
||||
.type = DNS_TYPEPAIR_VALUE(rdataset->type, rdataset->covers),
|
||||
.trust = rdataset->trust,
|
||||
.last_used = now,
|
||||
.node = node,
|
||||
};
|
||||
|
||||
dns_slabheader_reset(newheader, db, node);
|
||||
newheader->ttl = rdataset->ttl + now;
|
||||
newheader->ttl = rdataset->ttl;
|
||||
if (rdataset->ttl == 0U) {
|
||||
DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_ZEROTTL);
|
||||
}
|
||||
@@ -4837,7 +4799,6 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
atomic_fetch_add_relaxed(&init_count, 1));
|
||||
if (version != NULL) {
|
||||
newheader->serial = version->serial;
|
||||
now = 0;
|
||||
|
||||
if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
|
||||
DNS_SLABHEADER_SETATTR(newheader,
|
||||
@@ -4908,7 +4869,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = add(qpdb, node, name, version, newheader, options,
|
||||
false, addedrdataset, now DNS__DB_FLARG_PASS);
|
||||
false, addedrdataset, 0 DNS__DB_FLARG_PASS);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4927,14 +4888,6 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
dns_qpmulti_commit(qpdb->nsec, &nsec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the zone's secure status. If version is non-NULL
|
||||
* this is deferred until closeversion() is called.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS && version == NULL) {
|
||||
setsecure(db, version, qpdb->origin);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
@@ -4965,7 +4918,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
rdataset->type != dns_rdatatype_nsec3 &&
|
||||
rdataset->covers != dns_rdatatype_nsec3)));
|
||||
|
||||
dns_name_copy(node->name, nodename);
|
||||
dns_name_copy(&node->name, nodename);
|
||||
result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx,
|
||||
®ion, sizeof(dns_slabheader_t));
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
@@ -4983,7 +4936,6 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
newheader->closest = NULL;
|
||||
atomic_init(&newheader->count,
|
||||
atomic_fetch_add_relaxed(&init_count, 1));
|
||||
newheader->last_used = 0;
|
||||
newheader->node = node;
|
||||
newheader->db = (dns_db_t *)qpdb;
|
||||
if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
|
||||
@@ -5124,18 +5076,6 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
|
||||
unlock:
|
||||
NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype);
|
||||
|
||||
/*
|
||||
* Update the zone's secure status. If version is non-NULL
|
||||
* this is deferred until closeversion() is called.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS && version == NULL) {
|
||||
RWLOCK(&qpdb->lock, isc_rwlocktype_read);
|
||||
version = qpdb->current_version;
|
||||
RWUNLOCK(&qpdb->lock, isc_rwlocktype_read);
|
||||
setsecure(db, version, qpdb->origin);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
@@ -5152,7 +5092,7 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
||||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
INSIST(version == NULL || version->qpdb == qpdb);
|
||||
REQUIRE(version != NULL && version->qpdb == qpdb);
|
||||
|
||||
if (type == dns_rdatatype_any) {
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
@@ -5165,28 +5105,14 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
newheader->type = DNS_TYPEPAIR_VALUE(type, covers);
|
||||
newheader->ttl = 0;
|
||||
atomic_init(&newheader->attributes, DNS_SLABHEADERATTR_NONEXISTENT);
|
||||
if (version != NULL) {
|
||||
newheader->serial = version->serial;
|
||||
}
|
||||
newheader->serial = version->serial;
|
||||
|
||||
dns_name_copy(node->name, nodename);
|
||||
dns_name_copy(&node->name, nodename);
|
||||
|
||||
NODE_WRLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype);
|
||||
result = add(qpdb, node, nodename, version, newheader, DNS_DBADD_FORCE,
|
||||
false, NULL, 0 DNS__DB_FLARG_PASS);
|
||||
NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype);
|
||||
|
||||
/*
|
||||
* Update the zone's secure status. If version is non-NULL
|
||||
* this is deferred until closeversion() is called.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS && version == NULL) {
|
||||
RWLOCK(&qpdb->lock, isc_rwlocktype_read);
|
||||
version = qpdb->current_version;
|
||||
RWUNLOCK(&qpdb->lock, isc_rwlocktype_read);
|
||||
setsecure(db, version, qpdb->origin);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
@@ -5201,7 +5127,7 @@ nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) {
|
||||
REQUIRE(name != NULL);
|
||||
|
||||
NODE_RDLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
|
||||
dns_name_copy(qpnode->name, name);
|
||||
dns_name_copy(&qpnode->name, name);
|
||||
NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
@@ -5440,7 +5366,7 @@ newglue(qpzonedb_t *qpdb, qpdb_version_t *version, qpdata_t *node,
|
||||
* determining which NS records in the delegation are
|
||||
* in-bailiwick).
|
||||
*/
|
||||
dns_name_copy(node->name, ctx.nodename);
|
||||
dns_name_copy(&node->name, ctx.nodename);
|
||||
|
||||
(void)dns_rdataset_additionaldata(rdataset, dns_rootname,
|
||||
glue_nsdname_cb, &ctx);
|
||||
@@ -5555,13 +5481,14 @@ destroy_qpdata(qpdata_t *node) {
|
||||
dns_slabheader_destroy(¤t);
|
||||
}
|
||||
|
||||
dns_name_free(&node->name, node->mctx);
|
||||
isc_mem_putanddetach(&node->mctx, node, sizeof(qpdata_t));
|
||||
}
|
||||
|
||||
#if DNS_DB_NODETRACE
|
||||
ISC_REFCOUNT_TRACE_IMPL(qpdata, destroy_qpdata);
|
||||
ISC_REFCOUNT_STATIC_TRACE_IMPL(qpdata, destroy_qpdata);
|
||||
#else
|
||||
ISC_REFCOUNT_IMPL(qpdata, destroy_qpdata);
|
||||
ISC_REFCOUNT_STATIC_IMPL(qpdata, destroy_qpdata);
|
||||
#endif
|
||||
|
||||
static void
|
||||
@@ -5582,7 +5509,7 @@ static size_t
|
||||
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
|
||||
uint32_t ival ISC_ATTR_UNUSED) {
|
||||
qpdata_t *data = pval;
|
||||
return (dns_qpkey_fromname(key, data->name));
|
||||
return (dns_qpkey_fromname(key, &data->name));
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
-2950
File diff suppressed because it is too large
Load Diff
-4969
File diff suppressed because it is too large
Load Diff
@@ -1,480 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <isc/heap.h>
|
||||
#include <isc/lang.h>
|
||||
#include <isc/urcu.h>
|
||||
|
||||
#include <dns/nsec3.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
/*%
|
||||
* Note that "impmagic" is not the first four bytes of the struct, so
|
||||
* ISC_MAGIC_VALID cannot be used.
|
||||
*/
|
||||
#define RBTDB_MAGIC ISC_MAGIC('R', 'B', 'D', '4')
|
||||
#define VALID_RBTDB(rbtdb) \
|
||||
((rbtdb) != NULL && (rbtdb)->common.impmagic == RBTDB_MAGIC)
|
||||
|
||||
#define RBTDB_HEADERNODE(h) ((dns_rbtnode_t *)((h)->node))
|
||||
|
||||
/*
|
||||
* Allow clients with a virtual time of up to 5 minutes in the past to see
|
||||
* records that would have otherwise have expired.
|
||||
*/
|
||||
#define RBTDB_VIRTUAL 300
|
||||
|
||||
/*****
|
||||
***** Module Info
|
||||
*****/
|
||||
|
||||
/*! \file
|
||||
* \brief
|
||||
* DNS Red-Black Tree DB Implementation
|
||||
*/
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
typedef struct rbtdb_changed {
|
||||
dns_rbtnode_t *node;
|
||||
bool dirty;
|
||||
ISC_LINK(struct rbtdb_changed) link;
|
||||
} rbtdb_changed_t;
|
||||
|
||||
typedef ISC_LIST(rbtdb_changed_t) rbtdb_changedlist_t;
|
||||
|
||||
struct dns_rbtdb_version {
|
||||
/* Not locked */
|
||||
uint32_t serial;
|
||||
dns_rbtdb_t *rbtdb;
|
||||
/*
|
||||
* Protected in the refcount routines.
|
||||
* XXXJT: should we change the lock policy based on the refcount
|
||||
* performance?
|
||||
*/
|
||||
isc_refcount_t references;
|
||||
/* Locked by database lock. */
|
||||
bool writer;
|
||||
bool commit_ok;
|
||||
rbtdb_changedlist_t changed_list;
|
||||
dns_slabheaderlist_t resigned_list;
|
||||
ISC_LINK(dns_rbtdb_version_t) link;
|
||||
bool secure;
|
||||
bool havensec3;
|
||||
/* NSEC3 parameters */
|
||||
dns_hash_t hash;
|
||||
uint8_t flags;
|
||||
uint16_t iterations;
|
||||
uint8_t salt_length;
|
||||
unsigned char salt[DNS_NSEC3_SALTSIZE];
|
||||
|
||||
/*
|
||||
* records and xfrsize are covered by rwlock.
|
||||
*/
|
||||
isc_rwlock_t rwlock;
|
||||
uint64_t records;
|
||||
uint64_t xfrsize;
|
||||
|
||||
struct cds_wfs_stack glue_stack;
|
||||
};
|
||||
|
||||
typedef ISC_LIST(dns_rbtdb_version_t) rbtdb_versionlist_t;
|
||||
|
||||
struct dns_rbtdb {
|
||||
/* Unlocked. */
|
||||
dns_db_t common;
|
||||
/* Locks the data in this struct */
|
||||
isc_rwlock_t lock;
|
||||
/* Locks the tree structure (prevents nodes appearing/disappearing) */
|
||||
isc_rwlock_t tree_lock;
|
||||
/* Locks for individual tree nodes */
|
||||
unsigned int node_lock_count;
|
||||
db_nodelock_t *node_locks;
|
||||
dns_rbtnode_t *origin_node;
|
||||
dns_rbtnode_t *nsec3_origin_node;
|
||||
dns_stats_t *rrsetstats; /* cache DB only */
|
||||
isc_stats_t *cachestats; /* cache DB only */
|
||||
isc_stats_t *gluecachestats; /* zone DB only */
|
||||
/* Locked by lock. */
|
||||
unsigned int active;
|
||||
unsigned int attributes;
|
||||
uint32_t current_serial;
|
||||
uint32_t least_serial;
|
||||
uint32_t next_serial;
|
||||
dns_rbtdb_version_t *current_version;
|
||||
dns_rbtdb_version_t *future_version;
|
||||
rbtdb_versionlist_t open_versions;
|
||||
isc_loop_t *loop;
|
||||
dns_dbnode_t *soanode;
|
||||
dns_dbnode_t *nsnode;
|
||||
|
||||
/*
|
||||
* The time after a failed lookup, where stale answers from cache
|
||||
* may be used directly in a DNS response without attempting a
|
||||
* new iterative lookup.
|
||||
*/
|
||||
uint32_t serve_stale_refresh;
|
||||
|
||||
/*
|
||||
* This is an array of linked lists used to implement the LRU cache.
|
||||
* There will be node_lock_count linked lists here. Nodes in bucket 1
|
||||
* will be placed on the linked list lru[1].
|
||||
*/
|
||||
dns_slabheaderlist_t *lru;
|
||||
|
||||
/*
|
||||
* Start point % node_lock_count for next LRU cleanup.
|
||||
*/
|
||||
atomic_uint lru_sweep;
|
||||
|
||||
/*
|
||||
* When performing LRU cleaning limit cleaning to headers that were
|
||||
* last used at or before this.
|
||||
*/
|
||||
_Atomic(isc_stdtime_t) last_used;
|
||||
|
||||
/*%
|
||||
* Temporary storage for stale cache nodes and dynamically deleted
|
||||
* nodes that await being cleaned up.
|
||||
*/
|
||||
dns_rbtnodelist_t *deadnodes;
|
||||
|
||||
/*
|
||||
* Heaps. These are used for TTL based expiry in a cache,
|
||||
* or for zone resigning in a zone DB. hmctx is the memory
|
||||
* context to use for the heap (which differs from the main
|
||||
* database memory context in the case of a cache).
|
||||
*/
|
||||
isc_mem_t *hmctx;
|
||||
isc_heap_t **heaps;
|
||||
isc_heapcompare_t sooner;
|
||||
|
||||
/* Locked by tree_lock. */
|
||||
dns_rbt_t *tree;
|
||||
dns_rbt_t *nsec;
|
||||
dns_rbt_t *nsec3;
|
||||
|
||||
/* Unlocked */
|
||||
unsigned int quantum;
|
||||
};
|
||||
|
||||
/*%
|
||||
* Search Context
|
||||
*/
|
||||
typedef struct {
|
||||
dns_rbtdb_t *rbtdb;
|
||||
dns_rbtdb_version_t *rbtversion;
|
||||
uint32_t serial;
|
||||
unsigned int options;
|
||||
dns_rbtnodechain_t chain;
|
||||
bool copy_name;
|
||||
bool need_cleanup;
|
||||
bool wild;
|
||||
dns_rbtnode_t *zonecut;
|
||||
dns_slabheader_t *zonecut_header;
|
||||
dns_slabheader_t *zonecut_sigheader;
|
||||
dns_fixedname_t zonecut_name;
|
||||
isc_stdtime_t now;
|
||||
} rbtdb_search_t;
|
||||
|
||||
/*%
|
||||
* Load Context
|
||||
*/
|
||||
typedef struct {
|
||||
dns_db_t *db;
|
||||
isc_stdtime_t now;
|
||||
} rbtdb_load_t;
|
||||
|
||||
/*%
|
||||
* Prune context
|
||||
*/
|
||||
typedef struct {
|
||||
dns_db_t *db;
|
||||
dns_rbtnode_t *node;
|
||||
} rbtdb_prune_t;
|
||||
|
||||
extern dns_dbmethods_t dns__rbtdb_zonemethods;
|
||||
extern dns_dbmethods_t dns__rbtdb_cachemethods;
|
||||
|
||||
/*
|
||||
* Common DB implementation methods shared by both cache and zone RBT
|
||||
* databases:
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns__rbtdb_create(isc_mem_t *mctx, const dns_name_t *base, dns_dbtype_t type,
|
||||
dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
|
||||
void *driverarg, dns_db_t **dbp);
|
||||
/*%<
|
||||
* Create a new database of type "rbt". Called via dns_db_create();
|
||||
* see documentation for that function for more details.
|
||||
*
|
||||
* If argv[0] is set, it points to a valid memory context to be used for
|
||||
* allocation of heap memory. Generally this is used for cache databases
|
||||
* only.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* \li argc == 0 or argv[0] is a valid memory context.
|
||||
*/
|
||||
|
||||
void
|
||||
dns__rbtdb_destroy(dns_db_t *arg);
|
||||
/*%<
|
||||
* Implement dns_db_destroy() for RBT databases, see documentation
|
||||
* for that function for more details.
|
||||
*/
|
||||
|
||||
void
|
||||
dns__rbtdb_currentversion(dns_db_t *db, dns_dbversion_t **versionp);
|
||||
isc_result_t
|
||||
dns__rbtdb_newversion(dns_db_t *db, dns_dbversion_t **versionp);
|
||||
void
|
||||
dns__rbtdb_attachversion(dns_db_t *db, dns_dbversion_t *source,
|
||||
dns_dbversion_t **targetp);
|
||||
void
|
||||
dns__rbtdb_closeversion(dns_db_t *db, dns_dbversion_t **versionp,
|
||||
bool commit DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Implement the dns_db_currentversion(), _newversion(),
|
||||
* _attachversion() and _closeversion() methods for RBT databases;
|
||||
* see documentation of those functions for more details.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns__rbtdb_findnode(dns_db_t *db, const dns_name_t *name, bool create,
|
||||
dns_dbnode_t **nodep DNS__DB_FLARG);
|
||||
isc_result_t
|
||||
dns__rbtdb_findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree,
|
||||
const dns_name_t *name, bool create,
|
||||
dns_dbnode_t **nodep DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Implement the dns_db_findnode() and _findnodeintree() methods for
|
||||
* RBT databases; see documentation of those functions for more details.
|
||||
*/
|
||||
|
||||
void
|
||||
dns__rbtdb_attachnode(dns_db_t *db, dns_dbnode_t *source,
|
||||
dns_dbnode_t **targetp DNS__DB_FLARG);
|
||||
void
|
||||
dns__rbtdb_detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Implement the dns_db_attachnode() and _detachnode() methods for
|
||||
* RBT databases; see documentation of those functions for more details.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns__rbtdb_createiterator(dns_db_t *db, unsigned int options,
|
||||
dns_dbiterator_t **iteratorp);
|
||||
/*%<
|
||||
* Implement dns_db_createiterator() for RBT databases; see documentation of
|
||||
* that function for more details.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns__rbtdb_allrdatasets(dns_db_t *db, dns_dbnode_t *node,
|
||||
dns_dbversion_t *version, unsigned int options,
|
||||
isc_stdtime_t now,
|
||||
dns_rdatasetiter_t **iteratorp DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Implement dns_db_allrdatasets() for RBT databases; see documentation of
|
||||
* that function for more details.
|
||||
*/
|
||||
isc_result_t
|
||||
dns__rbtdb_addrdataset(dns_db_t *db, dns_dbnode_t *node,
|
||||
dns_dbversion_t *version, isc_stdtime_t now,
|
||||
dns_rdataset_t *rdataset, unsigned int options,
|
||||
dns_rdataset_t *addedrdataset DNS__DB_FLARG);
|
||||
isc_result_t
|
||||
dns__rbtdb_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
|
||||
dns_dbversion_t *version, dns_rdataset_t *rdataset,
|
||||
unsigned int options,
|
||||
dns_rdataset_t *newrdataset DNS__DB_FLARG);
|
||||
isc_result_t
|
||||
dns__rbtdb_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
|
||||
dns_dbversion_t *version, dns_rdatatype_t type,
|
||||
dns_rdatatype_t covers DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Implement the dns_db_addrdataset(), _subtractrdataset() and
|
||||
* _deleterdataset() methods for RBT databases; see documentation of
|
||||
* those functions for more details.
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
dns__rbtdb_nodecount(dns_db_t *db, dns_dbtree_t tree);
|
||||
/*%<
|
||||
* Implement dns_db_nodecount() for RBT databases; see documentation of
|
||||
* that function for more details.
|
||||
*/
|
||||
|
||||
void
|
||||
dns__rbtdb_setloop(dns_db_t *db, isc_loop_t *loop);
|
||||
/*%<
|
||||
* Implement dns_db_setloop() for RBT databases; see documentation of
|
||||
* that function for more details.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns__rbtdb_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Implement dns_db_getoriginnode() for RBT databases; see documentation of
|
||||
* that function for more details.
|
||||
*/
|
||||
|
||||
void
|
||||
dns__rbtdb_deletedata(dns_db_t *db ISC_ATTR_UNUSED,
|
||||
dns_dbnode_t *node ISC_ATTR_UNUSED, void *data);
|
||||
/*%<
|
||||
* Implement dns_db_deletedata() for RBT databases; see documentation of
|
||||
* that function for more details.
|
||||
*/
|
||||
|
||||
void
|
||||
dns__rbtdb_locknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type);
|
||||
void
|
||||
dns__rbtdb_unlocknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type);
|
||||
/*%<
|
||||
* Implement the dns_db_locknode() and _unlocknode() methods for
|
||||
* RBT databases; see documentation of those functions for more details.
|
||||
*/
|
||||
|
||||
/*%
|
||||
* Functions used for the RBT implementation which are defined and
|
||||
* used in rbtdb.c but may also be called from rbt-zonedb.c or
|
||||
* rbt-cachedb.c:
|
||||
*/
|
||||
void
|
||||
dns__rbtdb_bindrdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
||||
dns_slabheader_t *header, isc_stdtime_t now,
|
||||
isc_rwlocktype_t locktype,
|
||||
dns_rdataset_t *rdataset DNS__DB_FLARG);
|
||||
|
||||
isc_result_t
|
||||
dns__rbtdb_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name);
|
||||
|
||||
void
|
||||
dns__rbtdb_freeglue(dns_glue_t *glue_list);
|
||||
|
||||
void
|
||||
dns__rbtdb_newref(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
||||
isc_rwlocktype_t locktype DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Increment the reference counter to a node in an RBT database.
|
||||
* If the caller holds a node lock then its lock type is specified
|
||||
* as 'locktype'. If the node is write-locked, then the node can
|
||||
* be removed from the dead nodes list. If not, the list can be
|
||||
* cleaned up later.
|
||||
*/
|
||||
|
||||
bool
|
||||
dns__rbtdb_decref(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
||||
uint32_t least_serial, isc_rwlocktype_t *nlocktypep,
|
||||
isc_rwlocktype_t *tlocktypep, bool tryupgrade,
|
||||
bool pruning DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Decrement the reference counter to a node in an RBT database.
|
||||
* 'nlocktypep' and 'tlocktypep' are pointers to the current status
|
||||
* of the node lock and tree lock.
|
||||
*
|
||||
* If references go to 0, the node will be cleaned up, which may
|
||||
* necessitate upgrading the locks.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns__rbtdb_add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
|
||||
const dns_name_t *nodename, dns_rbtdb_version_t *rbtversion,
|
||||
dns_slabheader_t *newheader, unsigned int options, bool loading,
|
||||
dns_rdataset_t *addedrdataset, isc_stdtime_t now DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Add a slab header 'newheader' to a node in an RBT database.
|
||||
* The caller must have the node write-locked.
|
||||
*/
|
||||
|
||||
void
|
||||
dns__rbtdb_setsecure(dns_db_t *db, dns_rbtdb_version_t *version,
|
||||
dns_dbnode_t *origin);
|
||||
/*%<
|
||||
* Update the secure status for an RBT database version 'version'.
|
||||
* The version will be marked secure if it is fully signed and
|
||||
* and contains a complete NSEC/NSEC3 chain.
|
||||
*/
|
||||
|
||||
void
|
||||
dns__rbtdb_mark(dns_slabheader_t *header, uint_least16_t flag);
|
||||
/*%<
|
||||
* Set attribute 'flag' in a slab header 'header' - for example,
|
||||
* DNS_SLABHEADERATTR_STALE or DNS_SLABHEADERATTR_ANCIENT - and,
|
||||
* in a cache database, update the rrset stats accordingly.
|
||||
*/
|
||||
|
||||
void
|
||||
dns__rbtdb_setttl(dns_slabheader_t *header, dns_ttl_t newttl);
|
||||
/*%<
|
||||
* Set the TTL in a slab header 'header'. In a cache database,
|
||||
* also update the TTL heap accordingly.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions specific to zone databases that are also called from rbtdb.c.
|
||||
*/
|
||||
void
|
||||
dns__zonerbt_resigninsert(dns_rbtdb_t *rbtdb, int idx,
|
||||
dns_slabheader_t *newheader);
|
||||
void
|
||||
dns__zonerbt_resigndelete(dns_rbtdb_t *rbtdb, dns_rbtdb_version_t *version,
|
||||
dns_slabheader_t *header DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Insert/delete a node from the zone database's resigning heap.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns__zonerbt_wildcardmagic(dns_rbtdb_t *rbtdb, const dns_name_t *name,
|
||||
bool lock);
|
||||
/*%<
|
||||
* Add the necessary magic for the wildcard name 'name'
|
||||
* to be found in 'rbtdb'.
|
||||
*
|
||||
* In order for wildcard matching to work correctly in
|
||||
* zone_find(), we must ensure that a node for the wildcarding
|
||||
* level exists in the database, and has its 'find_callback'
|
||||
* and 'wild' bits set.
|
||||
*
|
||||
* E.g. if the wildcard name is "*.sub.example." then we
|
||||
* must ensure that "sub.example." exists and is marked as
|
||||
* a wildcard level.
|
||||
*
|
||||
* The tree must be write-locked.
|
||||
*/
|
||||
isc_result_t
|
||||
dns__zonerbt_addwildcards(dns_rbtdb_t *rbtdb, const dns_name_t *name,
|
||||
bool lock);
|
||||
/*%<
|
||||
* If 'name' is or contains a wildcard name, create a node for it in the
|
||||
* database. The tree must be write-locked.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Cache-specific functions that are called from rbtdb.c
|
||||
*/
|
||||
void
|
||||
dns__cacherbt_expireheader(dns_slabheader_t *header,
|
||||
isc_rwlocktype_t *tlocktypep,
|
||||
dns_expire_t reason DNS__DB_FLARG);
|
||||
void
|
||||
dns__cacherbt_overmem(dns_rbtdb_t *rbtdb, dns_slabheader_t *newheader,
|
||||
isc_rwlocktype_t *tlocktypep DNS__DB_FLARG);
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
+1
-4
@@ -1093,7 +1093,6 @@ dns_slabheader_copycase(dns_slabheader_t *dest, dns_slabheader_t *src) {
|
||||
|
||||
void
|
||||
dns_slabheader_reset(dns_slabheader_t *h, dns_db_t *db, dns_dbnode_t *node) {
|
||||
ISC_LINK_INIT(h, link);
|
||||
h->heap_index = 0;
|
||||
h->heap = NULL;
|
||||
h->glue_list = NULL;
|
||||
@@ -1115,9 +1114,7 @@ dns_slabheader_new(dns_db_t *db, dns_dbnode_t *node) {
|
||||
dns_slabheader_t *h = NULL;
|
||||
|
||||
h = isc_mem_get(db->mctx, sizeof(*h));
|
||||
*h = (dns_slabheader_t){
|
||||
.link = ISC_LINK_INITIALIZER,
|
||||
};
|
||||
*h = (dns_slabheader_t){ 0 };
|
||||
dns_slabheader_reset(h, db, node);
|
||||
return (h);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
#include <dns/nsec3.h>
|
||||
#include <dns/opcode.h>
|
||||
#include <dns/peer.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/rcode.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/rdataclass.h>
|
||||
|
||||
+5
-5
@@ -174,8 +174,7 @@ struct dns_rpz_nm_zbits {
|
||||
*/
|
||||
typedef struct nmdata nmdata_t;
|
||||
struct nmdata {
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *name;
|
||||
dns_name_t name;
|
||||
isc_mem_t *mctx;
|
||||
isc_refcount_t references;
|
||||
dns_rpz_nm_zbits_t set;
|
||||
@@ -1408,10 +1407,10 @@ new_nmdata(isc_mem_t *mctx, const dns_name_t *name, const nmdata_t *data) {
|
||||
*newdata = (nmdata_t){
|
||||
.set = data->set,
|
||||
.wild = data->wild,
|
||||
.name = DNS_NAME_INITEMPTY,
|
||||
.references = ISC_REFCOUNT_INITIALIZER(1),
|
||||
};
|
||||
newdata->name = dns_fixedname_initname(&newdata->fn);
|
||||
dns_name_copy(name, newdata->name);
|
||||
dns_name_dup(name, mctx, &newdata->name);
|
||||
isc_mem_attach(mctx, &newdata->mctx);
|
||||
|
||||
#ifdef DNS_RPZ_TRACE
|
||||
@@ -2683,6 +2682,7 @@ dns_rpz_decode_cname(dns_rpz_zone_t *rpz, dns_rdataset_t *rdataset,
|
||||
|
||||
static void
|
||||
destroy_nmdata(nmdata_t *data) {
|
||||
dns_name_free(&data->name, data->mctx);
|
||||
isc_mem_putanddetach(&data->mctx, data, sizeof(nmdata_t));
|
||||
}
|
||||
|
||||
@@ -2710,7 +2710,7 @@ static size_t
|
||||
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
|
||||
uint32_t ival ISC_ATTR_UNUSED) {
|
||||
nmdata_t *data = pval;
|
||||
return (dns_qpkey_fromname(key, data->name));
|
||||
return (dns_qpkey_fromname(key, &data->name));
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+2
-9
@@ -1357,7 +1357,6 @@ static isc_result_t
|
||||
dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
|
||||
const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
dns_db_t **dbp) {
|
||||
isc_result_t result;
|
||||
dns_sdlz_db_t *sdlzdb;
|
||||
dns_sdlzimplementation_t *imp;
|
||||
|
||||
@@ -1379,10 +1378,7 @@ dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
|
||||
|
||||
/* initialize and set origin */
|
||||
dns_name_init(&sdlzdb->common.origin, NULL);
|
||||
result = dns_name_dupwithoffsets(name, mctx, &sdlzdb->common.origin);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto mem_cleanup;
|
||||
}
|
||||
dns_name_dup(name, mctx, &sdlzdb->common.origin);
|
||||
|
||||
isc_refcount_init(&sdlzdb->common.references, 1);
|
||||
|
||||
@@ -1394,10 +1390,7 @@ dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
|
||||
sdlzdb->common.impmagic = SDLZDB_MAGIC;
|
||||
*dbp = (dns_db_t *)sdlzdb;
|
||||
|
||||
return (result);
|
||||
mem_cleanup:
|
||||
isc_mem_put(mctx, sdlzdb, sizeof(*sdlzdb));
|
||||
return (result);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
#include <dns/nta.h>
|
||||
#include <dns/order.h>
|
||||
#include <dns/peer.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/rdataset.h>
|
||||
#include <dns/request.h>
|
||||
#include <dns/resolver.h>
|
||||
|
||||
@@ -119,19 +119,26 @@ typedef atomic_uint_fast32_t isc_refcount_t;
|
||||
ISC_INSIST(_refs > 0); \
|
||||
} while (0)
|
||||
|
||||
#define ISC_REFCOUNT_TRACE_DECL(name) \
|
||||
name##_t *name##__ref(name##_t *ptr, const char *func, \
|
||||
const char *file, unsigned int line); \
|
||||
void name##__unref(name##_t *ptr, const char *func, const char *file, \
|
||||
unsigned int line); \
|
||||
void name##__attach(name##_t *ptr, name##_t **ptrp, const char *func, \
|
||||
const char *file, unsigned int line); \
|
||||
void name##__detach(name##_t **ptrp, const char *func, \
|
||||
const char *file, unsigned int line)
|
||||
#define ISC__REFCOUNT_TRACE_DECL(name, stat) \
|
||||
stat name##_t *name##__ref(name##_t *ptr, const char *func, \
|
||||
const char *file, unsigned int line); \
|
||||
stat void name##__unref(name##_t *ptr, const char *func, \
|
||||
const char *file, unsigned int line); \
|
||||
stat void name##__attach(name##_t *ptr, name##_t **ptrp, \
|
||||
const char *func, const char *file, \
|
||||
unsigned int line); \
|
||||
stat name##__detach(name##_t **ptrp, const char *func, \
|
||||
const char *file, unsigned int line)
|
||||
|
||||
#define ISC_REFCOUNT_TRACE_IMPL(name, destroy) \
|
||||
name##_t *name##__ref(name##_t *ptr, const char *func, \
|
||||
const char *file, unsigned int line) { \
|
||||
#define ISC_REFCOUNT_BLANK
|
||||
#define ISC_REFCOUNT_TRACE_DECL(name) \
|
||||
ISC__REFCOUNT_TRACE_DECL(name, ISC_REFCOUNT_BLANK)
|
||||
#define ISC_REFCOUNT_STATIC_TRACE_DECL(name) \
|
||||
ISC__REFCOUNT_TRACE_DECL(name, static inline)
|
||||
|
||||
#define ISC__REFCOUNT_TRACE_IMPL(name, destroy, stat) \
|
||||
stat name##_t *name##__ref(name##_t *ptr, const char *func, \
|
||||
const char *file, unsigned int line) { \
|
||||
REQUIRE(ptr != NULL); \
|
||||
uint_fast32_t refs = \
|
||||
isc_refcount_increment(&ptr->references) + 1; \
|
||||
@@ -141,8 +148,8 @@ typedef atomic_uint_fast32_t isc_refcount_t;
|
||||
return (ptr); \
|
||||
} \
|
||||
\
|
||||
void name##__unref(name##_t *ptr, const char *func, const char *file, \
|
||||
unsigned int line) { \
|
||||
stat void name##__unref(name##_t *ptr, const char *func, \
|
||||
const char *file, unsigned int line) { \
|
||||
REQUIRE(ptr != NULL); \
|
||||
uint_fast32_t refs = \
|
||||
isc_refcount_decrement(&ptr->references) - 1; \
|
||||
@@ -154,8 +161,9 @@ typedef atomic_uint_fast32_t isc_refcount_t;
|
||||
"%s:%s:%s:%u:t%u:%p->references = %" PRIuFAST32 "\n", \
|
||||
__func__, func, file, line, isc_tid(), ptr, refs); \
|
||||
} \
|
||||
void name##__attach(name##_t *ptr, name##_t **ptrp, const char *func, \
|
||||
const char *file, unsigned int line) { \
|
||||
stat void name##__attach(name##_t *ptr, name##_t **ptrp, \
|
||||
const char *func, const char *file, \
|
||||
unsigned int line) { \
|
||||
REQUIRE(ptrp != NULL && *ptrp == NULL); \
|
||||
uint_fast32_t refs = \
|
||||
isc_refcount_increment(&ptr->references) + 1; \
|
||||
@@ -165,8 +173,8 @@ typedef atomic_uint_fast32_t isc_refcount_t;
|
||||
*ptrp = ptr; \
|
||||
} \
|
||||
\
|
||||
void name##__detach(name##_t **ptrp, const char *func, \
|
||||
const char *file, unsigned int line) { \
|
||||
stat void name##__detach(name##_t **ptrp, const char *func, \
|
||||
const char *file, unsigned int line) { \
|
||||
REQUIRE(ptrp != NULL && *ptrp != NULL); \
|
||||
name##_t *ptr = *ptrp; \
|
||||
*ptrp = NULL; \
|
||||
@@ -181,37 +189,50 @@ typedef atomic_uint_fast32_t isc_refcount_t;
|
||||
__func__, func, file, line, isc_tid(), ptr, refs); \
|
||||
}
|
||||
|
||||
#define ISC_REFCOUNT_DECL(name) \
|
||||
name##_t *name##_ref(name##_t *ptr); \
|
||||
void name##_unref(name##_t *ptr); \
|
||||
void name##_attach(name##_t *ptr, name##_t **ptrp); \
|
||||
void name##_detach(name##_t **ptrp)
|
||||
#define ISC_REFCOUNT_TRACE_IMPL(name, destroy) \
|
||||
ISC__REFCOUNT_TRACE_DECL(name, destroy, ISC_REFCOUNT_BLANK)
|
||||
#define ISC_REFCOUNT_STATIC_TRACE_IMPL(name, destroy) \
|
||||
ISC__REFCOUNT_TRACE_DECL(name, destroy, static inline)
|
||||
|
||||
#define ISC_REFCOUNT_IMPL(name, destroy) \
|
||||
name##_t *name##_ref(name##_t *ptr) { \
|
||||
#define ISC__REFCOUNT_DECL(name, stat) \
|
||||
stat name##_t *name##_ref(name##_t *ptr); \
|
||||
stat void name##_unref(name##_t *ptr); \
|
||||
stat void name##_attach(name##_t *ptr, name##_t **ptrp); \
|
||||
stat void name##_detach(name##_t **ptrp)
|
||||
|
||||
#define ISC_REFCOUNT_DECL(name) ISC__REFCOUNT_DECL(name, ISC_REFCOUNT_BLANK)
|
||||
#define ISC_REFCOUNT_STATIC_DECL(name) ISC__REFCOUNT_DECL(name, static inline)
|
||||
|
||||
#define ISC__REFCOUNT_IMPL(name, destroy, stat) \
|
||||
stat name##_t *name##_ref(name##_t *ptr) { \
|
||||
REQUIRE(ptr != NULL); \
|
||||
isc_refcount_increment(&ptr->references); \
|
||||
return (ptr); \
|
||||
} \
|
||||
\
|
||||
void name##_unref(name##_t *ptr) { \
|
||||
stat void name##_unref(name##_t *ptr) { \
|
||||
REQUIRE(ptr != NULL); \
|
||||
if (isc_refcount_decrement(&ptr->references) == 1) { \
|
||||
isc_refcount_destroy(&ptr->references); \
|
||||
destroy(ptr); \
|
||||
} \
|
||||
} \
|
||||
void name##_attach(name##_t *ptr, name##_t **ptrp) { \
|
||||
stat void name##_attach(name##_t *ptr, name##_t **ptrp) { \
|
||||
REQUIRE(ptrp != NULL && *ptrp == NULL); \
|
||||
name##_ref(ptr); \
|
||||
*ptrp = ptr; \
|
||||
} \
|
||||
\
|
||||
void name##_detach(name##_t **ptrp) { \
|
||||
stat void name##_detach(name##_t **ptrp) { \
|
||||
REQUIRE(ptrp != NULL && *ptrp != NULL); \
|
||||
name##_t *ptr = *ptrp; \
|
||||
*ptrp = NULL; \
|
||||
name##_unref(ptr); \
|
||||
}
|
||||
|
||||
#define ISC_REFCOUNT_IMPL(name, destroy) \
|
||||
ISC__REFCOUNT_IMPL(name, destroy, ISC_REFCOUNT_BLANK)
|
||||
#define ISC_REFCOUNT_STATIC_IMPL(name, destroy) \
|
||||
ISC__REFCOUNT_IMPL(name, destroy, static inline)
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
#include <dns/keystore.h>
|
||||
#include <dns/keyvalues.h>
|
||||
#include <dns/peer.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/rdataclass.h>
|
||||
#include <dns/rdatatype.h>
|
||||
#include <dns/rpz.h>
|
||||
|
||||
@@ -47,7 +47,6 @@
|
||||
#include <dns/nsec.h>
|
||||
#include <dns/nsec3.h>
|
||||
#include <dns/order.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/rdataclass.h>
|
||||
#include <dns/rdatalist.h>
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/qp.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
#include "qp_p.h"
|
||||
@@ -298,78 +297,6 @@ thread_ht(void *arg0) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* rbt
|
||||
*/
|
||||
|
||||
static void *
|
||||
new_rbt(isc_mem_t *mem) {
|
||||
dns_rbt_t *rbt = NULL;
|
||||
(void)dns_rbt_create(mem, NULL, NULL, &rbt);
|
||||
return (rbt);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
add_rbt(void *rbt, size_t count) {
|
||||
isc_result_t result;
|
||||
dns_rbtnode_t *node = NULL;
|
||||
|
||||
result = dns_rbt_addnode(rbt, &item[count].fixed.name, &node);
|
||||
if (result == ISC_R_SUCCESS ||
|
||||
(result == ISC_R_EXISTS && node->data == NULL))
|
||||
{
|
||||
node->data = &item[count];
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
get_rbt(void *rbt, size_t count, void **pval) {
|
||||
isc_result_t result;
|
||||
dns_rbtnode_t *node = NULL;
|
||||
|
||||
result = dns_rbt_findnode(rbt, &item[count].fixed.name, NULL, &node,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
*pval = node->data;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void *
|
||||
thread_rbt(void *arg0) {
|
||||
struct thread_s *arg = arg0;
|
||||
|
||||
isc_barrier_wait(&barrier);
|
||||
|
||||
isc_time_t t0 = isc_time_now_hires();
|
||||
WRLOCK(&rwl);
|
||||
for (size_t n = arg->start; n < arg->end; n++) {
|
||||
isc_result_t result = add_rbt(arg->map, n);
|
||||
CHECK(n, result);
|
||||
}
|
||||
WRUNLOCK(&rwl);
|
||||
|
||||
isc_time_t t1 = isc_time_now_hires();
|
||||
RDLOCK(&rwl);
|
||||
for (size_t n = arg->start; n < arg->end; n++) {
|
||||
void *pval = NULL;
|
||||
isc_result_t result = get_rbt(arg->map, n, &pval);
|
||||
CHECK(n, result);
|
||||
assert(pval == &item[n]);
|
||||
}
|
||||
RDUNLOCK(&rwl);
|
||||
|
||||
isc_time_t t2 = isc_time_now_hires();
|
||||
|
||||
arg->d0 = isc_time_microdiff(&t1, &t0);
|
||||
arg->d1 = isc_time_microdiff(&t2, &t1);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* qp
|
||||
*/
|
||||
@@ -463,7 +390,6 @@ static struct fun fun_list[] = {
|
||||
{ "lfht", new_lfht, thread_lfht },
|
||||
{ "ht", new_ht, thread_ht },
|
||||
{ "hashmap", new_hashmap, thread_hashmap },
|
||||
{ "rbt", new_rbt, thread_rbt },
|
||||
{ "qp", new_qp, thread_qp },
|
||||
{ "qp+nosqz", new_qp, thread_qp_nosqz },
|
||||
{ "qp+barrier", new_qp, thread_qp_brr },
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/qp.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
#include <tests/dns.h>
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/qp.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
#include <tests/dns.h>
|
||||
|
||||
@@ -37,7 +37,6 @@ check_PROGRAMS = \
|
||||
qpmulti_test \
|
||||
qpdb_test \
|
||||
qpzone_test \
|
||||
rbt_test \
|
||||
rdata_test \
|
||||
rdataset_test \
|
||||
rdatasetstats_test \
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/rdatalist.h>
|
||||
#include <dns/rdataset.h>
|
||||
#include <dns/rdatastruct.h>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user