From: Mark Andrews Date: Thu, 30 Aug 2001 05:04:18 +0000 (+0000) Subject: dns_journal_compact() X-Git-Tag: v9.2.2rc1^3~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=53e3724e23307c983eb478f06388339519d38921;p=thirdparty%2Fbind9.git dns_journal_compact() --- diff --git a/lib/dns/include/dns/journal.h b/lib/dns/include/dns/journal.h index e28dc83ef48..7d53ad40db9 100644 --- a/lib/dns/include/dns/journal.h +++ b/lib/dns/include/dns/journal.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: journal.h,v 1.23 2001/05/21 23:56:33 gson Exp $ */ +/* $Id: journal.h,v 1.24 2001/08/30 05:04:18 marka Exp $ */ #ifndef DNS_JOURNAL_H #define DNS_JOURNAL_H 1 @@ -257,6 +257,14 @@ dns_db_diff(isc_mem_t *mctx, * entry to the journal file specified by 'journal_filename'. */ +isc_result_t +dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial, + isc_uint32_t target_size); +/* + * Attempt to compact the journal if it is greater that 'target_size'. + * Changes from 'serial' onwards will be preserved. If the journal + * exists and is non-empty 'serial' must exist in the journal. + */ ISC_LANG_ENDDECLS diff --git a/lib/dns/journal.c b/lib/dns/journal.c index 54c4c4480cb..fb1af8b1ec9 100644 --- a/lib/dns/journal.c +++ b/lib/dns/journal.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: journal.c,v 1.77 2001/08/06 02:10:59 marka Exp $ */ +/* $Id: journal.c,v 1.78 2001/08/30 05:04:17 marka Exp $ */ #include @@ -538,10 +538,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 +561,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 +668,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 +733,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. @@ -1906,3 +1913,227 @@ dns_db_diff(isc_mem_t *mctx, dns_journal_destroy(&journal); return (result); } + +static isc_result_t index_to_disk(dns_journal_t *) ; + +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 (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) && + (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) && + ((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 (j->header.end.offset - best_guess.offset > + 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 to 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)); + } + + /* + * Convert the index into on-disk format and write + * it to disk. + */ + CHECK(index_to_disk(j)); + 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_write(j, j->rawindex, rawbytes)); + } +failure: + return (result); +}