From 065273f52a2da0caa45123c70c6eeef4a7be7337 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Thu, 2 Sep 1999 16:43:45 +0000 Subject: [PATCH] add _last, _prev, and _seek for dbiterators --- bin/tests/db_test.c | 51 +++++++++++-- lib/dns/dbiterator.c | 33 ++++++++ lib/dns/include/dns/dbiterator.h | 51 +++++++++++++ lib/dns/rbtdb.c | 127 +++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+), 5 deletions(-) diff --git a/bin/tests/db_test.c b/bin/tests/db_test.c index 8a1b43d339..8bda93cdef 100644 --- a/bin/tests/db_test.c +++ b/bin/tests/db_test.c @@ -64,6 +64,7 @@ typedef struct dbinfo { dns_dbiterator_t * dbiterator; dns_dbversion_t * iversion; int pause_every; + isc_boolean_t ascending; ISC_LINK(struct dbinfo) link; } dbinfo; @@ -73,6 +74,7 @@ static dns_dbtable_t * dbtable; static ISC_LIST(dbinfo) dbs; static dbinfo * cache_dbi = NULL; static int pause_every = 0; +static isc_boolean_t ascending = ISC_TRUE; static void print_result(char *message, isc_result_t result) { @@ -158,13 +160,17 @@ select_db(char *origintext) { } static void -list(dbinfo *dbi) { +list(dbinfo *dbi, char *seektext) { dns_fixedname_t fname; dns_name_t *name; dns_dbnode_t *node; dns_rdatasetiter_t *rdsiter; isc_result_t result; int i; + size_t len; + dns_fixedname_t fseekname; + dns_name_t *seekname; + isc_buffer_t source; dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); @@ -181,8 +187,27 @@ list(dbinfo *dbi) { result = dns_db_createiterator(dbi->db, ISC_FALSE, &dbi->dbiterator); - if (result == DNS_R_SUCCESS) - result = dns_dbiterator_first(dbi->dbiterator); + if (result == DNS_R_SUCCESS) { + if (seektext != NULL) { + len = strlen(seektext); + isc_buffer_init(&source, seektext, len, + ISC_BUFFERTYPE_TEXT); + isc_buffer_add(&source, len); + dns_fixedname_init(&fseekname); + seekname = dns_fixedname_name(&fseekname); + result = dns_name_fromtext(seekname, &source, + dns_rootname, + ISC_FALSE, + NULL); + if (result == ISC_R_SUCCESS) + result = dns_dbiterator_seek( + dbi->dbiterator, + seekname); + } else if (dbi->ascending) + result = dns_dbiterator_first(dbi->dbiterator); + else + result = dns_dbiterator_last(dbi->dbiterator); + } } else result = DNS_R_SUCCESS; @@ -202,7 +227,10 @@ list(dbinfo *dbi) { print_rdatasets(name, rdsiter); dns_rdatasetiter_destroy(&rdsiter); dns_db_detachnode(dbi->db, &node); - result = dns_dbiterator_next(dbi->dbiterator); + if (dbi->ascending) + result = dns_dbiterator_next(dbi->dbiterator); + else + result = dns_dbiterator_prev(dbi->dbiterator); i++; if (result == DNS_R_SUCCESS && i == dbi->pause_every) { printf("[more...]\n"); @@ -244,6 +272,7 @@ load(char *filename, char *origintext, isc_boolean_t cache) { dbi->dbiterator = NULL; dbi->iversion = NULL; dbi->pause_every = pause_every; + dbi->ascending = ascending; len = strlen(origintext); isc_buffer_init(&source, origintext, len, ISC_BUFFERTYPE_TEXT); @@ -618,9 +647,13 @@ main(int argc, char *argv[]) { ((options & DNS_DBFIND_NOWILD) == 0) ? "TRUE" : "FALSE"); continue; + } else if (strstr(s, "!LS ") == s) { + DBI_CHECK(dbi); + list(dbi, &s[4]); + continue; } else if (strcmp(s, "!LS") == 0) { DBI_CHECK(dbi); - list(dbi); + list(dbi, NULL); continue; } else if (strstr(s, "!DU ") == s) { DBI_CHECK(dbi); @@ -643,6 +676,14 @@ main(int argc, char *argv[]) { v = atoi(&s[2]); dbi->pause_every = v; continue; + } else if (strcmp(s, "!+") == 0) { + DBI_CHECK(dbi); + dbi->ascending = ISC_TRUE; + continue; + } else if (strcmp(s, "!-") == 0) { + DBI_CHECK(dbi); + dbi->ascending = ISC_FALSE; + continue; } else if (strcmp(s, "!DB") == 0) { dbi = NULL; origin = dns_rootname; diff --git a/lib/dns/dbiterator.c b/lib/dns/dbiterator.c index 87b86d8310..fb99445ab3 100644 --- a/lib/dns/dbiterator.c +++ b/lib/dns/dbiterator.c @@ -49,6 +49,39 @@ dns_dbiterator_first(dns_dbiterator_t *iterator) { return (iterator->methods->first(iterator)); } +dns_result_t +dns_dbiterator_last(dns_dbiterator_t *iterator) { + /* + * Move the node cursor to the first node in the database (if any). + */ + + REQUIRE(DNS_DBITERATOR_VALID(iterator)); + + return (iterator->methods->last(iterator)); +} + +dns_result_t +dns_dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) { + /* + * Move the node cursor to the node with name 'name'. + */ + + REQUIRE(DNS_DBITERATOR_VALID(iterator)); + + return (iterator->methods->seek(iterator, name)); +} + +dns_result_t +dns_dbiterator_prev(dns_dbiterator_t *iterator) { + /* + * Move the node cursor to the previous node in the database (if any). + */ + + REQUIRE(DNS_DBITERATOR_VALID(iterator)); + + return (iterator->methods->prev(iterator)); +} + dns_result_t dns_dbiterator_next(dns_dbiterator_t *iterator) { /* diff --git a/lib/dns/include/dns/dbiterator.h b/lib/dns/include/dns/dbiterator.h index c8fd22fd0e..43cb6ba392 100644 --- a/lib/dns/include/dns/dbiterator.h +++ b/lib/dns/include/dns/dbiterator.h @@ -76,6 +76,9 @@ ISC_LANG_BEGINDECLS typedef struct dns_dbiteratormethods { void (*destroy)(dns_dbiterator_t **iteratorp); dns_result_t (*first)(dns_dbiterator_t *iterator); + dns_result_t (*last)(dns_dbiterator_t *iterator); + dns_result_t (*seek)(dns_dbiterator_t *iterator, dns_name_t *name); + dns_result_t (*prev)(dns_dbiterator_t *iterator); dns_result_t (*next)(dns_dbiterator_t *iterator); dns_result_t (*current)(dns_dbiterator_t *iterator, dns_dbnode_t **nodep, dns_name_t *name); @@ -136,6 +139,54 @@ dns_dbiterator_first(dns_dbiterator_t *iterator); * Other results are possible, depending on the DB implementation. */ +dns_result_t +dns_dbiterator_last(dns_dbiterator_t *iterator); +/* + * Move the node cursor to the last node in the database (if any). + * + * Requires: + * 'iterator' is a valid iterator. + * + * Returns: + * DNS_R_SUCCESS + * DNS_R_NOMORE There are no nodes in the database. + * + * Other results are possible, depending on the DB implementation. + */ + +dns_result_t +dns_dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name); +/* + * Move the node cursor to the node with name 'name'. + * + * Requires: + * 'iterator' is a valid iterator. + * + * 'name' is a valid name. + * + * Returns: + * DNS_R_SUCCESS + * DNS_R_NOTFOUND + * + * Other results are possible, depending on the DB implementation. + */ + +dns_result_t +dns_dbiterator_prev(dns_dbiterator_t *iterator); +/* + * Move the node cursor to the previous node in the database (if any). + * + * Requires: + * 'iterator' is a valid iterator. + * + * Returns: + * DNS_R_SUCCESS + * DNS_R_NOMORE There are no more nodes in the + * database. + * + * Other results are possible, depending on the DB implementation. + */ + dns_result_t dns_dbiterator_next(dns_dbiterator_t *iterator); /* diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 31022293ce..76d1912e35 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -222,6 +222,10 @@ typedef struct rbtdb_rdatasetiter { static void dbiterator_destroy(dns_dbiterator_t **iteratorp); static dns_result_t dbiterator_first(dns_dbiterator_t *iterator); +static dns_result_t dbiterator_last(dns_dbiterator_t *iterator); +static dns_result_t dbiterator_seek(dns_dbiterator_t *iterator, + dns_name_t *name); +static dns_result_t dbiterator_prev(dns_dbiterator_t *iterator); static dns_result_t dbiterator_next(dns_dbiterator_t *iterator); static dns_result_t dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep, @@ -233,6 +237,9 @@ static dns_result_t dbiterator_origin(dns_dbiterator_t *iterator, static dns_dbiteratormethods_t dbiterator_methods = { dbiterator_destroy, dbiterator_first, + dbiterator_last, + dbiterator_seek, + dbiterator_prev, dbiterator_next, dbiterator_current, dbiterator_pause, @@ -3900,6 +3907,126 @@ dbiterator_first(dns_dbiterator_t *iterator) { return (result); } +static dns_result_t +dbiterator_last(dns_dbiterator_t *iterator) { + dns_result_t result; + rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; + dns_name_t *name, *origin; + + if (rbtdbiter->result != DNS_R_SUCCESS && + rbtdbiter->result != DNS_R_NOMORE) + return (rbtdbiter->result); + + unpause(rbtdbiter); + + if (!rbtdbiter->tree_locked) { + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + rbtdbiter->tree_locked = ISC_TRUE; + } + + name = dns_fixedname_name(&rbtdbiter->name); + origin = dns_fixedname_name(&rbtdbiter->origin); + dns_rbtnodechain_reset(&rbtdbiter->chain); + result = dns_rbtnodechain_last(&rbtdbiter->chain, rbtdb->tree, name, + origin); + if (result != DNS_R_NEWORIGIN) { + INSIST(result != DNS_R_SUCCESS); + if (result == DNS_R_NOTFOUND) { + /* + * The tree is empty. + */ + result = DNS_R_NOMORE; + } + rbtdbiter->node = NULL; + } else { + result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL, + NULL, &rbtdbiter->node); + if (result == DNS_R_SUCCESS) + rbtdbiter->new_origin = ISC_TRUE; + else + rbtdbiter->node = NULL; + } + rbtdbiter->result = result; + + return (result); +} + +static dns_result_t +dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) { + dns_result_t result; + rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; + dns_name_t *iname, *origin; + + if (rbtdbiter->result != DNS_R_SUCCESS && + rbtdbiter->result != DNS_R_NOMORE) + return (rbtdbiter->result); + + unpause(rbtdbiter); + + if (!rbtdbiter->tree_locked) { + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + rbtdbiter->tree_locked = ISC_TRUE; + } + + iname = dns_fixedname_name(&rbtdbiter->name); + origin = dns_fixedname_name(&rbtdbiter->origin); + dns_rbtnodechain_reset(&rbtdbiter->chain); + rbtdbiter->node = NULL; + result = dns_rbt_findnode(rbtdb->tree, name, NULL, &rbtdbiter->node, + &rbtdbiter->chain, ISC_TRUE, NULL, NULL); + if (result != DNS_R_SUCCESS) { + if (result == DNS_R_PARTIALMATCH) + result = DNS_R_NOTFOUND; + rbtdbiter->node = NULL; + } else { + result = dns_rbtnodechain_current(&rbtdbiter->chain, iname, + origin, NULL); + if (result == DNS_R_SUCCESS) + rbtdbiter->new_origin = ISC_TRUE; + else + rbtdbiter->node = NULL; + } + rbtdbiter->result = result; + + return (result); +} + +static dns_result_t +dbiterator_prev(dns_dbiterator_t *iterator) { + dns_result_t result; + rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; + dns_name_t *name, *origin; + + REQUIRE(rbtdbiter->node != NULL); + + if (rbtdbiter->result != DNS_R_SUCCESS) + return (rbtdbiter->result); + + if (rbtdbiter->paused) + resume_iteration(rbtdbiter); + + name = dns_fixedname_name(&rbtdbiter->name); + origin = dns_fixedname_name(&rbtdbiter->origin); + result = dns_rbtnodechain_prev(&rbtdbiter->chain, name, origin); + if (result == DNS_R_NEWORIGIN || result == DNS_R_SUCCESS) { + if (result == DNS_R_NEWORIGIN) + rbtdbiter->new_origin = ISC_TRUE; + else + rbtdbiter->new_origin = ISC_FALSE; + result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL, + NULL, &rbtdbiter->node); + if (result != DNS_R_SUCCESS) { + rbtdbiter->result = result; + rbtdbiter->node = NULL; + } + } else + rbtdbiter->result = result; + + return (result); +} + static dns_result_t dbiterator_next(dns_dbiterator_t *iterator) { dns_result_t result;