basic versioning; 64-bit version support; C++ compatibility

This commit is contained in:
Bob Halley 1999-03-04 02:45:56 +00:00
parent 86921103ec
commit e371b7a70f
2 changed files with 606 additions and 53 deletions

View file

@ -15,6 +15,8 @@
* SOFTWARE.
*/
#include <config.h>
#include <stddef.h>
#include <string.h>
@ -29,49 +31,97 @@
#include <dns/rdataslab.h>
#include <dns/rdata.h>
#ifdef DNS_RBTDB_VERSION64
#include "rbtdb64.h"
#else
#include "rbtdb.h"
#endif
/* Lame. Move util.h to <isc/util.h> */
#include "../isc/util.h"
#define RBTDB_MAGIC 0x52424442U /* RBDB. */
#ifdef DNS_RBTDB_VERSION64
#define RBTDB_MAGIC 0x52424438U /* RBD8. */
#else
#define RBTDB_MAGIC 0x52424434U /* RBD4. */
#endif
#define VALID_RBTDB(rbtdb) ((rbtdb) != NULL && \
(rbtdb)->common.impmagic == \
RBTDB_MAGIC)
#ifdef DNS_RBTDB_VERSION64
typedef isc_uint64_t rbtdb_serial_t;
#else
typedef isc_uint32_t rbtdb_serial_t;
#endif
typedef struct rdatasetheader {
/* Not locked. */
dns_ttl_t ttl;
rbtdb_serial_t serial;
dns_rdatatype_t type;
isc_uint16_t attributes;
/*
* We don't use the LIST macros, because the LIST structure has
* both head and tail pointers. We only have a head pointer in
* the node to save space.
*/
unsigned int version;
struct rdatasetheader *prev;
struct rdatasetheader *next;
struct rdatasetheader *down;
} rdatasetheader_t;
#define RDATASET_ATTR_NXRRSET 0x01
#define DEFAULT_NODE_LOCK_COUNT 7 /* Should be prime. */
typedef struct {
isc_mutex_t lock;
unsigned int references;
} node_lock;
} rbtdb_nodelock_t;
typedef struct rbtdb_changed {
dns_rbtnode_t * node;
isc_boolean_t dirty;
ISC_LINK(struct rbtdb_changed) link;
} rbtdb_changed_t;
typedef ISC_LIST(rbtdb_changed_t) rbtdb_changedlist_t;
typedef struct rbtdb_version {
rbtdb_serial_t serial;
unsigned int references;
isc_boolean_t writer;
isc_boolean_t commit_ok;
rbtdb_changedlist_t changed_list;
ISC_LINK(struct rbtdb_version) link;
} rbtdb_version_t;
typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t;
typedef struct {
/* Unlocked */
/* Unlocked. */
dns_db_t common;
isc_mutex_t lock;
isc_rwlock_t tree_lock;
unsigned int node_lock_count;
node_lock * node_locks;
/* Locked by lock */
rbtdb_nodelock_t * node_locks;
/* Locked by lock. */
unsigned int references;
/* Locked by tree_lock */
unsigned int attributes;
rbtdb_serial_t current_serial;
rbtdb_serial_t least_serial;
rbtdb_serial_t next_serial;
rbtdb_version_t * current_version;
rbtdb_version_t * future_version;
rbtdb_versionlist_t open_versions;
/* Locked by tree_lock. */
dns_rbt_t * tree;
} dns_rbtdb_t;
#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);
@ -84,6 +134,22 @@ static dns_rdatasetmethods_t rdataset_methods = {
current
};
/*
* Locking
*
* If a routine is going to lock more than one lock in this module, then
* the locking must be done in the following order:
*
* Tree Lock
*
* Node Lock (Only one from the set may be locked at one time by
* any caller)
*
* Database Lock
*
* Failure to follow this hierarchy can result in deadlock.
*/
/*
* DB Routines
*/
@ -107,6 +173,10 @@ free_rbtdb(dns_rbtdb_t *rbtdb) {
unsigned int i;
isc_region_t r;
REQUIRE(EMPTY(rbtdb->open_versions));
REQUIRE(rbtdb->future_version == NULL);
isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,
sizeof (rbtdb_version_t));
dns_name_toregion(&rbtdb->common.origin, &r);
if (r.base != NULL)
isc_mem_put(rbtdb->common.mctx, r.base, r.length);
@ -115,7 +185,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb) {
for (i = 0; i < rbtdb->node_lock_count; i++)
isc_mutex_destroy(&rbtdb->node_locks[i].lock);
isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks,
rbtdb->node_lock_count * sizeof (node_lock));
rbtdb->node_lock_count * sizeof (rbtdb_nodelock_t));
isc_rwlock_destroy(&rbtdb->tree_lock);
isc_mutex_destroy(&rbtdb->lock);
rbtdb->common.magic = 0;
@ -168,30 +238,431 @@ detach(dns_db_t **dbp) {
static void
currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
rbtdb_version_t *version;
REQUIRE(VALID_RBTDB(rbtdb));
*versionp = NULL;
LOCK(&rbtdb->lock);
version = rbtdb->current_version;
if (version->references == 0)
PREPEND(rbtdb->open_versions, version, link);
version->references++;
UNLOCK(&rbtdb->lock);
*versionp = (dns_dbversion_t *)version;
}
static inline rbtdb_version_t *
allocate_version(isc_mem_t *mctx, unsigned int serial,
unsigned int references, isc_boolean_t writer)
{
rbtdb_version_t *version;
version = isc_mem_get(mctx, sizeof *version);
if (version == NULL)
return (NULL);
version->serial = serial;
version->references = references;
version->writer = writer;
version->commit_ok = ISC_FALSE;
ISC_LIST_INIT(version->changed_list);
ISC_LINK_INIT(version, link);
return (version);
}
static dns_result_t
newversion(dns_db_t *db, dns_dbversion_t **versionp) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
(void)versionp;
rbtdb_version_t *version;
REQUIRE(VALID_RBTDB(rbtdb));
REQUIRE(versionp != NULL && *versionp == NULL);
REQUIRE(rbtdb->future_version == NULL);
return (DNS_R_NOTIMPLEMENTED);
LOCK(&rbtdb->lock);
RUNTIME_CHECK(rbtdb->next_serial != 0); /* XXX Error? */
version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1,
ISC_TRUE);
if (version != NULL) {
rbtdb->next_serial++;
rbtdb->future_version = version;
}
UNLOCK(&rbtdb->lock);
if (version == NULL)
return (DNS_R_NOMEMORY);
return (DNS_R_SUCCESS);
}
static rbtdb_changed_t *
add_changed(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
dns_rbtnode_t *node)
{
rbtdb_changed_t *changed;
/*
* Caller must be holding the node lock.
*/
changed = isc_mem_get(rbtdb->common.mctx, sizeof *changed);
if (changed == NULL) {
version->commit_ok = ISC_FALSE;
return (NULL);
}
node->references++;
changed->node = node;
changed->dirty = ISC_FALSE;
APPEND(version->changed_list, changed, link);
return (changed);
}
static inline void
free_rdataset(isc_mem_t *mctx, rdatasetheader_t *rdataset) {
unsigned int size;
size = dns_rdataslab_size((unsigned char *)rdataset, sizeof *rdataset);
isc_mem_put(mctx, rdataset, size);
}
static void
rollback_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, rbtdb_serial_t serial) {
rdatasetheader_t *header, *header_next;
/*
* Caller must hold the node lock.
*/
REQUIRE(node->references == 0);
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
if (header->serial == serial) {
if (header->down != NULL) {
header->down->prev = header->prev;
if (header->prev != NULL)
header->prev->next = header->down;
else
node->data = header->down;
header->down->next = header->next;
if (header->next != NULL)
header->next->prev = header->down;
} else {
if (header->prev != NULL)
header->prev->next = header->next;
else
node->data = header->next;
if (header->next != NULL)
header->next->prev = header->prev;
}
free_rdataset(rbtdb->common.mctx, header);
}
}
}
static inline void
clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
rdatasetheader_t *current, *dcurrent, *top_next, *down_next;
isc_mem_t *mctx = rbtdb->common.mctx;
/*
* Caller must be holding the node lock.
*/
/* XXX should remove stale data. */
for (current = node->data; current != NULL; current = top_next) {
top_next = current->next;
dcurrent = current->down;
if (dcurrent != NULL) {
do {
down_next = dcurrent->down;
free_rdataset(mctx, dcurrent);
dcurrent = down_next;
} while (dcurrent != NULL);
current->down = NULL;
}
}
}
static inline void
clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
rbtdb_serial_t least_serial)
{
rdatasetheader_t *current, *dcurrent, *top_next, *down_next, *dparent;
isc_mem_t *mctx = rbtdb->common.mctx;
isc_boolean_t still_dirty = ISC_FALSE;
/*
* Caller must be holding the node lock.
*/
REQUIRE(least_serial != 0);
for (current = node->data; current != NULL; current = top_next) {
top_next = current->next;
/*
* Find the first rdataset less than the least serial, if
* any.
*/
dparent = current;
for (dcurrent = current->down;
dcurrent != NULL;
dcurrent = dcurrent->down) {
INSIST(dcurrent->serial < dparent->serial);
if (dcurrent->serial < least_serial)
break;
dparent = dcurrent;
}
/*
* If there is a such an rdataset, delete it and any older
* versions.
*/
if (dcurrent != NULL) {
do {
down_next = dcurrent->down;
INSIST(dcurrent->serial < least_serial);
free_rdataset(mctx, dcurrent);
dcurrent = down_next;
} while (dcurrent != NULL);
dparent->down = NULL;
}
/*
* Note. The serial number of 'current' might be less than
* least_serial too, but we cannot delete it because it is
* the most recent version. Only old versions less than the
* least_serial can be deleted.
*/
if (current->down != NULL)
still_dirty = ISC_TRUE;
/*
* XXX It would be good to garbage collect "rdataset doesn't
* exist" records that are in the current version and have no
* down pointers. Can this be done safely? Yes, provided
* that we never create an external reference to one of those
* records. This isn't as easy as it first sounds, because we
* could have an rdataset iterator parked on it. Solution:
* make sure iterators never park on such a rdataset.
*/
}
if (!still_dirty)
node->dirty = 0;
}
static inline void
no_references(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
rbtdb_serial_t least_serial)
{
/*
* Caller must be holding the node lock.
*/
REQUIRE(node->references == 0);
if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) != 0)
clean_cache_node(rbtdb, node);
else if (node->dirty) {
if (least_serial == 0) {
/*
* Caller doesn't know the least serial. Get it.
*/
LOCK(&rbtdb->lock);
least_serial = rbtdb->least_serial;
UNLOCK(&rbtdb->lock);
}
clean_zone_node(rbtdb, node, least_serial);
}
INSIST(rbtdb->node_locks[node->locknum].references > 0);
rbtdb->node_locks[node->locknum].references--;
}
static inline void
make_least_version(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
rbtdb_changedlist_t *cleanup_list)
{
/*
* Caller must be holding the database lock.
*/
rbtdb->least_serial = version->serial;
*cleanup_list = version->changed_list;
}
static inline void
cleanup_nondirty(rbtdb_version_t *version, rbtdb_changedlist_t *cleanup_list) {
rbtdb_changed_t *changed, *next_changed;
/*
* If the changed record is dirty, then
* an update created multiple versions of
* a given rdataset. We keep this list
* until we're the least open version, at
* which point it's safe to get rid of any
* older versions.
*
* If the changed record isn't dirty, then
* we don't need it anymore since we're
* committing and not rolling back.
*/
for (changed = HEAD(version->changed_list);
changed != NULL;
changed = next_changed) {
next_changed = NEXT(changed, link);
if (!changed->dirty) {
UNLINK(version->changed_list,
changed, link);
APPEND(*cleanup_list,
changed, link);
}
}
}
static void
closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
(void)commit;
rbtdb_version_t *version, *cleanup_version, *next_greater_version;
isc_boolean_t rollback = ISC_FALSE;
rbtdb_changedlist_t cleanup_list;
rbtdb_changed_t *changed, *next_changed;
rbtdb_serial_t serial, least_serial;
dns_rbtnode_t *rbtnode;
REQUIRE(VALID_RBTDB(rbtdb));
REQUIRE(versionp != NULL && *versionp != NULL);
version = (rbtdb_version_t *)*versionp;
cleanup_version = NULL;
ISC_LIST_INIT(cleanup_list);
LOCK(&rbtdb->lock);
INSIST((version->writer && version->references == 1) ||
version->references > 0);
version->references--;
serial = version->serial;
if (version->references == 0) {
if (version->writer) {
if (commit) {
INSIST(version->commit_ok);
INSIST(version == rbtdb->future_version);
if (EMPTY(rbtdb->open_versions)) {
/*
* We're going to become the least open
* version.
*/
make_least_version(rbtdb, version,
&cleanup_list);
} else {
/*
* Some other open version is the
* least version. We can't cleanup
* records that were changed in this
* version because the older versions
* may still be in use by an open
* version.
*
* We can, however, discard the
* changed records for things that
* we've added that didn't exist in
* prior versions.
*/
cleanup_nondirty(version,
&cleanup_list);
}
/*
* If the (soon to be former) current version
* isn't being used by anyone, we can clean
* it up.
*/
if (rbtdb->current_version->references == 0)
cleanup_version =
rbtdb->current_version;
/*
* Become the current version.
*/
rbtdb->current_version = version;
rbtdb->current_serial = version->serial;
rbtdb->future_version = NULL;
} else {
/*
* We're rolling back this transaction.
*/
cleanup_list = version->changed_list;
rollback = ISC_TRUE;
cleanup_version = version;
}
/* XXX wake up waiting updates */
} else {
if (version != rbtdb->current_version) {
/*
* There are no external or internal references
* to this version and it can be cleaned up.
*/
cleanup_version = version;
}
/*
* Find the open version with the next-greater serial
* number than ours.
*/
next_greater_version = PREV(version, link);
if (next_greater_version == NULL)
next_greater_version = rbtdb->current_version;
/*
* Is this the least open version?
*/
if (version->serial == rbtdb->least_serial) {
/*
* Yes. Install the new least open version.
*/
make_least_version(rbtdb,
next_greater_version,
&cleanup_list);
} else if (version != rbtdb->current_version) {
/*
* Add any unexecuted cleanups to those of
* the next-greater version.
*/
APPENDLIST(next_greater_version->changed_list,
version->changed_list, link);
}
UNLINK(rbtdb->open_versions, version, link);
}
}
least_serial = rbtdb->least_serial;
UNLOCK(&rbtdb->lock);
if (cleanup_version != NULL)
isc_mem_put(rbtdb->common.mctx, cleanup_version,
sizeof *cleanup_version);
if (!EMPTY(cleanup_list)) {
for (changed = HEAD(cleanup_list);
changed != NULL;
changed = next_changed) {
next_changed = NEXT(changed, link);
rbtnode = changed->node;
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
/*
* XXX Like the rest of this module, this code doesn't
* deal with node splits.
*/
INSIST(rbtnode->references > 0);
rbtnode->references--;
if (rollback)
rollback_node(rbtdb, rbtnode, serial);
if (rbtnode->references == 0)
no_references(rbtdb, rbtnode, least_serial);
UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
isc_mem_put(rbtdb->common.mctx, changed,
sizeof *changed);
}
}
*versionp = NULL;
}
@ -271,14 +742,14 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
REQUIRE(targetp != NULL && *targetp != NULL);
node = (dns_rbtnode_t *)(*targetp);
LOCK(&rbtdb->node_locks[node->locknum].lock);
INSIST(node->references > 0);
node->references--;
if (node->references == 0) {
INSIST(rbtdb->node_locks[node->locknum].references > 0);
rbtdb->node_locks[node->locknum].references--;
/* XXX other detach stuff here */
}
if (node->references == 0)
no_references(rbtdb, node, 0);
UNLOCK(&rbtdb->node_locks[node->locknum].lock);
*targetp = NULL;
@ -293,16 +764,31 @@ findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
rdatasetheader_t *header;
unsigned char *raw;
unsigned int count;
(void)version;
rbtdb_serial_t serial;
rbtdb_version_t *rbtversion = version;
REQUIRE(VALID_RBTDB(rbtdb));
REQUIRE(type != dns_rdatatype_any);
if (rbtversion == NULL) {
LOCK(&rbtdb->lock);
serial = rbtdb->current_serial;
UNLOCK(&rbtdb->lock);
} else
serial = rbtversion->serial;
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
for (header = rbtnode->data; header != NULL; header = header->next) {
/* XXX version */
if (header->type == type)
if (header->type == type) {
do {
if (header->serial <= serial)
break;
else
header = header->down;
} while (header != NULL);
break;
}
}
if (header != NULL) {
INSIST(rbtnode->references > 0);
@ -310,7 +796,7 @@ findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
INSIST(rbtnode->references != 0); /* Catch overflow. */
rdataset->methods = &rdataset_methods;
rdataset->class = rbtdb->common.class;
rdataset->rdclass = rbtdb->common.rdclass;
rdataset->type = header->type;
rdataset->ttl = header->ttl;
rdataset->private1 = rbtdb;
@ -333,6 +819,7 @@ findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
rdataset->private5 = raw;
}
}
UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
if (header == NULL)
@ -350,9 +837,9 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
isc_region_t region;
rdatasetheader_t *header, *newheader;
dns_result_t result;
rbtdb_version_t *rbtversion = version;
rbtdb_changed_t *changed = NULL;
(void)version;
REQUIRE(VALID_RBTDB(rbtdb));
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
@ -360,18 +847,67 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
sizeof (rdatasetheader_t));
if (result != DNS_R_SUCCESS)
return (result);
newheader = (rdatasetheader_t *)region.base;
newheader->ttl = rdataset->ttl;
newheader->type = rdataset->type;
newheader->version = 0; /* XXX version */
newheader->prev = NULL;
newheader->attributes = 0;
if (rbtversion != NULL)
newheader->serial = rbtversion->serial;
else
newheader->serial = 0;
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
header = rbtnode->data;
newheader->next = header;
if (header != NULL)
if (rbtversion != NULL) {
changed = add_changed(rbtdb, rbtversion, rbtnode);
if (changed == NULL) {
UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
return (DNS_R_NOMEMORY);
}
}
for (header = rbtnode->data; header != NULL; header = header->next) {
if (header->type == rdataset->type)
break;
}
if (header != NULL) {
if (rbtversion != NULL) {
INSIST(rbtversion->serial >= header->serial);
if (rbtversion->serial == header->serial) {
/*
* XXX created merged rdataset, make
* newheader point to it
*/
}
}
INSIST(rbtversion == NULL ||
rbtversion->serial > header->serial);
newheader->prev = header->prev;
if (header->prev != NULL)
header->prev->next = newheader;
else
rbtnode->data = newheader;
newheader->next = header->next;
if (header->next != NULL)
header->next->prev = newheader;
newheader->down = header;
header->prev = newheader;
rbtnode->data = newheader;
header->next = NULL;
rbtnode->dirty = 1;
changed->dirty = ISC_TRUE;
} else {
/*
* The rdataset type doesn't exist at this node.
*/
newheader->prev = NULL;
newheader->next = rbtnode->data;
if (newheader->next != NULL)
newheader->next->prev = newheader;
newheader->down = NULL;
rbtnode->data = newheader;
}
UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
return (DNS_R_SUCCESS);
@ -423,8 +959,10 @@ add_rdataset_callback(dns_rdatacallbacks_t *callbacks, dns_name_t *name,
newheader = (rdatasetheader_t *)region.base;
newheader->ttl = rdataset->ttl;
newheader->type = rdataset->type;
newheader->version = 0; /* XXX version */
newheader->attributes = 0;
newheader->serial = 1;
newheader->prev = NULL;
newheader->down = NULL;
header = node->data;
newheader->next = header;
@ -443,24 +981,24 @@ load(dns_db_t *db, char *filename) {
REQUIRE(VALID_RBTDB(rbtdb));
LOCK(&rbtdb->lock);
REQUIRE((rbtdb->common.attributes & RBTDB_ATTR_LOADED) == 0);
/*
* XXX
*
* For now, there is no locking, since database
* loading is assumed to occur before parallel
* access. Clearly the database should be empty
* before trying to load it. Probably need some
* kind of "loaded" flag so we can
*
* REQUIRE(!rbtdb->loaded);
* We set RBTDB_ATTR_LOADED even though we don't know the
* load is going to succeed because we don't want someone to try
* again with partial prior load results if a load fails.
*/
rbtdb->attributes |= RBTDB_ATTR_LOADED;
UNLOCK(&rbtdb->lock);
dns_rdatacallbacks_init(&callbacks);
callbacks.commit = add_rdataset_callback;
callbacks.commit_private = rbtdb;
return (dns_master_load(filename, &rbtdb->common.origin,
&rbtdb->common.origin, rbtdb->common.class,
&rbtdb->common.origin, rbtdb->common.rdclass,
&soacount, &nscount, &callbacks,
rbtdb->common.mctx));
}
@ -495,8 +1033,13 @@ static dns_dbmethods_t methods = {
};
dns_result_t
dns_rbtdb_create(isc_mem_t *mctx, dns_name_t *origin, isc_boolean_t cache,
dns_rdataclass_t class, unsigned int argc, char *argv[],
#ifdef DNS_RBTDB_VERSION64
dns_rbtdb64_create
#else
dns_rbtdb_create
#endif
(isc_mem_t *mctx, dns_name_t *origin, isc_boolean_t cache,
dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
dns_db_t **dbp)
{
dns_rbtdb_t *rbtdb;
@ -517,7 +1060,7 @@ dns_rbtdb_create(isc_mem_t *mctx, dns_name_t *origin, isc_boolean_t cache,
rbtdb->common.attributes = 0;
if (cache)
rbtdb->common.attributes |= DNS_DBATTR_CACHE;
rbtdb->common.class = class;
rbtdb->common.rdclass = rdclass;
rbtdb->common.mctx = mctx;
iresult = isc_mutex_init(&rbtdb->lock);
@ -544,7 +1087,7 @@ dns_rbtdb_create(isc_mem_t *mctx, dns_name_t *origin, isc_boolean_t cache,
if (rbtdb->node_lock_count == 0)
rbtdb->node_lock_count = DEFAULT_NODE_LOCK_COUNT;
rbtdb->node_locks = isc_mem_get(mctx, rbtdb->node_lock_count *
sizeof (node_lock));
sizeof (rbtdb_nodelock_t));
for (i = 0; i < (int)(rbtdb->node_lock_count); i++) {
iresult = isc_mutex_init(&rbtdb->node_locks[i].lock);
if (iresult != ISC_R_SUCCESS) {
@ -555,7 +1098,7 @@ dns_rbtdb_create(isc_mem_t *mctx, dns_name_t *origin, isc_boolean_t cache,
}
isc_mem_put(mctx, rbtdb->node_locks,
rbtdb->node_lock_count *
sizeof (node_lock));
sizeof (rbtdb_nodelock_t));
isc_rwlock_destroy(&rbtdb->tree_lock);
isc_mutex_destroy(&rbtdb->lock);
isc_mem_put(rbtdb->common.mctx, rbtdb, sizeof *rbtdb);
@ -592,7 +1135,18 @@ dns_rbtdb_create(isc_mem_t *mctx, dns_name_t *origin, isc_boolean_t cache,
rbtdb->references = 1;
/* XXX Version init here */
/*
* Version Initialization.
*/
rbtdb->current_serial = 1;
rbtdb->least_serial = 1;
rbtdb->next_serial = 2;
rbtdb->current_version = allocate_version(mctx, 1, 0, ISC_FALSE);
if (rbtdb->current_version == NULL) {
free_rbtdb(rbtdb);
return (DNS_R_NOMEMORY);
}
ISC_LIST_INIT(rbtdb->open_versions);
rbtdb->common.magic = DNS_DB_MAGIC;
rbtdb->common.impmagic = RBTDB_MAGIC;
@ -603,7 +1157,6 @@ dns_rbtdb_create(isc_mem_t *mctx, dns_name_t *origin, isc_boolean_t cache,
}
/*
* Slabbed Rdataset Methods
*/
@ -670,5 +1223,5 @@ current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
r.length = raw[0] * 256 + raw[1];
raw += 2;
r.base = raw;
dns_rdata_fromregion(rdata, rdataset->class, rdataset->type, &r);
dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
}

View file

@ -30,7 +30,7 @@
dns_result_t
dns_rbtdb_create(isc_mem_t *mctx, dns_name_t *base, isc_boolean_t is_cache,
dns_rdataclass_t class, unsigned int argc, char *argv[],
dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
dns_db_t **dbp);
#endif /* DNS_RBTDB_H */