Throttled answer while loading support (still needs config file hooks).

This commit is contained in:
Mark Andrews 2000-09-05 03:35:24 +00:00
parent 1162a4e02a
commit d22b4de3f1
9 changed files with 736 additions and 60 deletions

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.h,v 1.35 2000/08/01 01:12:16 tale Exp $ */
/* $Id: server.h,v 1.36 2000/09/05 03:35:16 marka Exp $ */
#ifndef NAMED_SERVER_H
#define NAMED_SERVER_H 1
@ -53,6 +53,7 @@ struct ns_server {
dns_aclenv_t aclenv;
/* Server data structures. */
dns_loadmgr_t * loadmgr;
dns_zonemgr_t * zonemgr;
ns_clientmgr_t * clientmgr;
dns_viewlist_t viewlist;

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.c,v 1.217 2000/08/31 12:15:07 marka Exp $ */
/* $Id: server.c,v 1.218 2000/09/05 03:35:14 marka Exp $ */
#include <config.h>
@ -38,6 +38,7 @@
#include <dns/forward.h>
#include <dns/journal.h>
#include <dns/keytable.h>
#include <dns/master.h>
#include <dns/peer.h>
#include <dns/rdatastruct.h>
#include <dns/resolver.h>
@ -429,6 +430,11 @@ configure_view(dns_view_t *view, dns_c_ctx_t *cctx, dns_c_view_t *cview,
port = 53;
dns_view_setdstport(view, port);
/*
* Attach load manager to view.
*/
dns_view_setloadmgr(view, ns_g_server->loadmgr);
/*
* Configure the view's cache. Try to reuse an existing
* cache if possible, otherwise create a new cache.
@ -1315,6 +1321,8 @@ load_configuration(const char *filename, ns_server_t *server,
configure_server_quota(cctx, dns_c_ctx_getrecursiveclients,
&server->recursionquota, 1000);
/* dns_loadmgr_setlimit(server->loadmgr, 20); XXXMPA */
/*
* Configure the zone manager.
*/
@ -1725,6 +1733,7 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
RUNTIME_CHECK(result == ISC_R_SUCCESS);
/* Initialize server data structures. */
server->loadmgr = NULL;
server->zonemgr = NULL;
server->clientmgr = NULL;
server->interfacemgr = NULL;
@ -1774,6 +1783,8 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
ns_g_socketmgr, &server->zonemgr),
"dns_zonemgr_create");
CHECKFATAL(dns_loadmgr_create(ns_g_mctx, &server->loadmgr),
"dns_loadmgr_create");
server->magic = NS_SERVER_MAGIC;
*serverp = server;
@ -1784,6 +1795,7 @@ ns_server_destroy(ns_server_t **serverp) {
ns_server_t *server = *serverp;
REQUIRE(NS_SERVER_VALID(server));
dns_loadmgr_detach(&server->loadmgr);
dns_zonemgr_detach(&server->zonemgr);
if (server->tkeyctx != NULL)

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: events.h,v 1.30 2000/08/31 12:15:14 marka Exp $ */
/* $Id: events.h,v 1.31 2000/09/05 03:35:21 marka Exp $ */
#ifndef DNS_EVENTS_H
#define DNS_EVENTS_H 1
@ -54,6 +54,7 @@
#define DNS_EVENT_ZONESTARTXFRIN (ISC_EVENTCLASS_DNS + 25)
#define DNS_EVENT_MASTERQUANTUM (ISC_EVENTCLASS_DNS + 26)
#define DNS_EVENT_CACHEOVERMEM (ISC_EVENTCLASS_DNS + 27)
#define DNS_EVENT_MASTERNEXTZONE (ISC_EVENTCLASS_DNS + 28)
#define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0)
#define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535)

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: master.h,v 1.23 2000/08/15 03:33:51 marka Exp $ */
/* $Id: master.h,v 1.24 2000/09/05 03:35:22 marka Exp $ */
#ifndef DNS_MASTER_H
#define DNS_MASTER_H 1
@ -96,6 +96,15 @@ dns_master_loadbufferinc(isc_buffer_t *buffer,
dns_loaddonefunc_t done, void *done_arg,
isc_mem_t *mctx);
isc_result_t
dns_master_loadfilequota(const char *master_file, dns_name_t *top,
dns_name_t *origin, dns_rdataclass_t zclass,
isc_boolean_t age_ttl, dns_rdatacallbacks_t *callbacks,
isc_task_t *task, dns_loaddonefunc_t done,
void *done_arg, dns_loadmgr_t *lmgr,
dns_loadctx_t **ctxp, isc_mem_t *mctx);
/*
* Loads a RFC 1305 master file from a file, stream, or buffer into rdatasets
* and then calls 'callbacks->commit' to commit the rdatasets. Rdata memory
@ -122,6 +131,8 @@ dns_master_loadbufferinc(isc_buffer_t *buffer,
* 'callbacks->done' points to a valid function or NULL.
* 'mctx' points to a valid memory context.
* 'task' and 'done' to be NULL or 'task' and 'done' to be valid.
* 'lmgr' to be valid.
* 'ctxp != NULL && ctxp == NULL'.
*
* Returns:
* ISC_R_SUCCESS upon successfully loading the master file.
@ -137,6 +148,103 @@ dns_master_loadbufferinc(isc_buffer_t *buffer,
* Any error code from callbacks->commit().
*/
void
dns_loadctx_detach(dns_loadctx_t **ctxp);
/*
* Detach from the load context.
*
* Requires:
* '*ctxp' to be valid.
*
* Ensures:
* '*ctxp == NULL'
*/
void
dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target);
/*
* Attach to the load context.
*
* Requires:
* 'source' to be valid.
* 'target != NULL && *target == NULL'.
*/
void
dns_loadctx_cancel(dns_loadctx_t *ctx);
/*
* Cancel loading the zone file associated with this load context.
*
* Requires:
* 'ctx' to be valid
*/
isc_result_t
dns_loadmgr_create(isc_mem_t *mctx, dns_loadmgr_t **mgrp);
/*
* Create a new load manager.
*
* Requires:
* 'mgrp != NULL && *mgrp == NULL'
*
* Returns:
* ISC_R_SUCCESS upon successfully creating a load manager.
* ISC_R_MEMORY
* ISC_R_UNEXPECTED
*/
void
dns_loadmgr_cancel(dns_loadmgr_t *mgr);
/*
* Cancel all queue loads. Loads that are already in progress are not
* canceled.
*
* Requires:
* 'mgr' to be valid.
*/
void
dns_loadmgr_attach(dns_loadmgr_t *source, dns_loadmgr_t **target);
/*
* Attach to the load manager.
*
* Requires:
* 'source' to be valid.
* 'target != NULL && *target == NULL'
*/
void
dns_loadmgr_detach(dns_loadmgr_t **mgrp);
/*
* Detach from the load manager.
*
* Requires:
* '*mgrp' to be valid.
*
* Ensures:
* '*mgr == NULL'
*/
void
dns_loadmgr_setlimit(dns_loadmgr_t *mgr, isc_uint32_t limit);
/*
* Set the number of simultaneous loads permitted by the load manager.
* 0 is unlimited.
*
* Requires:
* 'mgr' to be valid.
*/
isc_uint32_t
dns_loadmgr_getlimit(dns_loadmgr_t *mgr);
/*
* Return the number of simultaneous loads permitted by the load manager.
* 0 is unlimited.
*
* Requires:
* 'mgr' to be valid.
*/
ISC_LANG_ENDDECLS
#endif /* DNS_MASTER_H */

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: types.h,v 1.93 2000/08/24 22:15:37 bwelling Exp $ */
/* $Id: types.h,v 1.94 2000/09/05 03:35:23 marka Exp $ */
#ifndef DNS_TYPES_H
#define DNS_TYPES_H 1
@ -64,6 +64,8 @@ typedef isc_uint16_t dns_keyflags_t;
typedef struct dns_keynode dns_keynode_t;
typedef struct dns_keytable dns_keytable_t;
typedef isc_uint16_t dns_keytag_t;
typedef struct dns_loadctx dns_loadctx_t;
typedef struct dns_loadmgr dns_loadmgr_t;
typedef struct dns_message dns_message_t;
typedef isc_uint16_t dns_messageid_t;
typedef isc_region_t dns_label_t;

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: view.h,v 1.51 2000/08/25 01:16:04 bwelling Exp $ */
/* $Id: view.h,v 1.52 2000/09/05 03:35:24 marka Exp $ */
#ifndef DNS_VIEW_H
#define DNS_VIEW_H 1
@ -80,6 +80,7 @@ struct dns_view {
dns_zt_t * zonetable;
dns_resolver_t * resolver;
dns_adb_t * adb;
dns_loadmgr_t * loadmgr;
dns_requestmgr_t * requestmgr;
dns_cache_t * cache;
dns_db_t * cachedb;
@ -600,6 +601,9 @@ dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg);
* see dns_tsig_verify()
*/
void
dns_view_setloadmgr(dns_view_t *view, dns_loadmgr_t *loadmgr);
ISC_LANG_ENDDECLS
#endif /* DNS_VIEW_H */

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: master.c,v 1.63 2000/08/24 19:13:13 gson Exp $ */
/* $Id: master.c,v 1.64 2000/09/05 03:35:17 marka Exp $ */
#include <config.h>
@ -82,13 +82,12 @@ typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t;
/*
* Master file loading state that persists across $INCLUDEs.
*/
typedef struct loadctx loadctx_t;
struct loadctx {
struct dns_loadctx {
isc_uint32_t magic;
isc_mem_t *mctx;
isc_lex_t *lex;
loadctx_t *parent;
dns_loadctx_t *parent;
dns_rdatacallbacks_t *callbacks;
isc_task_t *task;
dns_loaddonefunc_t done;
@ -113,13 +112,38 @@ struct loadctx {
int origin_in_use;
unsigned int loop_cnt; /* records per quantum,
* 0 => all. */
isc_boolean_t canceled;
/* Rate limit goo. */
isc_boolean_t rate_limited;
ISC_LINK(dns_loadctx_t) link;
char *master_file;
dns_loadmgr_t *loadmgr;
isc_event_t event;
isc_mutex_t lock;
/* locked by lock */
isc_uint32_t references;
};
#define DNS_LCTX_MAGIC ISC_MAGIC('L','c','t','x')
#define DNS_LCTX_VALID(ctx) ISC_MAGIC_VALID(ctx, DNS_LCTX_MAGIC)
struct dns_loadmgr {
isc_uint32_t magic;
isc_mem_t *mctx;
isc_uint32_t erefs;
isc_uint32_t irefs;
isc_mutex_t lock;
isc_uint32_t active;
isc_uint32_t limit;
ISC_LIST(dns_loadctx_t) list;
};
#define DNS_LMGR_MAGIC ISC_MAGIC('L','m','g','r')
#define DNS_LMGR_VALID(ctx) ISC_MAGIC_VALID(ctx, DNS_LMGR_MAGIC)
static isc_result_t
pushfile(const char *master_file, dns_name_t *origin, loadctx_t **ctxp);
pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t **ctxp);
static isc_result_t
commit(dns_rdatacallbacks_t *, isc_lex_t *, rdatalist_head_t *, dns_name_t *,
@ -143,7 +167,25 @@ static void
load_quantum(isc_task_t *task, isc_event_t *event);
static isc_result_t
task_send(loadctx_t *ctx);
task_send(dns_loadctx_t *ctx);
static void
loadctx_destroy(dns_loadctx_t *ctx);
static void
loadmgr_start(isc_task_t *task, isc_event_t *event);
static void
loadmgr_cancel(dns_loadmgr_t *mgr);
static void
loadmgr_iattach(dns_loadmgr_t *source, dns_loadmgr_t **target);
static void
loadmgr_idetach(dns_loadmgr_t **mgrp);
static void
loadmgr_destroy(dns_loadmgr_t *mgr);
#define GETTOKEN(lexer, options, token, eol) \
do { \
@ -224,20 +266,52 @@ gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *token,
return (ISC_R_SUCCESS);
}
static void
loadctx_destroy(loadctx_t **ctxp) {
loadctx_t *ctx;
isc_mem_t *mctx;
void
dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) {
REQUIRE(target != NULL && *target == NULL);
REQUIRE(DNS_LCTX_VALID(source));
LOCK(&source->lock);
INSIST(source->references > 0);
source->references++;
INSIST(source->references != 0); /* Overflow? */
UNLOCK(&source->lock);
*target = source;
}
void
dns_loadctx_detach(dns_loadctx_t **ctxp) {
dns_loadctx_t *ctx;
isc_boolean_t need_destroy = ISC_FALSE;
REQUIRE(ctxp != NULL);
ctx = *ctxp;
REQUIRE(DNS_LCTX_VALID(ctx));
LOCK(&ctx->lock);
INSIST(ctx->references > 0);
ctx->references--;
if (ctx->references == 0)
need_destroy = ISC_TRUE;
UNLOCK(&ctx->lock);
if (need_destroy)
loadctx_destroy(ctx);
*ctxp = NULL;
}
static void
loadctx_destroy(dns_loadctx_t *ctx) {
isc_mem_t *mctx;
REQUIRE(DNS_LCTX_VALID(ctx));
ctx->magic = 0;
if (ctx->parent != NULL)
loadctx_destroy(&ctx->parent);
dns_loadctx_detach(&ctx->parent);
if (ctx->lex != NULL) {
isc_lex_close(ctx->lex);
@ -245,6 +319,13 @@ loadctx_destroy(loadctx_t **ctxp) {
}
if (ctx->task != NULL)
isc_task_detach(&ctx->task);
if (ctx->master_file != NULL) {
isc_mem_free(ctx->mctx, ctx->master_file);
ctx->master_file = NULL;
}
if (ctx->loadmgr != NULL)
loadmgr_idetach(&ctx->loadmgr);
DESTROYLOCK(&ctx->lock);
mctx = NULL;
isc_mem_attach(ctx->mctx, &mctx);
isc_mem_detach(&ctx->mctx);
@ -257,9 +338,9 @@ loadctx_create(isc_mem_t *mctx, isc_boolean_t age_ttl, dns_name_t *top,
dns_rdataclass_t zclass, dns_name_t *origin,
dns_rdatacallbacks_t *callbacks, isc_task_t *task,
dns_loaddonefunc_t done, void *done_arg,
loadctx_t **ctxp)
dns_loadctx_t **ctxp)
{
loadctx_t *ctx;
dns_loadctx_t *ctx;
isc_result_t result;
isc_region_t r;
int i;
@ -279,6 +360,14 @@ loadctx_create(isc_mem_t *mctx, isc_boolean_t age_ttl, dns_name_t *top,
ctx = isc_mem_get(mctx, sizeof(*ctx));
if (ctx == NULL)
return (ISC_R_NOMEMORY);
result = isc_mutex_init(&ctx->lock);
if (result != ISC_R_SUCCESS) {
isc_mem_put(mctx, ctx, sizeof *ctx);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_mutex_init() failed: %s",
isc_result_totext(result));
return (ISC_R_UNEXPECTED);
}
ctx->lex = NULL;
result = isc_lex_create(mctx, TOKENSIZ, &ctx->lex);
@ -328,8 +417,18 @@ loadctx_create(isc_mem_t *mctx, isc_boolean_t age_ttl, dns_name_t *top,
ctx->done = done;
ctx->done_arg = done_arg;
ctx->rate_limited = ISC_FALSE;
ctx->master_file = NULL;
ctx->loadmgr = NULL;
ISC_LINK_INIT(ctx, link);
ISC_EVENT_INIT(&ctx->event, sizeof(ctx->event), 0, NULL,
DNS_EVENT_MASTERNEXTZONE, loadmgr_start,
ctx, ctx, NULL, NULL);
ctx->canceled = ISC_FALSE;
ctx->mctx = NULL;
isc_mem_attach(mctx, &ctx->mctx);
ctx->references = 1; /* Implicit attach. */
ctx->magic = DNS_LCTX_MAGIC;
*ctxp = ctx;
return (ISC_R_SUCCESS);
@ -340,7 +439,7 @@ loadctx_create(isc_mem_t *mctx, isc_boolean_t age_ttl, dns_name_t *top,
}
static isc_result_t
load(loadctx_t **ctxp) {
load(dns_loadctx_t **ctxp) {
dns_rdataclass_t rdclass;
dns_rdatatype_t type, covers;
isc_uint32_t ttl_offset = 0;
@ -376,7 +475,7 @@ load(loadctx_t **ctxp) {
unsigned int loop_cnt = 0;
isc_mem_t *mctx;
dns_rdatacallbacks_t *callbacks;
loadctx_t *ctx;
dns_loadctx_t *ctx;
ctx = *ctxp;
@ -416,7 +515,7 @@ load(loadctx_t **ctxp) {
CTX_COPYVAR(ctx, *ctxp, ttl);
CTX_COPYVAR(ctx, *ctxp, default_ttl);
CTX_COPYVAR(ctx, *ctxp, warn_1035);
loadctx_destroy(&ctx);
dns_loadctx_detach(&ctx);
ctx = *ctxp;
continue;
}
@ -993,10 +1092,10 @@ load(loadctx_t **ctxp) {
}
static isc_result_t
pushfile(const char *master_file, dns_name_t *origin, loadctx_t **ctxp) {
pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t **ctxp) {
isc_result_t result;
loadctx_t *ctx;
loadctx_t *new = NULL;
dns_loadctx_t *ctx;
dns_loadctx_t *new = NULL;
isc_region_t r;
int new_in_use;
@ -1043,7 +1142,7 @@ pushfile(const char *master_file, dns_name_t *origin, loadctx_t **ctxp) {
cleanup:
if (new != NULL)
loadctx_destroy(&new);
dns_loadctx_detach(&new);
return (result);
}
@ -1053,7 +1152,7 @@ dns_master_loadfile(const char *master_file, dns_name_t *top,
dns_rdataclass_t zclass, isc_boolean_t age_ttl,
dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
{
loadctx_t *ctx = NULL;
dns_loadctx_t *ctx = NULL;
isc_result_t result;
result = loadctx_create(mctx, age_ttl, top, zclass, origin,
@ -1070,10 +1169,110 @@ dns_master_loadfile(const char *master_file, dns_name_t *top,
cleanup:
if (ctx != NULL)
loadctx_destroy(&ctx);
dns_loadctx_detach(&ctx);
return (result);
}
isc_result_t
dns_master_loadfilequota(const char *master_file, dns_name_t *top,
dns_name_t *origin, dns_rdataclass_t zclass,
isc_boolean_t age_ttl, dns_rdatacallbacks_t *callbacks, isc_task_t *task, dns_loaddonefunc_t done,
void *done_arg, dns_loadmgr_t *lmgr,
dns_loadctx_t **ctxp, isc_mem_t *mctx)
{
isc_boolean_t queue;
dns_loadctx_t *ctx = NULL;
isc_result_t result;
isc_event_t *event;
REQUIRE(DNS_LMGR_VALID(lmgr));
REQUIRE(ctxp != NULL && *ctxp == NULL);
result = loadctx_create(mctx, age_ttl, top, zclass, origin,
callbacks, task, done, done_arg, &ctx);
if (result != ISC_R_SUCCESS)
goto cleanup;
ctx->rate_limited = ISC_TRUE;
ctx->master_file = isc_mem_strdup(mctx, master_file);
if (ctx->master_file == NULL) {
result = ISC_R_NOMEMORY;
goto cleanup;
}
loadmgr_iattach(lmgr, &ctx->loadmgr);
LOCK(&lmgr->lock);
lmgr->active++;
queue = ISC_TF((lmgr->limit != 0 && lmgr->active > lmgr->limit));
if (queue)
ISC_LIST_APPEND(lmgr->list, ctx, link);
INSIST(queue || ISC_LIST_EMPTY(lmgr->list));
UNLOCK(&lmgr->lock);
dns_loadctx_attach(ctx, ctxp);
result = DNS_R_CONTINUE;
if (!queue) {
event = &ctx->event;
isc_task_send(ctx->task, &event);
}
return (result);
cleanup:
if (ctx != NULL)
dns_loadctx_detach(&ctx);
return (result);
}
static void
loadmgr_done(dns_loadctx_t *ctx, isc_result_t result) {
dns_loadctx_t *next;
isc_event_t *event;
if (ctx->done != NULL)
(ctx->done)(ctx->done_arg, result);
LOCK(&ctx->loadmgr->lock);
INSIST(ctx->loadmgr->active > 0);
ctx->loadmgr->active--;
/* dequeue */
next = ISC_LIST_HEAD(ctx->loadmgr->list);
if (next != NULL)
ISC_LIST_UNLINK(ctx->loadmgr->list, next, link);
UNLOCK(&ctx->loadmgr->lock);
if (next != NULL) {
event = &next->event;
isc_task_send(next->task, &event);
}
}
static void
loadmgr_start(isc_task_t *task, isc_event_t *event) {
dns_loadctx_t *ctx = event->ev_arg;
isc_result_t result;
INSIST(task == ctx->task);
if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0) {
result = ISC_R_CANCELED;
goto done;
}
result = isc_lex_openfile(ctx->lex, ctx->master_file);
if (result == ISC_R_SUCCESS)
result = load(&ctx);
if (result == DNS_R_CONTINUE) {
result = task_send(ctx);
if (result == ISC_R_SUCCESS)
isc_event_free(&event);
return;
}
done:
loadmgr_done(ctx, result);
isc_event_free(&event);
dns_loadctx_detach(&ctx);
return;
}
isc_result_t
dns_master_loadfileinc(const char *master_file, dns_name_t *top,
dns_name_t *origin, dns_rdataclass_t zclass,
@ -1081,7 +1280,7 @@ dns_master_loadfileinc(const char *master_file, dns_name_t *top,
isc_task_t *task, dns_loaddonefunc_t done,
void *done_arg, isc_mem_t *mctx)
{
loadctx_t *ctx = NULL;
dns_loadctx_t *ctx = NULL;
isc_result_t tresult;
isc_result_t result;
@ -1106,7 +1305,7 @@ dns_master_loadfileinc(const char *master_file, dns_name_t *top,
cleanup:
if (ctx != NULL)
loadctx_destroy(&ctx);
dns_loadctx_detach(&ctx);
return (result);
}
@ -1116,7 +1315,7 @@ dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
{
isc_result_t result;
loadctx_t *ctx = NULL;
dns_loadctx_t *ctx = NULL;
REQUIRE(stream != NULL);
@ -1134,7 +1333,7 @@ dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
cleanup:
if (ctx != NULL)
loadctx_destroy(&ctx);
dns_loadctx_detach(&ctx);
return (result);
}
@ -1147,7 +1346,7 @@ dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin,
{
isc_result_t result;
isc_result_t tresult;
loadctx_t *ctx = NULL;
dns_loadctx_t *ctx = NULL;
REQUIRE(stream != NULL);
@ -1172,7 +1371,7 @@ dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin,
cleanup:
if (ctx != NULL)
loadctx_destroy(&ctx);
dns_loadctx_detach(&ctx);
return (result);
}
@ -1183,7 +1382,7 @@ dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top,
dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
{
isc_result_t result;
loadctx_t *ctx = NULL;
dns_loadctx_t *ctx = NULL;
REQUIRE(buffer != NULL);
@ -1201,7 +1400,7 @@ dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top,
cleanup:
if (ctx != NULL)
loadctx_destroy(&ctx);
dns_loadctx_detach(&ctx);
return (result);
}
@ -1215,7 +1414,7 @@ dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top,
{
isc_result_t result;
isc_result_t tresult;
loadctx_t *ctx = NULL;
dns_loadctx_t *ctx = NULL;
REQUIRE(buffer != NULL);
@ -1240,7 +1439,7 @@ dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top,
cleanup:
if (ctx != NULL)
loadctx_destroy(&ctx);
dns_loadctx_detach(&ctx);
return (result);
}
@ -1458,30 +1657,36 @@ on_list(dns_rdatalist_t *rdatalist, dns_rdata_t *rdata) {
static void
load_quantum(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
loadctx_t *ctx;
dns_loadctx_t *ctx;
REQUIRE(event != NULL);
ctx = event->ev_arg;
REQUIRE(DNS_LCTX_VALID(ctx));
result = load(&ctx);
if (ctx->canceled)
result = ISC_R_CANCELED;
else
result = load(&ctx);
if (result == DNS_R_CONTINUE) {
isc_task_send(task, &event);
} else if (result == ISC_R_SUCCESS && ctx->parent) {
/* Pop ctx and continue. */
event->ev_arg = ctx->parent;
ctx->parent = NULL;
loadctx_destroy(&ctx);
dns_loadctx_detach(&ctx);
isc_task_send(task, &event);
} else {
(ctx->done)(ctx->done_arg, result);
if (ctx->rate_limited)
loadmgr_done(ctx, result);
else
(ctx->done)(ctx->done_arg, result);
isc_event_free(&event);
loadctx_destroy(&ctx);
dns_loadctx_detach(&ctx);
}
}
static isc_result_t
task_send(loadctx_t *ctx) {
task_send(dns_loadctx_t *ctx) {
isc_event_t *event;
event = isc_event_allocate(ctx->mctx, NULL,
@ -1492,3 +1697,181 @@ task_send(loadctx_t *ctx) {
isc_task_send(ctx->task, &event);
return (ISC_R_SUCCESS);
}
/*
* DNS load manager.
*/
isc_result_t
dns_loadmgr_create(isc_mem_t *mctx, dns_loadmgr_t **mgrp) {
dns_loadmgr_t *mgr;
isc_result_t result;
REQUIRE(mgrp != NULL && *mgrp == NULL);
mgr = isc_mem_get(mctx, sizeof(*mgr));
if (mgr == NULL)
return (ISC_R_NOMEMORY);
result = isc_mutex_init(&mgr->lock);
if (result != ISC_R_SUCCESS) {
isc_mem_put(mctx, mgr, sizeof(*mgr));
return (result);
}
mgr->erefs = 1;
mgr->irefs = 0;
mgr->limit = 0;
mgr->active = 0;
mgr->mctx = NULL;
isc_mem_attach(mctx, &mgr->mctx);
ISC_LIST_INIT(mgr->list);
mgr->magic = DNS_LMGR_MAGIC;
*mgrp = mgr;
return (ISC_R_SUCCESS);
}
void
dns_loadmgr_setlimit(dns_loadmgr_t *mgr, isc_uint32_t limit) {
REQUIRE(DNS_LMGR_VALID(mgr));
mgr->limit = limit;
}
isc_uint32_t
dns_loadmgr_getlimit(dns_loadmgr_t *mgr) {
REQUIRE(DNS_LMGR_VALID(mgr));
return(mgr->limit);
}
void
dns_loadmgr_cancel(dns_loadmgr_t *mgr) {
REQUIRE(DNS_LMGR_VALID(mgr));
LOCK(&mgr->lock);
loadmgr_cancel(mgr);
UNLOCK(&mgr->lock);
}
static void
loadmgr_cancel(dns_loadmgr_t *mgr) {
dns_loadctx_t *ctx;
isc_event_t *event;
for (ctx = ISC_LIST_HEAD(mgr->list); ctx != NULL; ) {
ISC_LIST_UNLINK(mgr->list, ctx, link);
event = &ctx->event;
event->ev_attributes |= ISC_EVENTATTR_CANCELED;
isc_task_send(ctx->task, &event);
}
}
void
dns_loadctx_cancel(dns_loadctx_t *ctx) {
isc_event_t *event;
REQUIRE(DNS_LCTX_VALID(ctx));
LOCK(&ctx->lock);
ctx->canceled = ISC_TRUE;
/*
* If we are queued to be run dequeue.
*/
if (ctx->loadmgr != NULL && ISC_LINK_LINKED(ctx, link)) {
LOCK(&ctx->loadmgr->lock);
ISC_LIST_UNLINK(ctx->loadmgr->list, ctx, link);
UNLOCK(&ctx->loadmgr->lock);
event = &ctx->event;
event->ev_attributes |= ISC_EVENTATTR_CANCELED;
isc_task_send(ctx->task, &event);
}
UNLOCK(&ctx->lock);
}
void
dns_loadmgr_attach(dns_loadmgr_t *source, dns_loadmgr_t **target) {
REQUIRE(DNS_LMGR_VALID(source));
REQUIRE(target != NULL && *target == NULL);
LOCK(&source->lock);
INSIST(source->erefs != 0);
source->erefs++;
INSIST(source->erefs != 0); /* Overflow? */
UNLOCK(&source->lock);
*target = source;
}
void
dns_loadmgr_detach(dns_loadmgr_t **mgrp) {
dns_loadmgr_t *mgr;
isc_boolean_t destroy = ISC_FALSE;
REQUIRE(mgrp != NULL);
mgr = *mgrp;
REQUIRE(DNS_LMGR_VALID(mgr));
mgrp = NULL;
LOCK(&mgr->lock);
INSIST(mgr->erefs != 0);
mgr->erefs--;
if (mgr->erefs == 0) {
if (mgr->irefs == 0)
destroy = ISC_TRUE;
else
loadmgr_cancel(mgr);
}
UNLOCK(&mgr->lock);
if (destroy)
loadmgr_destroy(mgr);
}
static void
loadmgr_iattach(dns_loadmgr_t *source, dns_loadmgr_t **target) {
REQUIRE(DNS_LMGR_VALID(source));
REQUIRE(target != NULL && *target == NULL);
LOCK(&source->lock);
source->irefs++;
INSIST(source->irefs != 0); /* Overflow? */
UNLOCK(&source->lock);
*target = source;
}
static void
loadmgr_idetach(dns_loadmgr_t **mgrp) {
dns_loadmgr_t *mgr;
isc_boolean_t destroy = ISC_FALSE;
REQUIRE(mgrp != NULL);
mgr = *mgrp;
REQUIRE(DNS_LMGR_VALID(mgr));
mgrp = NULL;
LOCK(&mgr->lock);
INSIST(mgr->irefs != 0);
mgr->irefs--;
if (mgr->erefs == 0 && mgr->irefs == 0)
destroy = ISC_TRUE;
UNLOCK(&mgr->lock);
if (destroy)
loadmgr_destroy(mgr);
}
static void
loadmgr_destroy(dns_loadmgr_t *mgr) {
INSIST(ISC_LIST_EMPTY(mgr->list));
mgr->magic = 0;
DESTROYLOCK(&mgr->lock);
isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
}

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: view.c,v 1.78 2000/08/26 01:36:59 bwelling Exp $ */
/* $Id: view.c,v 1.79 2000/09/05 03:35:18 marka Exp $ */
#include <config.h>
@ -127,6 +127,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->hints = NULL;
view->resolver = NULL;
view->adb = NULL;
view->loadmgr = NULL;
view->requestmgr = NULL;
view->mctx = mctx;
view->rdclass = rdclass;
@ -228,6 +229,8 @@ destroy(dns_view_t *view) {
dns_adb_detach(&view->adb);
if (view->resolver != NULL)
dns_resolver_detach(&view->resolver);
if (view->loadmgr != NULL)
dns_loadmgr_detach(&view->loadmgr);
if (view->requestmgr != NULL)
dns_requestmgr_detach(&view->requestmgr);
if (view->task != NULL)
@ -523,6 +526,15 @@ dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
view->dstport = dstport;
}
void
dns_view_setloadmgr(dns_view_t *view, dns_loadmgr_t *loadmgr) {
REQUIRE(DNS_VIEW_VALID(view));
if (view->loadmgr != NULL)
dns_loadmgr_detach(&view->loadmgr);
dns_loadmgr_attach(loadmgr, &view->loadmgr);
}
isc_result_t
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
isc_result_t result;

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.c,v 1.200 2000/08/31 06:16:42 marka Exp $ */
/* $Id: zone.c,v 1.201 2000/09/05 03:35:19 marka Exp $ */
#include <config.h>
@ -30,10 +30,12 @@
#include <dns/acl.h>
#include <dns/adb.h>
#include <dns/callbacks.h>
#include <dns/db.h>
#include <dns/events.h>
#include <dns/journal.h>
#include <dns/log.h>
#include <dns/master.h>
#include <dns/masterdump.h>
#include <dns/message.h>
#include <dns/name.h>
@ -54,6 +56,7 @@
#define NOTIFY_MAGIC 0x4e746679U /* Ntfy */
#define STUB_MAGIC 0x53747562U /* Stub */
#define ZONEMGR_MAGIC 0x5a6d6772U /* Zmgr */
#define LOAD_MAGIC ISC_MAGIC('L','o','a','d')
#define DNS_ZONE_VALID(zone) \
ISC_MAGIC_VALID(zone, ZONE_MAGIC)
@ -63,6 +66,9 @@
ISC_MAGIC_VALID(stub, STUB_MAGIC)
#define DNS_ZONEMGR_VALID(stub) \
ISC_MAGIC_VALID(stub, ZONEMGR_MAGIC)
#define DNS_LOAD_VALID(load) \
ISC_MAGIC_VALID(load, LOAD_MAGIC)
#define RANGE(a, b, c) (((a) < (b)) ? (b) : ((a) < (c) ? (a) : (c)))
@ -79,6 +85,7 @@
typedef struct dns_notify dns_notify_t;
typedef struct dns_stub dns_stub_t;
typedef struct dns_load dns_load_t;
struct dns_zone {
/* Unlocked */
@ -146,6 +153,7 @@ struct dns_zone {
dns_severity_t check_names;
ISC_LIST(dns_notify_t) notifies;
dns_request_t *request;
dns_loadctx_t *loadctx;
isc_uint32_t maxxfrin;
isc_uint32_t maxxfrout;
isc_uint32_t idlein;
@ -186,6 +194,7 @@ struct dns_zone {
#define DNS_ZONEFLG_NOMASTERS 0x00001000U /* an attempt to refresh a
* zone with no masters
* occured */
#define DNS_ZONEFLG_LOADING 0x00002000U /* load from disk in progress */
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
@ -246,6 +255,18 @@ struct dns_stub {
dns_dbversion_t *version;
};
/*
* Hold load state.
*/
struct dns_load {
isc_int32_t magic;
isc_mem_t *mctx;
dns_zone_t *zone;
dns_db_t *db;
isc_time_t loadtime;
dns_rdatacallbacks_t callbacks;
};
static isc_result_t zone_settimer(dns_zone_t *, isc_stdtime_t);
static void cancel_refresh(dns_zone_t *);
@ -261,7 +282,12 @@ static isc_result_t zone_replacedb(dns_zone_t *zone, dns_db_t *db,
isc_boolean_t dump);
static isc_result_t default_journal(dns_zone_t *zone);
static void zone_xfrdone(dns_zone_t *zone, isc_result_t result);
static isc_result_t zone_postload(dns_zone_t *zone, dns_db_t *db,
isc_time_t loadtime, isc_result_t result);
static void zone_shutdown(isc_task_t *, isc_event_t *);
static void zone_loaddone(void *arg, isc_result_t result);
static isc_result_t zone_startload(dns_db_t *db, dns_zone_t *zone,
isc_time_t loadtime);
#if 0
/* ondestroy example */
@ -389,6 +415,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->xfr_acl = NULL;
zone->check_names = dns_severity_ignore;
zone->request = NULL;
zone->loadctx = NULL;
zone->timer = NULL;
zone->idlein = DNS_DEFAULT_IDLEIN;
zone->idleout = DNS_DEFAULT_IDLEOUT;
@ -443,6 +470,8 @@ zone_free(dns_zone_t *zone) {
isc_timer_detach(&zone->timer);
if (zone->request != NULL)
dns_request_destroy(&zone->request); /* XXXMPA */
if (zone->loadctx != NULL)
dns_loadctx_detach(&zone->loadctx);
INSIST(zone->statelist == NULL);
@ -708,9 +737,6 @@ dns_zone_getjournal(dns_zone_t *zone) {
isc_result_t
dns_zone_load(dns_zone_t *zone) {
const char me[] = "dns_zone_load";
unsigned int soacount = 0;
unsigned int nscount = 0;
isc_uint32_t serial, refresh, retry, expire, minimum;
isc_result_t result;
isc_stdtime_t now;
isc_time_t loadtime, filetime;
@ -770,7 +796,88 @@ dns_zone_load(dns_zone_t *zone) {
goto cleanup;
if (!dns_db_ispersistent(db))
result = zone_startload(db, zone, loadtime);
if (result == DNS_R_CONTINUE) {
zone->flags |= DNS_ZONEFLG_LOADING;
result = ISC_R_SUCCESS;
goto cleanup;
}
result = zone_postload(zone, db, loadtime, result);
cleanup:
UNLOCK(&zone->lock);
if (db != NULL)
dns_db_detach(&db);
return (result);
}
static isc_result_t
zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
dns_load_t *load;
isc_result_t result;
isc_result_t tresult;
if (zone->view != NULL && zone->view->loadmgr != NULL &&
zone->db != NULL) {
load = isc_mem_get(zone->mctx, sizeof(*load));
if (load == NULL)
return (ISC_R_NOMEMORY);
load->mctx = NULL;
load->zone = NULL;
load->db = NULL;
load->loadtime = loadtime;
load->magic = LOAD_MAGIC;
isc_mem_attach(zone->mctx, &load->mctx);
dns_zone_iattach(zone, &load->zone);
dns_db_attach(db, &load->db);
dns_rdatacallbacks_init(&load->callbacks);
result = dns_db_beginload(db, &load->callbacks.add,
&load->callbacks.add_private);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = dns_master_loadfilequota(zone->dbname,
dns_db_origin(db),
dns_db_origin(db),
zone->rdclass, ISC_FALSE,
&load->callbacks, zone->task,
zone_loaddone, load,
zone->view->loadmgr,
&zone->loadctx, zone->mctx);
if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) {
tresult = dns_db_endload(load->db,
&load->callbacks.add_private);
if (result == ISC_R_SUCCESS)
result = tresult;
}
} else {
result = dns_db_load(db, zone->dbname);
}
return (result);
cleanup:
load->magic = 0;
dns_db_detach(&load->db);
dns_zone_idetach(&load->zone);
isc_mem_detach(&load->mctx);
isc_mem_put(zone->mctx, load, sizeof(*load));
return (result);
}
static isc_result_t
zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
isc_result_t result)
{
const char me[] = "dns_zone_load";
unsigned int soacount = 0;
unsigned int nscount = 0;
isc_uint32_t serial, refresh, retry, expire, minimum;
isc_stdtime_t now;
/*
* Initiate zone transfer? We may need a error code that
@ -780,8 +887,14 @@ dns_zone_load(dns_zone_t *zone) {
if (result != ISC_R_SUCCESS) {
if (zone->type == dns_zone_slave ||
zone->type == dns_zone_stub) {
zone_log(zone, me, ISC_LOG_INFO,
"no database file");
if (result == ISC_R_FILENOTFOUND)
zone_log(zone, me, ISC_LOG_INFO,
"no database file");
else
zone_log(zone, me, ISC_LOG_ERROR,
"database %s: dns_db_load failed: %s",
zone->dbname,
dns_result_totext(result));
/* Mark the zone for immediate refresh. */
zone->refreshtime = now;
result = ISC_R_SUCCESS;
@ -797,6 +910,7 @@ dns_zone_load(dns_zone_t *zone) {
"number of nodes in database: %u",
dns_db_nodecount(db));
zone->loadtime = loadtime;
isc_stdtime_get(&now);
zone_log(zone, me, ISC_LOG_DEBUG(1), "loaded");
@ -914,11 +1028,10 @@ dns_zone_load(dns_zone_t *zone) {
zone->flags |= DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY;
}
result = ISC_R_SUCCESS;
if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING))
(void) zone_settimer(zone, now);
cleanup:
UNLOCK(&zone->lock);
if (db != NULL)
dns_db_detach(&db);
return (result);
}
@ -1579,7 +1692,7 @@ dns_zone_refresh(dns_zone_t *zone) {
}
zone->flags |= DNS_ZONEFLG_REFRESH;
UNLOCK(&zone->lock);
if ((oldflags & DNS_ZONEFLG_REFRESH) != 0)
if ((oldflags & (DNS_ZONEFLG_REFRESH|DNS_ZONEFLG_LOADING)) != 0)
return;
/*
@ -3111,6 +3224,9 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
if (zone->request != NULL)
dns_request_cancel(zone->request);
if (zone->loadctx != NULL)
dns_loadctx_cancel(zone->loadctx);
notify_cancel(zone);
if (zone->timer != NULL) {
@ -3387,6 +3503,7 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
dns_rdata_t rdata;
isc_result_t result;
isc_stdtime_t now;
char fromtext[ISC_SOCKADDR_FORMATSIZE];
#ifndef NOMINUM_PUBLIC
int match = 0;
isc_netaddr_t netaddr;
@ -3415,6 +3532,8 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
* first address to check. Return ISC_R_SUCCESS.
*/
isc_sockaddr_format(from, fromtext, sizeof(fromtext));
/*
* We only handle NOTIFY (SOA) at the present.
*/
@ -3426,7 +3545,7 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
UNLOCK(&zone->lock);
if (msg->counts[DNS_SECTION_QUESTION] == 0) {
zone_log(zone, me, ISC_LOG_NOTICE,
"FORMERR no question");
"FORMERR no question: %s", fromtext);
return (DNS_R_FORMERR);
}
zone_log(zone, me, ISC_LOG_NOTICE,
@ -3465,7 +3584,7 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
if (i >= zone->masterscnt) {
UNLOCK(&zone->lock);
zone_log(zone, me, ISC_LOG_DEBUG(3),
"REFUSED notify from non master");
"REFUSED notify from non master: %s", fromtext);
return (DNS_R_REFUSED);
}
@ -3494,7 +3613,8 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
serial = soa.serial;
if (isc_serial_le(serial, zone->serial)) {
zone_log(zone, me, ISC_LOG_DEBUG(3),
"zone up to date");
"zone up to date: %s",
fromtext);
UNLOCK(&zone->lock);
return (ISC_R_SUCCESS);
}
@ -3520,7 +3640,8 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
zone->notifyfrom = *from;
UNLOCK(&zone->lock);
zone_log(zone, me, ISC_LOG_DEBUG(3),
"refresh in progress, refresh check queued");
"refresh in progress, refresh check queued: %s",
fromtext);
return (ISC_R_SUCCESS);
}
isc_stdtime_get(&now);
@ -3528,7 +3649,8 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
zone->notifyfrom = *from;
zone_settimer(zone, now);
UNLOCK(&zone->lock);
zone_log(zone, me, ISC_LOG_DEBUG(3), "immediate refresh check queued");
zone_log(zone, me, ISC_LOG_DEBUG(3), "immediate refresh check queued: %s",
fromtext);
return (ISC_R_SUCCESS);
}
@ -4081,6 +4203,37 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
queue_soa_query(zone);
}
static void
zone_loaddone(void *arg, isc_result_t result) {
static char me[] = "zone_loaddone";
dns_load_t *load = arg;
dns_zone_t *zone;
isc_result_t tresult;
isc_mem_t *mctx;
REQUIRE(DNS_LOAD_VALID(load));
zone = load->zone;
mctx = load->mctx;
DNS_ENTER;
tresult = dns_db_endload(load->db, &load->callbacks.add_private);
if (result == ISC_R_SUCCESS)
result = tresult;
LOCK(&load->zone->lock);
(void)zone_postload(load->zone, load->db, load->loadtime, result);
load->zone->flags &= ~DNS_ZONEFLG_LOADING;
UNLOCK(&load->zone->lock);
load->magic = 0;
dns_db_detach(&load->db);
dns_loadctx_detach(&zone->loadctx);
dns_zone_idetach(&zone);
isc_mem_put(mctx, load, sizeof (*load));
isc_mem_detach(&mctx);
}
void
dns_zone_getssutable(dns_zone_t *zone, dns_ssutable_t **table) {
REQUIRE(DNS_ZONE_VALID(zone));