Commit 9d308c62 authored by Bob Halley's avatar Bob Halley
Browse files

use only one database version per query

parent a2ce103c
......@@ -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:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment