mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-08 22:32:07 -04:00
use only one database version per query
This commit is contained in:
parent
a2ce103c23
commit
9d308c6236
4 changed files with 159 additions and 7 deletions
|
|
@ -404,6 +404,8 @@ client_request(isc_task_t *task, isc_event_t *event) {
|
|||
CTRACE("request");
|
||||
|
||||
client->state = ns_clientstate_working;
|
||||
if (isc_stdtime_get(&client->requesttime) != ISC_R_SUCCESS)
|
||||
client->requesttime = 0;
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (TCP_CLIENT(client))
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#define NS_CLIENT_H 1
|
||||
|
||||
#include <isc/types.h>
|
||||
#include <isc/stdtime.h>
|
||||
#include <isc/buffer.h>
|
||||
|
||||
#include <dns/types.h>
|
||||
|
|
@ -64,6 +65,7 @@ struct ns_client {
|
|||
isc_mempool_t * sendbufs;
|
||||
void (*next)(ns_client_t *, isc_result_t);
|
||||
ns_query_t query;
|
||||
isc_stdtime_t requesttime;
|
||||
ISC_LINK(struct ns_client) link;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
|
||||
#include <named/types.h>
|
||||
|
||||
typedef struct ns_dbversion {
|
||||
dns_db_t *db;
|
||||
dns_dbversion_t *version;
|
||||
ISC_LINK(struct ns_dbversion) link;
|
||||
} ns_dbversion_t;
|
||||
|
||||
struct ns_query {
|
||||
unsigned int attributes;
|
||||
dns_name_t * qname;
|
||||
|
|
@ -33,6 +39,8 @@ struct ns_query {
|
|||
ISC_LIST(isc_dynbuffer_t) namebufs;
|
||||
ISC_LIST(dns_name_t) tmpnames;
|
||||
ISC_LIST(dns_rdataset_t) tmprdatasets;
|
||||
ISC_LIST(ns_dbversion_t) activeversions;
|
||||
ISC_LIST(ns_dbversion_t) freeversions;
|
||||
};
|
||||
|
||||
#define NS_QUERYATTR_RECURSIONOK 0x01
|
||||
|
|
|
|||
|
|
@ -50,6 +50,42 @@
|
|||
static inline void
|
||||
query_reset(ns_client_t *client, isc_boolean_t everything) {
|
||||
isc_dynbuffer_t *dbuf, *dbuf_next;
|
||||
ns_dbversion_t *dbversion, *dbversion_next;
|
||||
unsigned int i;
|
||||
|
||||
|
||||
/*
|
||||
* Cleanup any active versions.
|
||||
*/
|
||||
for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
|
||||
dbversion != NULL;
|
||||
dbversion = dbversion_next) {
|
||||
dbversion_next = ISC_LIST_NEXT(dbversion, link);
|
||||
dns_db_closeversion(dbversion->db, &dbversion->version,
|
||||
ISC_FALSE);
|
||||
dns_db_detach(&dbversion->db);
|
||||
ISC_LIST_APPEND(client->query.freeversions, dbversion, link);
|
||||
}
|
||||
ISC_LIST_INIT(client->query.activeversions);
|
||||
|
||||
/*
|
||||
* Clean up free versions.
|
||||
*/
|
||||
for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0;
|
||||
dbversion != NULL;
|
||||
dbversion = dbversion_next, i++) {
|
||||
dbversion_next = ISC_LIST_NEXT(dbversion, link);
|
||||
/*
|
||||
* If we're not freeing everything, we keep the first three
|
||||
* dbversions structures around.
|
||||
*/
|
||||
if (i > 3 || everything) {
|
||||
ISC_LIST_UNLINK(client->query.freeversions, dbversion,
|
||||
link);
|
||||
isc_mem_put(client->mctx, dbversion,
|
||||
sizeof *dbversion);
|
||||
}
|
||||
}
|
||||
|
||||
for (dbuf = ISC_LIST_HEAD(client->query.namebufs);
|
||||
dbuf != NULL;
|
||||
|
|
@ -89,8 +125,6 @@ query_newnamebuf(ns_client_t *client) {
|
|||
isc_dynbuffer_t *dbuf;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
|
||||
dbuf = NULL;
|
||||
result = isc_dynbuffer_allocate(client->mctx, &dbuf, 1024,
|
||||
ISC_BUFFERTYPE_BINARY);
|
||||
|
|
@ -201,13 +235,96 @@ query_newrdataset(ns_client_t *client) {
|
|||
return (rdataset);
|
||||
}
|
||||
|
||||
static inline isc_result_t
|
||||
query_newdbversion(ns_client_t *client, unsigned int n) {
|
||||
unsigned int i;
|
||||
ns_dbversion_t *dbversion;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
dbversion = isc_mem_get(client->mctx, sizeof *dbversion);
|
||||
if (dbversion != NULL) {
|
||||
dbversion->db = NULL;
|
||||
dbversion->version = NULL;
|
||||
ISC_LIST_APPEND(client->query.freeversions, dbversion,
|
||||
link);
|
||||
} else {
|
||||
/*
|
||||
* We only return ISC_R_NOMEMORY if we couldn't
|
||||
* allocate anything.
|
||||
*/
|
||||
if (i == 0)
|
||||
return (ISC_R_NOMEMORY);
|
||||
else
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static inline ns_dbversion_t *
|
||||
query_getdbversion(ns_client_t *client) {
|
||||
isc_result_t result;
|
||||
ns_dbversion_t *dbversion;
|
||||
|
||||
if (ISC_LIST_EMPTY(client->query.freeversions)) {
|
||||
result = query_newdbversion(client, 1);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (NULL);
|
||||
}
|
||||
dbversion = ISC_LIST_HEAD(client->query.freeversions);
|
||||
INSIST(dbversion != NULL);
|
||||
ISC_LIST_UNLINK(client->query.freeversions, dbversion, link);
|
||||
|
||||
return (dbversion);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
ns_query_init(ns_client_t *client) {
|
||||
isc_result_t result;
|
||||
|
||||
ISC_LIST_INIT(client->query.namebufs);
|
||||
ISC_LIST_INIT(client->query.activeversions);
|
||||
ISC_LIST_INIT(client->query.freeversions);
|
||||
query_reset(client, ISC_FALSE);
|
||||
result = query_newdbversion(client, 3);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
return (query_newnamebuf(client));
|
||||
}
|
||||
|
||||
static inline dns_dbversion_t *
|
||||
query_findversion(ns_client_t *client, dns_db_t *db) {
|
||||
ns_dbversion_t *dbversion;
|
||||
|
||||
/*
|
||||
* We may already have done a query related to this
|
||||
* database. If so, we must be sure to make subsequent
|
||||
* queries from the same version.
|
||||
*/
|
||||
for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
|
||||
dbversion != NULL;
|
||||
dbversion = ISC_LIST_NEXT(dbversion, link)) {
|
||||
if (dbversion->db == db)
|
||||
break;
|
||||
}
|
||||
if (dbversion == NULL) {
|
||||
/*
|
||||
* This is a new zone for this query. Add it to
|
||||
* the active list.
|
||||
*/
|
||||
dbversion = query_getdbversion(client);
|
||||
if (dbversion == NULL)
|
||||
return (NULL);
|
||||
dns_db_attach(db, &dbversion->db);
|
||||
dns_db_currentversion(db, &dbversion->version);
|
||||
ISC_LIST_APPEND(client->query.activeversions,
|
||||
dbversion, link);
|
||||
}
|
||||
|
||||
return (dbversion->version);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t type) {
|
||||
ns_client_t *client = arg;
|
||||
|
|
@ -219,6 +336,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t type) {
|
|||
dns_section_t section;
|
||||
isc_dynbuffer_t *dbuf;
|
||||
isc_buffer_t b;
|
||||
dns_dbversion_t *version;
|
||||
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
REQUIRE(type != dns_rdatatype_any);
|
||||
|
|
@ -236,6 +354,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t type) {
|
|||
fname = NULL;
|
||||
rdataset = NULL;
|
||||
db = NULL;
|
||||
version = NULL;
|
||||
node = NULL;
|
||||
|
||||
/*
|
||||
|
|
@ -256,12 +375,21 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t type) {
|
|||
if (result != ISC_R_SUCCESS && result != DNS_R_PARTIALMATCH)
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* Get the current version of this database.
|
||||
*/
|
||||
if (dns_db_iszone(db)) {
|
||||
version = query_findversion(client, db);
|
||||
if (version == NULL)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now look for an answer in the database.
|
||||
*/
|
||||
node = NULL;
|
||||
result = dns_db_find(db, name, NULL, type, client->query.dboptions,
|
||||
0, &node, fname, rdataset);
|
||||
result = dns_db_find(db, name, version, type, client->query.dboptions,
|
||||
client->requesttime, &node, fname, rdataset);
|
||||
switch (result) {
|
||||
case DNS_R_SUCCESS:
|
||||
case DNS_R_GLUE:
|
||||
|
|
@ -534,6 +662,7 @@ query_find(ns_client_t *client) {
|
|||
isc_buffer_t b;
|
||||
isc_result_t result, eresult;
|
||||
dns_fixedname_t fixed;
|
||||
dns_dbversion_t *version;
|
||||
|
||||
/*
|
||||
* One-time initialization.
|
||||
|
|
@ -550,6 +679,7 @@ query_find(ns_client_t *client) {
|
|||
rdataset = NULL;
|
||||
node = NULL;
|
||||
db = NULL;
|
||||
version = NULL;
|
||||
|
||||
if (client->view->cachedb == NULL ||
|
||||
client->view->resolver == NULL) {
|
||||
|
|
@ -593,9 +723,19 @@ query_find(ns_client_t *client) {
|
|||
}
|
||||
|
||||
is_zone = dns_db_iszone(db);
|
||||
if (is_zone)
|
||||
if (is_zone) {
|
||||
auth = ISC_TRUE;
|
||||
|
||||
/*
|
||||
* Get the current version of this database.
|
||||
*/
|
||||
version = query_findversion(client, db);
|
||||
if (version == NULL) {
|
||||
QUERY_ERROR(DNS_R_SERVFAIL);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the first unanswered type in the question section.
|
||||
*/
|
||||
|
|
@ -658,8 +798,8 @@ query_find(ns_client_t *client) {
|
|||
/*
|
||||
* Now look for an answer in the database.
|
||||
*/
|
||||
result = dns_db_find(db, client->query.qname, NULL, type, 0, 0, &node,
|
||||
fname, rdataset);
|
||||
result = dns_db_find(db, client->query.qname, version, type, 0,
|
||||
client->requesttime, &node, fname, rdataset);
|
||||
switch (result) {
|
||||
case DNS_R_SUCCESS:
|
||||
case DNS_R_ZONECUT:
|
||||
|
|
|
|||
Loading…
Reference in a new issue