diff options
Diffstat (limited to 'usr.sbin/bind/lib/dns/journal.c')
-rw-r--r-- | usr.sbin/bind/lib/dns/journal.c | 315 |
1 files changed, 269 insertions, 46 deletions
diff --git a/usr.sbin/bind/lib/dns/journal.c b/usr.sbin/bind/lib/dns/journal.c index 688c2d774d2..0ad9a8c8d33 100644 --- a/usr.sbin/bind/lib/dns/journal.c +++ b/usr.sbin/bind/lib/dns/journal.c @@ -1,21 +1,21 @@ /* - * Copyright (C) 1999-2001 Internet Software Consortium. + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM - * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING - * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ -/* $ISC: journal.c,v 1.77.2.1 2001/10/15 04:57:51 marka Exp $ */ +/* $ISC: journal.c,v 1.77.2.1.10.8 2004/05/14 05:27:47 marka Exp $ */ #include <config.h> @@ -72,6 +72,8 @@ static isc_boolean_t bind8_compat = ISC_TRUE; /* XXX config */ if (result != ISC_R_SUCCESS) goto failure; \ } while (0) +static isc_result_t index_to_disk(dns_journal_t *); + static inline isc_uint32_t decode_uint32(unsigned char *p) { return ((p[0] << 24) + @@ -538,10 +540,9 @@ journal_file_create(isc_mem_t *mctx, const char *filename) { return (ISC_R_SUCCESS); } - -isc_result_t -dns_journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, - dns_journal_t **journalp) { +static isc_result_t +journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, + isc_boolean_t create, dns_journal_t **journalp) { FILE *fp = NULL; isc_result_t result; journal_rawheader_t rawheader; @@ -562,7 +563,7 @@ dns_journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, result = isc_stdio_open(j->filename, write ? "rb+" : "rb", &fp); if (result == ISC_R_FILENOTFOUND) { - if (write) { + if (create) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_INFO, "journal file %s does not exist, " @@ -669,6 +670,12 @@ dns_journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, return (result); } +isc_result_t +dns_journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, + dns_journal_t **journalp) { + return (journal_open(mctx, filename, write, write, journalp)); +} + /* * A comparison function defining the sorting order for * entries in the IXFR-style journal file. @@ -728,6 +735,8 @@ journal_next(dns_journal_t *j, journal_pos_t *pos) { if (result != ISC_R_SUCCESS) return (result); + if (pos->serial == j->header.end.serial) + return (ISC_R_NOMORE); /* * Read the header of the current transaction. * This will return ISC_R_NOMORE if we are at EOF. @@ -942,7 +951,7 @@ dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff) { REQUIRE(j->state == JOURNAL_STATE_TRANSACTION); isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "writing to journal"); - dns_diff_print(diff, NULL); + (void)dns_diff_print(diff, NULL); /* * Pass 1: determine the buffer size needed, and @@ -1104,24 +1113,7 @@ dns_journal_commit(dns_journal_t *j) { * Convert the index into on-disk format and write * it to disk. */ - if (j->header.index_size != 0) { - unsigned int i; - unsigned char *p; - unsigned int rawbytes; - - rawbytes = j->header.index_size * sizeof(journal_rawpos_t); - - p = j->rawindex; - for (i = 0; i < j->header.index_size; i++) { - encode_uint32(j->index[i].serial, p); - p += 4; - encode_uint32(j->index[i].offset, p); - p += 4; - } - INSIST(p == j->rawindex + rawbytes); - - CHECK(journal_write(j, j->rawindex, rawbytes)); - } + CHECK(index_to_disk(j)); /* * Commit the header to stable storage. @@ -1253,8 +1245,11 @@ roll_forward(dns_journal_t *j, dns_db_t *db) { rdata = NULL; dns_journal_current_rr(j, &name, &ttl, &rdata); - if (rdata->type == dns_rdatatype_soa) + if (rdata->type == dns_rdatatype_soa) { n_soa++; + if (n_soa == 2) + db_serial = j->it.current_serial; + } if (n_soa == 3) n_soa = 1; @@ -1271,8 +1266,9 @@ roll_forward(dns_journal_t *j, dns_db_t *db) { if (++n_put > 100) { isc_log_write(JOURNAL_DEBUG_LOGARGS(3), - "applying diff to database"); - dns_diff_print(&diff, NULL); + "applying diff to database (%u)", + db_serial); + (void)dns_diff_print(&diff, NULL); CHECK(dns_diff_apply(&diff, db, ver)); dns_diff_clear(&diff); n_put = 0; @@ -1284,8 +1280,9 @@ roll_forward(dns_journal_t *j, dns_db_t *db) { if (n_put != 0) { isc_log_write(JOURNAL_DEBUG_LOGARGS(3), - "applying final diff to database"); - dns_diff_print(&diff, NULL); + "applying final diff to database (%u)", + db_serial); + (void)dns_diff_print(&diff, NULL); CHECK(dns_diff_apply(&diff, db, ver)); dns_diff_clear(&diff); } @@ -1600,7 +1597,7 @@ read_one_rr(dns_journal_t *j) { isc_buffer_setactive(&j->it.source, j->it.source.used - j->it.source.current); CHECK(dns_name_fromwire(&j->it.name, &j->it.source, - &j->it.dctx, ISC_FALSE, &j->it.target)); + &j->it.dctx, 0, &j->it.target)); /* * Check that the RR header is there, and parse it. @@ -1620,7 +1617,7 @@ read_one_rr(dns_journal_t *j) { dns_rdata_reset(&j->it.rdata); CHECK(dns_rdata_fromwire(&j->it.rdata, rdclass, rdtype, &j->it.source, &j->it.dctx, - ISC_FALSE, &j->it.target)); + 0, &j->it.target)); j->it.ttl = ttl; j->it.xpos += sizeof(journal_rawrrhdr_t) + rrhdr.size; @@ -1825,10 +1822,16 @@ dns_db_diff(isc_mem_t *mctx, dns_fixedname_init(&fixname[0]); dns_fixedname_init(&fixname[1]); - CHECK(dns_journal_open(mctx, journal_filename, ISC_TRUE, &journal)); + result = dns_journal_open(mctx, journal_filename, ISC_TRUE, &journal); + if (result != ISC_R_SUCCESS) + return (result); - CHECK(dns_db_createiterator(db[0], ISC_FALSE, &dbit[0])); - CHECK(dns_db_createiterator(db[1], ISC_FALSE, &dbit[1])); + result = dns_db_createiterator(db[0], ISC_FALSE, &dbit[0]); + if (result != ISC_R_SUCCESS) + goto cleanup_journal; + result = dns_db_createiterator(db[1], ISC_FALSE, &dbit[1]); + if (result != ISC_R_SUCCESS) + goto cleanup_interator0; itresult[0] = dns_dbiterator_first(dbit[0]); itresult[1] = dns_dbiterator_first(dbit[1]); @@ -1898,11 +1901,231 @@ dns_db_diff(isc_mem_t *mctx, } INSIST(ISC_LIST_EMPTY(diff[0].tuples)); INSIST(ISC_LIST_EMPTY(diff[1].tuples)); - dns_diff_clear(&resultdiff); failure: - dns_dbiterator_destroy(&dbit[0]); + dns_diff_clear(&resultdiff); dns_dbiterator_destroy(&dbit[1]); + cleanup_interator0: + dns_dbiterator_destroy(&dbit[0]); + cleanup_journal: dns_journal_destroy(&journal); return (result); } + +isc_result_t +dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial, + isc_uint32_t target_size) +{ + unsigned int i; + journal_pos_t best_guess; + journal_pos_t current_pos; + dns_journal_t *j = NULL; + journal_rawheader_t rawheader; + unsigned int copy_length; + unsigned int len; + char *buf = NULL; + unsigned int size = 0; + isc_result_t result; + unsigned int indexend; + + CHECK(journal_open(mctx, filename, ISC_TRUE, ISC_FALSE, &j)); + + if (JOURNAL_EMPTY(&j->header)) { + dns_journal_destroy(&j); + return (ISC_R_SUCCESS); + } + + if (DNS_SERIAL_GT(j->header.begin.serial, serial) || + DNS_SERIAL_GT(serial, j->header.end.serial)) { + dns_journal_destroy(&j); + return (ISC_R_RANGE); + } + + /* + * Cope with very small target sizes. + */ + indexend = sizeof(journal_rawheader_t) + + j->header.index_size * sizeof(journal_rawpos_t); + if (target_size < indexend * 2) + target_size = target_size/2 + indexend; + + /* + * See if there is any work to do. + */ + if ((isc_uint32_t) j->header.end.offset < target_size) { + dns_journal_destroy(&j); + return (ISC_R_SUCCESS); + } + + /* + * Remove overhead so space test below can succeed. + */ + if (target_size >= indexend) + target_size -= indexend; + + /* + * Find if we can create enough free space. + */ + best_guess = j->header.begin; + for (i = 0; i < j->header.index_size; i++) { + if (POS_VALID(j->index[i]) && + DNS_SERIAL_GE(serial, j->index[i].serial) && + ((isc_uint32_t)(j->header.end.offset - j->index[i].offset) + >= target_size / 2) && + j->index[i].offset > best_guess.offset) + best_guess = j->index[i]; + } + + current_pos = best_guess; + while (current_pos.serial != serial) { + CHECK(journal_next(j, ¤t_pos)); + if (current_pos.serial == j->header.end.serial) + break; + + if (DNS_SERIAL_GE(serial, current_pos.serial) && + ((isc_uint32_t)(j->header.end.offset - current_pos.offset) + >= (target_size / 2)) && + current_pos.offset > best_guess.offset) + best_guess = current_pos; + else + break; + } + + INSIST(best_guess.serial != j->header.end.serial); + if (best_guess.serial != serial) + CHECK(journal_next(j, &best_guess)); + + /* + * Enough space to proceed? + */ + if ((isc_uint32_t) (j->header.end.offset - best_guess.offset) > + (isc_uint32_t) (best_guess.offset - indexend)) { + dns_journal_destroy(&j); + return (ISC_R_NOSPACE); + } + + copy_length = j->header.end.offset - best_guess.offset; + + /* + * Invalidate entire index, will be rebuilt at end. + */ + for (i = 0; i < j->header.index_size; i++) { + if (POS_VALID(j->index[i])) + POS_INVALIDATE(j->index[i]); + } + + /* + * Convert the index into on-disk format and write + * it to disk. + */ + CHECK(index_to_disk(j)); + CHECK(journal_fsync(j)); + + /* + * Update the journal header. + */ + if (copy_length == 0) { + j->header.begin.serial = 0; + j->header.end.serial = 0; + j->header.begin.offset = 0; + j->header.end.offset = 0; + } else { + j->header.begin = best_guess; + } + journal_header_encode(&j->header, &rawheader); + CHECK(journal_seek(j, 0)); + CHECK(journal_write(j, &rawheader, sizeof(rawheader))); + CHECK(journal_fsync(j)); + + if (copy_length != 0) { + /* + * Copy best_guess to end into space just freed. + */ + size = 64*1024; + if (copy_length < size) + size = copy_length; + buf = isc_mem_get(mctx, size); + if (buf == NULL) { + result = ISC_R_NOMEMORY; + goto failure; + } + + for (i = 0; i < copy_length; i += size) { + len = (copy_length - i) > size ? size : + (copy_length - i); + CHECK(journal_seek(j, best_guess.offset + i)); + CHECK(journal_read(j, buf, len)); + CHECK(journal_seek(j, indexend + i)); + CHECK(journal_write(j, buf, len)); + } + + CHECK(journal_fsync(j)); + + /* + * Compute new header. + */ + j->header.begin.offset = indexend; + j->header.end.offset = indexend + copy_length; + /* + * Update the journal header. + */ + journal_header_encode(&j->header, &rawheader); + CHECK(journal_seek(j, 0)); + CHECK(journal_write(j, &rawheader, sizeof(rawheader))); + CHECK(journal_fsync(j)); + + /* + * Build new index. + */ + current_pos = j->header.begin; + while (current_pos.serial != j->header.end.serial) { + index_add(j, ¤t_pos); + CHECK(journal_next(j, ¤t_pos)); + } + + /* + * Write index. + */ + CHECK(index_to_disk(j)); + CHECK(journal_fsync(j)); + + indexend = j->header.end.offset; + } + dns_journal_destroy(&j); + (void)isc_file_truncate(filename, (isc_offset_t)indexend); + result = ISC_R_SUCCESS; + + failure: + if (buf != NULL) + isc_mem_put(mctx, buf, size); + if (j != NULL) + dns_journal_destroy(&j); + return (result); +} + +static isc_result_t +index_to_disk(dns_journal_t *j) { + isc_result_t result = ISC_R_SUCCESS; + + if (j->header.index_size != 0) { + unsigned int i; + unsigned char *p; + unsigned int rawbytes; + + rawbytes = j->header.index_size * sizeof(journal_rawpos_t); + + p = j->rawindex; + for (i = 0; i < j->header.index_size; i++) { + encode_uint32(j->index[i].serial, p); + p += 4; + encode_uint32(j->index[i].offset, p); + p += 4; + } + INSIST(p == j->rawindex + rawbytes); + + CHECK(journal_seek(j, sizeof(journal_rawheader_t))); + CHECK(journal_write(j, j->rawindex, rawbytes)); + } +failure: + return (result); +} |