From 9aba20edee4e704433a464ae43b070b0775de506 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Tue, 4 Sep 2001 14:18:31 +0000 Subject: [PATCH] 979. [func] Incremental master file dumping. dns_master_dumpinc(), dns_master_dumptostreaminc(), dns_dumpctx_attach(), dns_dumpctx_detach() and dns_dumpctx_cancel(). --- CHANGES | 4 + lib/dns/include/dns/events.h | 3 +- lib/dns/include/dns/masterdump.h | 53 ++- lib/dns/include/dns/types.h | 6 +- lib/dns/masterdump.c | 586 ++++++++++++++++++++++++------- 5 files changed, 513 insertions(+), 139 deletions(-) diff --git a/CHANGES b/CHANGES index d276096484..511f53c80d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ + 979. [func] Incremental master file dumping. dns_master_dumpinc(), + dns_master_dumptostreaminc(), dns_dumpctx_attach(), + dns_dumpctx_detach() and dns_dumpctx_cancel(). + 978. [bug] dns_db_attachversion() had an invalid REQUIRE() condition. diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h index 6f3db80bb9..962bd248f6 100644 --- a/lib/dns/include/dns/events.h +++ b/lib/dns/include/dns/events.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: events.h,v 1.37 2001/02/13 02:49:07 gson Exp $ */ +/* $Id: events.h,v 1.38 2001/09/04 14:18:28 marka Exp $ */ #ifndef DNS_EVENTS_H #define DNS_EVENTS_H 1 @@ -60,6 +60,7 @@ #define DNS_EVENT_QUERYABORTED (ISC_EVENTCLASS_DNS + 31) #define DNS_EVENT_DISPATCHCONTROL (ISC_EVENTCLASS_DNS + 32) #define DNS_EVENT_REQUESTCONTROL (ISC_EVENTCLASS_DNS + 33) +#define DNS_EVENT_DUMPQUANTUM (ISC_EVENTCLASS_DNS + 34) #define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0) #define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535) diff --git a/lib/dns/include/dns/masterdump.h b/lib/dns/include/dns/masterdump.h index 509e6fa39f..255847b926 100644 --- a/lib/dns/include/dns/masterdump.h +++ b/lib/dns/include/dns/masterdump.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: masterdump.h,v 1.22 2001/07/16 05:10:25 mayer Exp $ */ +/* $Id: masterdump.h,v 1.23 2001/09/04 14:18:29 marka Exp $ */ #ifndef DNS_MASTERDUMP_H #define DNS_MASTERDUMP_H 1 @@ -89,6 +89,44 @@ LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_debug; *** Functions ***/ +void +dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target); +/* + * Attach to a dump context. + * + * Require: + * 'source' to be valid. + * 'target' to be non NULL and '*target' to be NULL. + */ + +void +dns_dumpctx_detach(dns_dumpctx_t **dctxp); +/* + * Detach from a dump context. + * + * Require: + * 'dctxp' to point to a valid dump context. + * + * Ensures: + * '*dctxp' is NULL. + */ + +void +dns_dumpctx_cancel(dns_dumpctx_t *dctx); +/* + * Cancel a in progress dump. + * + * Require: + * 'dctx' to be valid. + */ + +isc_result_t +dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db, + dns_dbversion_t *version, + const dns_master_style_t *style, FILE *f, + isc_task_t *task, dns_dumpdonefunc_t done, + void *done_arg, dns_dumpctx_t **dctxp); + isc_result_t dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, @@ -100,13 +138,25 @@ dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, * * Temporary dynamic memory may be allocated from 'mctx'. * + * Require: + * 'task' to be valid. + * 'done' to be non NULL. + * 'dctxp' to be non NULL && '*dctxp' to be NULL. + * * Returns: * ISC_R_SUCCESS + * ISC_R_CONTINUE dns_master_dumptostreaminc() only. * ISC_R_NOMEMORY * Any database or rrset iterator error. * Any dns_rdata_totext() error code. */ +isc_result_t +dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, + const dns_master_style_t *style, const char *filename, + isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, + dns_dumpctx_t **dctxp); + isc_result_t dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, @@ -120,6 +170,7 @@ dns_master_dump(isc_mem_t *mctx, dns_db_t *db, * * Returns: * ISC_R_SUCCESS + * ISC_R_CONTINUE dns_master_dumpinc() only. * ISC_R_NOMEMORY * Any database or rrset iterator error. * Any dns_rdata_totext() error code. diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index a0478ed141..6d67b8691a 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.103 2001/07/23 17:55:37 gson Exp $ */ +/* $Id: types.h,v 1.104 2001/09/04 14:18:31 marka Exp $ */ #ifndef DNS_TYPES_H #define DNS_TYPES_H 1 @@ -57,6 +57,7 @@ typedef struct dns_dispatchevent dns_dispatchevent_t; typedef struct dns_dispatchlist dns_dispatchlist_t; typedef struct dns_dispatchmgr dns_dispatchmgr_t; typedef struct dns_dispentry dns_dispentry_t; +typedef struct dns_dumpctx dns_dumpctx_t; typedef struct dns_fetch dns_fetch_t; typedef struct dns_fixedname dns_fixedname_t; typedef struct dns_forwarders dns_forwarders_t; @@ -280,6 +281,9 @@ typedef enum { /* * Functions. */ +typedef void +(*dns_dumpdonefunc_t)(void *, isc_result_t); + typedef void (*dns_loaddonefunc_t)(void *, isc_result_t); diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c index d4091004df..c322f02a75 100644 --- a/lib/dns/masterdump.c +++ b/lib/dns/masterdump.c @@ -15,20 +15,24 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: masterdump.c,v 1.56 2001/08/29 05:52:49 marka Exp $ */ +/* $Id: masterdump.c,v 1.57 2001/09/04 14:18:27 marka Exp $ */ #include #include +#include #include +#include #include #include #include +#include #include #include #include +#include #include #include #include @@ -41,6 +45,9 @@ #include #include +#define DNS_DCTX_MAGIC ISC_MAGIC('D', 'c', 't', 'x') +#define DNS_DCTX_VALID(d) ISC_MAGIC_VALID(d, DNS_DCTX_MAGIC) + #define RETERR(x) do { \ isc_result_t _r = (x); \ if (_r != ISC_R_SUCCESS) \ @@ -186,7 +193,28 @@ static char spaces[N_SPACES+1] = " "; #define N_TABS 10 static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t"; - +struct dns_dumpctx { + unsigned int magic; + isc_mem_t *mctx; + isc_mutex_t lock; + unsigned int references; + isc_boolean_t canceled; + isc_boolean_t first; + isc_boolean_t do_date; + isc_stdtime_t now; + FILE *f; + dns_db_t *db; + dns_dbversion_t *version; + dns_dbiterator_t *dbiter; + dns_totext_ctx_t tctx; + isc_task_t *task; + dns_dumpdonefunc_t done; + void *done_arg; + unsigned int nodes; + /* dns_master_dumpinc() */ + char *file; + char *tmpfile; +}; /* * Output tabs and spaces to go from column '*current' to @@ -857,6 +885,339 @@ dump_rdatasets(isc_mem_t *mctx, dns_name_t *name, dns_rdatasetiter_t *rdsiter, */ static const int initial_buffer_length = 1200; +static isc_result_t +dumptostreaminc(dns_dumpctx_t *dctx); + +static void +dumpctx_destroy(dns_dumpctx_t *dctx) { + + dctx->magic = 0; + DESTROYLOCK(&dctx->lock); + if (dctx->version != NULL) + dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); + dns_dbiterator_destroy(&dctx->dbiter); + dns_db_detach(&dctx->db); + if (dctx->task != NULL) + isc_task_detach(&dctx->task); + if (dctx->file != NULL) + isc_mem_free(dctx->mctx, dctx->file); + if (dctx->tmpfile != NULL) + isc_mem_free(dctx->mctx, dctx->tmpfile); + isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx)); +} + +void +dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) { + + REQUIRE(DNS_DCTX_VALID(source)); + REQUIRE(target != NULL && *target == NULL); + + LOCK(&source->lock); + INSIST(source->references > 0); + source->references++; + INSIST(source->references != 0); /* Overflow? */ + UNLOCK(&source->lock); + + *target = source; +} + +void +dns_dumpctx_detach(dns_dumpctx_t **dctxp) { + dns_dumpctx_t *dctx; + isc_boolean_t need_destroy = ISC_FALSE; + + REQUIRE(dctxp != NULL); + dctx = *dctxp; + REQUIRE(DNS_DCTX_VALID(dctx)); + + *dctxp = NULL; + + LOCK(&dctx->lock); + INSIST(dctx->references != 0); + dctx->references--; + if (dctx->references == 0) + need_destroy = ISC_TRUE; + UNLOCK(&dctx->lock); + if (need_destroy) + dumpctx_destroy(dctx); +} + +void +dns_dumpctx_cancel(dns_dumpctx_t *dctx) { + REQUIRE(DNS_DCTX_VALID(dctx)); + + LOCK(&dctx->lock); + dctx->canceled = ISC_TRUE; + UNLOCK(&dctx->lock); +} + +static isc_result_t +closeandrename(FILE *f, isc_result_t result, const char *temp, const char *file) +{ + isc_result_t tresult; + isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS); + + if (result == ISC_R_SUCCESS) + result = isc_stdio_sync(f); + if (result != ISC_R_SUCCESS && logit) { + isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, + "dumping master file: %s: fsync: %s", + temp, isc_result_totext(result)); + logit = ISC_FALSE; + } + tresult = isc_stdio_close(f); + if (result == ISC_R_SUCCESS) + result = tresult; + if (result != ISC_R_SUCCESS && logit) { + isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, + "dumping master file: %s: fclose: %s", + temp, isc_result_totext(result)); + logit = ISC_FALSE; + } + if (result == ISC_R_SUCCESS) + result = isc_file_rename(temp, file); + else + (void)isc_file_remove(temp); + if (result != ISC_R_SUCCESS && logit) { + isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, + "dumping master file: rename: %s: %s", + file, isc_result_totext(result)); + } + return (result); +} + +static void +dump_quantum(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + dns_dumpctx_t *dctx; + + REQUIRE(event != NULL); + dctx = event->ev_arg; + REQUIRE(DNS_DCTX_VALID(dctx)); + if (dctx->canceled) + result = ISC_R_CANCELED; + else + result = dumptostreaminc(dctx); + if (result == DNS_R_CONTINUE) { + event->ev_arg = dctx; + isc_task_send(task, &event); + return; + } + + if (dctx->file != NULL) + result = closeandrename(dctx->f, result, + dctx->tmpfile, dctx->file); + if (dctx->version != NULL) + dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); + (dctx->done)(dctx->done_arg, result); + isc_event_free(&event); + dns_dumpctx_detach(&dctx); +} + +static isc_result_t +task_send(dns_dumpctx_t *dctx) { + isc_event_t *event; + + event = isc_event_allocate(dctx->mctx, NULL, DNS_EVENT_DUMPQUANTUM, + dump_quantum, dctx, sizeof(*event)); + if (event == NULL) + return (ISC_R_NOMEMORY); + isc_task_send(dctx->task, &event); + return (ISC_R_SUCCESS); +} + +static isc_result_t +dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, + const dns_master_style_t *style, FILE *f, dns_dumpctx_t **dctxp) +{ + dns_dumpctx_t *dctx; + isc_result_t result; + isc_boolean_t relative; + + dctx = isc_mem_get(mctx, sizeof(*dctx)); + if (dctx == NULL) + return (ISC_R_NOMEMORY); + + dctx->mctx = NULL; + dctx->f = f; + dctx->dbiter = NULL; + dctx->db = NULL; + dctx->version = NULL; + dctx->done = NULL; + dctx->done_arg = NULL; + dctx->task = NULL; + dctx->nodes = 0; + dctx->first = ISC_TRUE; + dctx->canceled = ISC_FALSE; + dctx->file = NULL; + dctx->tmpfile = NULL; + + result = totext_ctx_init(style, &dctx->tctx); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "could not set master file style"); + goto cleanup; + } + + isc_stdtime_get(&dctx->now); + dns_db_attach(db, &dctx->db); + + dctx->do_date = dns_db_iscache(dctx->db); + + relative = ((dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) ? + ISC_TRUE : ISC_FALSE, + result = dns_db_createiterator(dctx->db, relative, &dctx->dbiter); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = isc_mutex_init(&dctx->lock); + if (result != ISC_R_SUCCESS) + goto cleanup; + if (version != NULL) + dns_db_attachversion(dctx->db, version, &dctx->version); + else if (!dns_db_iscache(db)) + dns_db_currentversion(dctx->db, &dctx->version); + isc_mem_attach(mctx, &dctx->mctx); + dctx->references = 1; + dctx->magic = DNS_DCTX_MAGIC; + *dctxp = dctx; + return (ISC_R_SUCCESS); + +cleanup: + if (dctx->dbiter != NULL) + dns_dbiterator_destroy(&dctx->dbiter); + if (dctx->db != NULL) + dns_db_detach(&dctx->db); + if (dctx != NULL) + isc_mem_put(mctx, dctx, sizeof(*dctx)); + return (result); +} + +static isc_result_t +dumptostreaminc(dns_dumpctx_t *dctx) { + isc_result_t result; + isc_buffer_t buffer; + char *bufmem; + isc_region_t r; + dns_name_t *name; + dns_fixedname_t fixname; + unsigned int nodes; + + bufmem = isc_mem_get(dctx->mctx, initial_buffer_length); + if (bufmem == NULL) + return (ISC_R_NOMEMORY); + + isc_buffer_init(&buffer, bufmem, initial_buffer_length); + + dns_fixedname_init(&fixname); + name = dns_fixedname_name(&fixname); + + if (dctx->first) { + /* + * If the database has cache semantics, output an RFC2540 + * $DATE directive so that the TTLs can be adjusted when + * it is reloaded. For zones it is not really needed, and + * it would make the file incompatible with pre-RFC2540 + * software, so we omit it in the zone case. + */ + if (dctx->do_date) { + result = dns_time32_totext(dctx->now, &buffer); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + isc_buffer_usedregion(&buffer, &r); + fprintf(dctx->f, "$DATE %.*s\n", + (int) r.length, (char *) r.base); + } + result = dns_dbiterator_first(dctx->dbiter); + dctx->first = ISC_FALSE; + } else + result = ISC_R_SUCCESS; + + nodes = dctx->nodes; + while (result == ISC_R_SUCCESS && (dctx->nodes == 0 || nodes--)) { + dns_rdatasetiter_t *rdsiter = NULL; + dns_dbnode_t *node = NULL; + + result = dns_dbiterator_current(dctx->dbiter, &node, name); + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) + break; + if (result == DNS_R_NEWORIGIN) { + dns_name_t *origin = + dns_fixedname_name(&dctx->tctx.origin_fixname); + result = dns_dbiterator_origin(dctx->dbiter, origin); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + isc_buffer_clear(&buffer); + result = dns_name_totext(origin, ISC_FALSE, &buffer); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + isc_buffer_usedregion(&buffer, &r); + fprintf(dctx->f, "$ORIGIN %.*s\n", (int) r.length, + (char *) r.base); + if ((dctx->tctx.style.flags & DNS_STYLEFLAG_REL_DATA) != 0) + dctx->tctx.origin = origin; + } + result = dns_db_allrdatasets(dctx->db, node, dctx->version, + dctx->now, &rdsiter); + if (result != ISC_R_SUCCESS) { + dns_db_detachnode(dctx->db, &node); + goto fail; + } + result = dump_rdatasets(dctx->mctx, name, rdsiter, &dctx->tctx, + &buffer, dctx->f); + dns_rdatasetiter_destroy(&rdsiter); + if (result != ISC_R_SUCCESS) { + dns_db_detachnode(dctx->db, &node); + goto fail; + } + dns_db_detachnode(dctx->db, &node); + result = dns_dbiterator_next(dctx->dbiter); + } + + if (dctx->nodes != 0 && result == ISC_R_SUCCESS) { + dns_dbiterator_pause(dctx->dbiter); + result = DNS_R_CONTINUE; + } else if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + fail: + isc_mem_put(dctx->mctx, buffer.base, buffer.length); + return (result); +} + +isc_result_t +dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db, + dns_dbversion_t *version, + const dns_master_style_t *style, + FILE *f, isc_task_t *task, + dns_dumpdonefunc_t done, void *done_arg, + dns_dumpctx_t **dctxp) +{ + dns_dumpctx_t *dctx = NULL; + isc_result_t result; + + REQUIRE(task != NULL); + REQUIRE(f != NULL); + REQUIRE(done != NULL); + + result = dumpctx_create(mctx, db, version, style, f, &dctx); + if (result != ISC_R_SUCCESS) + return (result); + isc_task_attach(task, &dctx->task); + dctx->done = done; + dctx->done_arg = done_arg; + dctx->nodes = 100; + + result = task_send(dctx); + if (result == ISC_R_SUCCESS) { + dns_dumpctx_attach(dctx, dctxp); + return (DNS_R_CONTINUE); + } + if (dctx != NULL) + dns_dumpctx_detach(&dctx); + + return (result); +} + /* * Dump an entire database into a master file. */ @@ -866,121 +1227,32 @@ dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, const dns_master_style_t *style, FILE *f) { - dns_fixedname_t fixname; - dns_name_t *name; - dns_dbiterator_t *dbiter = NULL; + dns_dumpctx_t *dctx = NULL; isc_result_t result; - isc_buffer_t buffer; - char *bufmem; - isc_stdtime_t now; - isc_region_t r; - dns_totext_ctx_t ctx; - result = totext_ctx_init(style, &ctx); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "could not set master file style"); - return (ISC_R_UNEXPECTED); - } - - dns_fixedname_init(&fixname); - name = dns_fixedname_name(&fixname); - - isc_stdtime_get(&now); - - bufmem = isc_mem_get(mctx, initial_buffer_length); - if (bufmem == NULL) - return (ISC_R_NOMEMORY); - - isc_buffer_init(&buffer, bufmem, initial_buffer_length); - - /* - * If the database has cache semantics, output an RFC2540 - * $DATE directive so that the TTLs can be adjusted when - * it is reloaded. For zones it is not really needed, and - * it would make the file incompatible with pre-RFC2540 - * software, so we omit it in the zone case. - */ - if (dns_db_iscache(db)) { - result = dns_time32_totext(now, &buffer); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc_buffer_usedregion(&buffer, &r); - fprintf(f, "$DATE %.*s\n", (int) r.length, (char *) r.base); - } - - result = dns_db_createiterator(db, - ((ctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) ? - ISC_TRUE : ISC_FALSE, - &dbiter); + result = dumpctx_create(mctx, db, version, style, f, &dctx); if (result != ISC_R_SUCCESS) - goto create_iter_failure; + return (result); - result = dns_dbiterator_first(dbiter); - - while (result == ISC_R_SUCCESS) { - dns_rdatasetiter_t *rdsiter = NULL; - dns_dbnode_t *node = NULL; - result = dns_dbiterator_current(dbiter, &node, name); - if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) - break; - if (result == DNS_R_NEWORIGIN) { - dns_name_t *origin = - dns_fixedname_name(&ctx.origin_fixname); - result = dns_dbiterator_origin(dbiter, origin); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc_buffer_clear(&buffer); - result = dns_name_totext(origin, ISC_FALSE, &buffer); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc_buffer_usedregion(&buffer, &r); - fprintf(f, "$ORIGIN %.*s\n", (int) r.length, - (char *) r.base); - if ((ctx.style.flags & DNS_STYLEFLAG_REL_DATA) != 0) - ctx.origin = origin; - } - result = dns_db_allrdatasets(db, node, version, now, &rdsiter); - if (result != ISC_R_SUCCESS) { - dns_db_detachnode(db, &node); - goto iter_failure; - } - result = dump_rdatasets(mctx, name, rdsiter, &ctx, - &buffer, f); - if (result != ISC_R_SUCCESS) { - dns_db_detachnode(db, &node); - goto iter_failure; - } - dns_rdatasetiter_destroy(&rdsiter); - dns_db_detachnode(db, &node); - result = dns_dbiterator_next(dbiter); - } - if (result != ISC_R_NOMORE) - goto iter_failure; - - result = ISC_R_SUCCESS; - - iter_failure: - dns_dbiterator_destroy(&dbiter); - - create_iter_failure: - isc_mem_put(mctx, buffer.base, buffer.length); + result = dumptostreaminc(dctx); + INSIST(result != DNS_R_CONTINUE); + dns_dumpctx_detach(&dctx); return (result); } - -isc_result_t -dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, - const dns_master_style_t *style, const char *filename) -{ +static isc_result_t +opentmp(isc_mem_t *mctx, const char *file, char **tempp, FILE **fp) { FILE *f = NULL; isc_result_t result; - char *tempname; + char *tempname = NULL; int tempnamelen; - tempnamelen = strlen(filename) + 20; - tempname = isc_mem_get(mctx, tempnamelen); + tempnamelen = strlen(file) + 20; + tempname = isc_mem_allocate(mctx, tempnamelen); if (tempname == NULL) return (ISC_R_NOMEMORY); - result = isc_file_mktemplate(filename, tempname, tempnamelen); + result = isc_file_mktemplate(file, tempname, tempnamelen); if (result != ISC_R_SUCCESS) goto cleanup; @@ -992,50 +1264,92 @@ dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, tempname, isc_result_totext(result)); goto cleanup; } + *tempp = tempname; + *fp = f; + return (ISC_R_SUCCESS); - result = dns_master_dumptostream(mctx, db, version, style, f); +cleanup: + isc_mem_free(mctx, tempname); + return (result); +} + +isc_result_t +dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, + const dns_master_style_t *style, const char *filename, + isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, + dns_dumpctx_t **dctxp) +{ + FILE *f = NULL; + isc_result_t result; + char *tempname = NULL; + char *file = NULL; + dns_dumpctx_t *dctx = NULL; + + file = isc_mem_strdup(mctx, filename); + if (tempname == NULL) + return (ISC_R_NOMEMORY); + + result = opentmp(mctx, filename, &tempname, &f); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dumpctx_create(mctx, db, version, style, f, &dctx); if (result != ISC_R_SUCCESS) { - isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, - "dumping master file: %s: %s", - tempname, isc_result_totext(result)); (void)isc_stdio_close(f); (void)isc_file_remove(tempname); goto cleanup; } - result = isc_stdio_sync(f); - if (result != ISC_R_SUCCESS) { - isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, - "dumping master file: %s: fsync: %s", - tempname, isc_result_totext(result)); - (void)isc_stdio_close(f); - (void)isc_file_remove(tempname); - goto cleanup; - } + isc_task_attach(task, &dctx->task); + dctx->done = done; + dctx->done_arg = done_arg; + dctx->nodes = 100; + dctx->file = file; + file = NULL; + dctx->tmpfile = tempname; + tempname = NULL; - result = isc_stdio_close(f); - if (result != ISC_R_SUCCESS) { - isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, - "dumping master file: %s: close: %s", - tempname, isc_result_totext(result)); - (void)isc_file_remove(tempname); - goto cleanup; - } - - result = isc_file_rename(tempname, filename); - if (result != ISC_R_SUCCESS) { - isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, - "dumping master file: rename: %s: %s", - filename, isc_result_totext(result)); - goto cleanup; + result = task_send(dctx); + if (result == ISC_R_SUCCESS) { + dns_dumpctx_attach(dctx, dctxp); + return (DNS_R_CONTINUE); } cleanup: - isc_mem_put(mctx, tempname, tempnamelen); + if (dctx != NULL) + dns_dumpctx_detach(&dctx); + if (file != NULL) + isc_mem_free(mctx, file); + if (tempname != NULL) + isc_mem_free(mctx, tempname); + return (result); +} + +isc_result_t +dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, + const dns_master_style_t *style, const char *filename) +{ + FILE *f = NULL; + isc_result_t result; + char *tempname; + dns_dumpctx_t *dctx = NULL; + + result = opentmp(mctx, filename, &tempname, &f); + if (result != ISC_R_SUCCESS) + return (result); + + result = dumpctx_create(mctx, db, version, style, f, &dctx); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dumptostreaminc(dctx); + INSIST(result != DNS_R_CONTINUE); + dns_dumpctx_detach(&dctx); + + result = closeandrename(f, result, tempname, filename); + + cleanup: + isc_mem_free(mctx, tempname); return (result); }