summaryrefslogtreecommitdiff
path: root/usr.sbin/bind/lib/dns/journal.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bind/lib/dns/journal.c')
-rw-r--r--usr.sbin/bind/lib/dns/journal.c315
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, &current_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, &current_pos);
+ CHECK(journal_next(j, &current_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);
+}