mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 14:07:59 +00:00
implement rdataset iteration
This commit is contained in:
271
lib/dns/rbtdb.c
271
lib/dns/rbtdb.c
@@ -30,6 +30,8 @@
|
||||
#include <dns/master.h>
|
||||
#include <dns/rdataslab.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/rdataset.h>
|
||||
#include <dns/rdatasetiter.h>
|
||||
|
||||
#ifdef DNS_RBTDB_VERSION64
|
||||
#include "rbtdb64.h"
|
||||
@@ -56,6 +58,8 @@ typedef isc_uint64_t rbtdb_serial_t;
|
||||
typedef isc_uint32_t rbtdb_serial_t;
|
||||
#endif
|
||||
|
||||
static const rbtdb_serial_t max_serial = ~((rbtdb_serial_t)0);
|
||||
|
||||
typedef struct rdatasetheader {
|
||||
/* Not locked. */
|
||||
dns_ttl_t ttl;
|
||||
@@ -72,7 +76,7 @@ typedef struct rdatasetheader {
|
||||
struct rdatasetheader *down;
|
||||
} rdatasetheader_t;
|
||||
|
||||
#define RDATASET_ATTR_NONEXISTENT 0x01
|
||||
#define RDATASET_ATTR_NONEXISTENT 0x01
|
||||
|
||||
#define DEFAULT_NODE_LOCK_COUNT 7 /* Should be prime. */
|
||||
|
||||
@@ -122,18 +126,36 @@ typedef struct {
|
||||
|
||||
#define RBTDB_ATTR_LOADED 0x01
|
||||
|
||||
static dns_result_t disassociate(dns_rdataset_t *rdatasetp);
|
||||
static dns_result_t first(dns_rdataset_t *rdataset);
|
||||
static dns_result_t next(dns_rdataset_t *rdataset);
|
||||
static void current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
|
||||
static dns_result_t rdataset_disassociate(dns_rdataset_t *rdatasetp);
|
||||
static dns_result_t rdataset_first(dns_rdataset_t *rdataset);
|
||||
static dns_result_t rdataset_next(dns_rdataset_t *rdataset);
|
||||
static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
|
||||
|
||||
static dns_rdatasetmethods_t rdataset_methods = {
|
||||
disassociate,
|
||||
first,
|
||||
next,
|
||||
current
|
||||
rdataset_disassociate,
|
||||
rdataset_first,
|
||||
rdataset_next,
|
||||
rdataset_current
|
||||
};
|
||||
|
||||
static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
|
||||
static dns_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator);
|
||||
static dns_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator);
|
||||
static void rdatasetiter_current(dns_rdatasetiter_t *iterator,
|
||||
dns_rdataset_t *rdataset);
|
||||
|
||||
static dns_rdatasetitermethods_t rdatasetiter_methods = {
|
||||
rdatasetiter_destroy,
|
||||
rdatasetiter_first,
|
||||
rdatasetiter_next,
|
||||
rdatasetiter_current
|
||||
};
|
||||
|
||||
typedef struct rbtdb_rdatasetiter {
|
||||
dns_rdatasetiter_t common;
|
||||
rdatasetheader_t * current;
|
||||
} rbtdb_rdatasetiter_t;
|
||||
|
||||
/*
|
||||
* Locking
|
||||
*
|
||||
@@ -845,12 +867,15 @@ findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
REQUIRE(type != dns_rdatatype_any);
|
||||
|
||||
if (rbtversion == NULL) {
|
||||
LOCK(&rbtdb->lock);
|
||||
serial = rbtdb->current_serial;
|
||||
UNLOCK(&rbtdb->lock);
|
||||
if ((db->attributes & DNS_DBATTR_CACHE) == 0) {
|
||||
if (rbtversion == NULL) {
|
||||
LOCK(&rbtdb->lock);
|
||||
serial = rbtdb->current_serial;
|
||||
UNLOCK(&rbtdb->lock);
|
||||
} else
|
||||
serial = rbtversion->serial;
|
||||
} else
|
||||
serial = rbtversion->serial;
|
||||
serial = max_serial;
|
||||
|
||||
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
|
||||
|
||||
@@ -910,6 +935,55 @@ findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
return (DNS_R_SUCCESS);
|
||||
}
|
||||
|
||||
static dns_result_t
|
||||
allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
dns_rdatasetiter_t **iteratorp)
|
||||
{
|
||||
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
|
||||
dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
|
||||
rbtdb_version_t *rbtversion = version;
|
||||
rbtdb_rdatasetiter_t *iterator;
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
|
||||
iterator = isc_mem_get(rbtdb->common.mctx, sizeof *iterator);
|
||||
if (iterator == NULL)
|
||||
return (DNS_R_NOMEMORY);
|
||||
|
||||
if ((db->attributes & DNS_DBATTR_CACHE) == 0) {
|
||||
LOCK(&rbtdb->lock);
|
||||
if (rbtversion == NULL) {
|
||||
rbtversion = rbtdb->current_version;
|
||||
if (rbtversion->references == 0)
|
||||
PREPEND(rbtdb->open_versions, rbtversion,
|
||||
link);
|
||||
}
|
||||
rbtversion->references++;
|
||||
INSIST(rbtversion->references != 0);
|
||||
UNLOCK(&rbtdb->lock);
|
||||
} else
|
||||
rbtversion = NULL;
|
||||
|
||||
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 *)rbtversion;
|
||||
|
||||
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
|
||||
|
||||
INSIST(rbtnode->references > 0);
|
||||
rbtnode->references++;
|
||||
INSIST(rbtnode->references != 0);
|
||||
iterator->current = NULL;
|
||||
|
||||
UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
|
||||
|
||||
*iteratorp = (dns_rdatasetiter_t *)iterator;
|
||||
|
||||
return (DNS_R_SUCCESS);
|
||||
}
|
||||
|
||||
static inline dns_result_t
|
||||
add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
|
||||
rdatasetheader_t *newheader)
|
||||
@@ -1159,6 +1233,7 @@ static dns_dbmethods_t methods = {
|
||||
printnode,
|
||||
createiterator,
|
||||
findrdataset,
|
||||
allrdatasets,
|
||||
addrdataset,
|
||||
deleterdataset
|
||||
};
|
||||
@@ -1293,7 +1368,7 @@ dns_rbtdb_create
|
||||
*/
|
||||
|
||||
static dns_result_t
|
||||
disassociate(dns_rdataset_t *rdataset) {
|
||||
rdataset_disassociate(dns_rdataset_t *rdataset) {
|
||||
dns_db_t *db = rdataset->private1;
|
||||
dns_dbnode_t *node = rdataset->private2;
|
||||
|
||||
@@ -1303,7 +1378,7 @@ disassociate(dns_rdataset_t *rdataset) {
|
||||
}
|
||||
|
||||
static dns_result_t
|
||||
first(dns_rdataset_t *rdataset) {
|
||||
rdataset_first(dns_rdataset_t *rdataset) {
|
||||
unsigned char *raw = rdataset->private3;
|
||||
unsigned int count;
|
||||
|
||||
@@ -1326,7 +1401,7 @@ first(dns_rdataset_t *rdataset) {
|
||||
}
|
||||
|
||||
static dns_result_t
|
||||
next(dns_rdataset_t *rdataset) {
|
||||
rdataset_next(dns_rdataset_t *rdataset) {
|
||||
unsigned int count;
|
||||
unsigned int length;
|
||||
unsigned char *raw;
|
||||
@@ -1345,7 +1420,7 @@ next(dns_rdataset_t *rdataset) {
|
||||
}
|
||||
|
||||
static void
|
||||
current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
|
||||
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
|
||||
unsigned char *raw = rdataset->private5;
|
||||
isc_region_t r;
|
||||
|
||||
@@ -1356,3 +1431,163 @@ current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
|
||||
r.base = raw;
|
||||
dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rdataset Iterator Methods
|
||||
*/
|
||||
|
||||
static void
|
||||
rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
|
||||
rbtdb_rdatasetiter_t *rbtiterator;
|
||||
|
||||
rbtiterator = (rbtdb_rdatasetiter_t *)(*iteratorp);
|
||||
|
||||
if (rbtiterator->common.version != NULL)
|
||||
closeversion(rbtiterator->common.db,
|
||||
&rbtiterator->common.version, ISC_FALSE);
|
||||
detachnode(rbtiterator->common.db, &rbtiterator->common.node);
|
||||
isc_mem_put(rbtiterator->common.db->mctx, rbtiterator,
|
||||
sizeof *rbtiterator);
|
||||
|
||||
*iteratorp = NULL;
|
||||
}
|
||||
|
||||
static dns_result_t
|
||||
rdatasetiter_first(dns_rdatasetiter_t *iterator) {
|
||||
rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
|
||||
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
|
||||
dns_rbtnode_t *rbtnode = rbtiterator->common.node;
|
||||
rbtdb_version_t *rbtversion = rbtiterator->common.version;
|
||||
rdatasetheader_t *header, *top_next;
|
||||
rbtdb_serial_t serial;
|
||||
|
||||
if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) == 0)
|
||||
serial = rbtversion->serial;
|
||||
else
|
||||
serial = max_serial;
|
||||
|
||||
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
|
||||
|
||||
for (header = rbtnode->data; header != NULL; header = top_next) {
|
||||
top_next = header->next;
|
||||
do {
|
||||
if (header->serial <= serial) {
|
||||
/*
|
||||
* Is this a "this rdataset doesn't
|
||||
* exist" record?
|
||||
*/
|
||||
if ((header->attributes &
|
||||
RDATASET_ATTR_NONEXISTENT) != 0)
|
||||
header = NULL;
|
||||
break;
|
||||
} else
|
||||
header = header->down;
|
||||
} while (header != NULL);
|
||||
if (header != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
|
||||
|
||||
rbtiterator->current = header;
|
||||
|
||||
if (header == NULL)
|
||||
return (DNS_R_NOMORE);
|
||||
|
||||
return (DNS_R_SUCCESS);
|
||||
}
|
||||
|
||||
static dns_result_t
|
||||
rdatasetiter_next(dns_rdatasetiter_t *iterator) {
|
||||
rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
|
||||
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
|
||||
dns_rbtnode_t *rbtnode = rbtiterator->common.node;
|
||||
rbtdb_version_t *rbtversion = rbtiterator->common.version;
|
||||
rdatasetheader_t *header, *top_next;
|
||||
rbtdb_serial_t serial;
|
||||
|
||||
header = rbtiterator->current;
|
||||
if (header == NULL)
|
||||
return (DNS_R_NOMORE);
|
||||
|
||||
if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) == 0)
|
||||
serial = rbtversion->serial;
|
||||
else
|
||||
serial = max_serial;
|
||||
|
||||
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
|
||||
|
||||
for (header = header->next; header != NULL; header = top_next) {
|
||||
top_next = header->next;
|
||||
do {
|
||||
if (header->serial <= serial) {
|
||||
/*
|
||||
* Is this a "this rdataset doesn't
|
||||
* exist" record?
|
||||
*/
|
||||
if ((header->attributes &
|
||||
RDATASET_ATTR_NONEXISTENT) != 0)
|
||||
header = NULL;
|
||||
break;
|
||||
} else
|
||||
header = header->down;
|
||||
} while (header != NULL);
|
||||
if (header != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
|
||||
|
||||
rbtiterator->current = header;
|
||||
|
||||
if (header == NULL)
|
||||
return (DNS_R_NOMORE);
|
||||
|
||||
return (DNS_R_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
|
||||
rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
|
||||
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
|
||||
dns_rbtnode_t *rbtnode = rbtiterator->common.node;
|
||||
rdatasetheader_t *header;
|
||||
unsigned char *raw;
|
||||
unsigned int count;
|
||||
|
||||
header = rbtiterator->current;
|
||||
REQUIRE(header != NULL);
|
||||
|
||||
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
|
||||
|
||||
INSIST(rbtnode->references > 0);
|
||||
rbtnode->references++;
|
||||
INSIST(rbtnode->references != 0); /* Catch overflow. */
|
||||
|
||||
rdataset->methods = &rdataset_methods;
|
||||
rdataset->rdclass = rbtdb->common.rdclass;
|
||||
rdataset->type = header->type;
|
||||
rdataset->ttl = header->ttl;
|
||||
rdataset->private1 = rbtdb;
|
||||
rdataset->private2 = rbtnode;
|
||||
raw = (unsigned char *)header + sizeof *header;
|
||||
rdataset->private3 = raw;
|
||||
count = raw[0] * 256 + raw[1];
|
||||
raw += 2;
|
||||
if (count == 0) {
|
||||
rdataset->private4 = (void *)0;
|
||||
rdataset->private5 = NULL;
|
||||
} else {
|
||||
/*
|
||||
* The private4 field is the number of rdata beyond
|
||||
* the cursor position, so we decrement the total
|
||||
* count by one before storing it.
|
||||
*/
|
||||
count--;
|
||||
rdataset->private4 = (void *)count;
|
||||
rdataset->private5 = raw;
|
||||
}
|
||||
|
||||
UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
|
||||
}
|
||||
|
Reference in New Issue
Block a user