mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-09 03:42:06 -04:00
dns_journal_compact()
This commit is contained in:
parent
0914e94965
commit
53e3724e23
2 changed files with 246 additions and 7 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <config.h>
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue