|
|
|
@@ -18,6 +18,7 @@
|
|
|
|
|
#include <isc/file.h>
|
|
|
|
|
#include <isc/mem.h>
|
|
|
|
|
#include <isc/print.h>
|
|
|
|
|
#include <isc/serial.h>
|
|
|
|
|
#include <isc/stdio.h>
|
|
|
|
|
#include <isc/string.h>
|
|
|
|
|
#include <isc/util.h>
|
|
|
|
@@ -193,6 +194,11 @@ typedef struct {
|
|
|
|
|
*/
|
|
|
|
|
#define JOURNAL_HEADER_SIZE 64 /* Bytes. */
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
|
XHDR_VERSION1 = 1,
|
|
|
|
|
XHDR_VERSION2 = 2,
|
|
|
|
|
} xhdr_version_t;
|
|
|
|
|
|
|
|
|
|
/*%
|
|
|
|
|
* The on-disk representation of the journal header.
|
|
|
|
|
* All numbers are stored in big-endian order.
|
|
|
|
@@ -216,7 +222,7 @@ typedef union {
|
|
|
|
|
} journal_rawheader_t;
|
|
|
|
|
|
|
|
|
|
/*%
|
|
|
|
|
* The on-disk representation of the transaction header.
|
|
|
|
|
* The on-disk representation of the transaction header, version 2.
|
|
|
|
|
* There is one of these at the beginning of each transaction.
|
|
|
|
|
*/
|
|
|
|
|
typedef struct {
|
|
|
|
@@ -226,6 +232,16 @@ typedef struct {
|
|
|
|
|
unsigned char serial1[4]; /*%< SOA serial after update. */
|
|
|
|
|
} journal_rawxhdr_t;
|
|
|
|
|
|
|
|
|
|
/*%
|
|
|
|
|
* Old-style raw transaction header, version 1, used for backward
|
|
|
|
|
* compatibility mode.
|
|
|
|
|
*/
|
|
|
|
|
typedef struct {
|
|
|
|
|
unsigned char size[4];
|
|
|
|
|
unsigned char serial0[4];
|
|
|
|
|
unsigned char serial1[4];
|
|
|
|
|
} journal_rawxhdr_ver1_t;
|
|
|
|
|
|
|
|
|
|
/*%
|
|
|
|
|
* The on-disk representation of the RR header.
|
|
|
|
|
* There is one of these at the beginning of each RR.
|
|
|
|
@@ -275,16 +291,19 @@ typedef struct {
|
|
|
|
|
* Initial contents to store in the header of a newly created
|
|
|
|
|
* journal file.
|
|
|
|
|
*
|
|
|
|
|
* The header starts with the magic string ";BIND LOG V9\n"
|
|
|
|
|
* The header starts with the magic string ";BIND LOG V9.2\n"
|
|
|
|
|
* to identify the file as a BIND 9 journal file. An ASCII
|
|
|
|
|
* identification string is used rather than a binary magic
|
|
|
|
|
* number to be consistent with BIND 8 (BIND 8 journal files
|
|
|
|
|
* are ASCII text files).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static journal_header_t initial_journal_header = {
|
|
|
|
|
static journal_header_t journal_header_ver1 = {
|
|
|
|
|
";BIND LOG V9\n", { 0, 0 }, { 0, 0 }, 0, 0, 0
|
|
|
|
|
};
|
|
|
|
|
static journal_header_t initial_journal_header = {
|
|
|
|
|
";BIND LOG V9.2\n", { 0, 0 }, { 0, 0 }, 0, 0, 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define JOURNAL_EMPTY(h) ((h)->begin.offset == (h)->end.offset)
|
|
|
|
|
|
|
|
|
@@ -300,9 +319,15 @@ struct dns_journal {
|
|
|
|
|
unsigned int magic; /*%< JOUR */
|
|
|
|
|
isc_mem_t *mctx; /*%< Memory context */
|
|
|
|
|
journal_state_t state;
|
|
|
|
|
xhdr_version_t xhdr_version; /*%< Expected transaction header version */
|
|
|
|
|
bool header_ver1; /*%< Transaction header compatibility
|
|
|
|
|
* mode is allowed */
|
|
|
|
|
bool recovered; /*%< A recoverable error was found
|
|
|
|
|
* while reading the journal */
|
|
|
|
|
char *filename; /*%< Journal file name */
|
|
|
|
|
FILE *fp; /*%< File handle */
|
|
|
|
|
isc_offset_t offset; /*%< Current file offset */
|
|
|
|
|
journal_xhdr_t curxhdr; /*%< Current transaction header */
|
|
|
|
|
journal_header_t header; /*%< In-core journal header */
|
|
|
|
|
unsigned char *rawindex; /*%< In-core buffer for journal index
|
|
|
|
|
* in on-disk format */
|
|
|
|
@@ -321,8 +346,7 @@ struct dns_journal {
|
|
|
|
|
journal_pos_t bpos; /*%< Position before first, */
|
|
|
|
|
journal_pos_t epos; /*%< and after last transaction */
|
|
|
|
|
/* The rest is iterator state. */
|
|
|
|
|
uint32_t current_serial; /*%< Current SOA serial
|
|
|
|
|
* */
|
|
|
|
|
uint32_t current_serial; /*%< Current SOA serial */
|
|
|
|
|
isc_buffer_t source; /*%< Data from disk */
|
|
|
|
|
isc_buffer_t target; /*%< Data from _fromwire check */
|
|
|
|
|
dns_decompress_t dctx; /*%< Dummy decompression ctx */
|
|
|
|
@@ -353,6 +377,7 @@ journal_pos_encode(journal_rawpos_t *raw, journal_pos_t *cooked) {
|
|
|
|
|
static void
|
|
|
|
|
journal_header_decode(journal_rawheader_t *raw, journal_header_t *cooked) {
|
|
|
|
|
INSIST(sizeof(cooked->format) == sizeof(raw->h.format));
|
|
|
|
|
|
|
|
|
|
memmove(cooked->format, raw->h.format, sizeof(cooked->format));
|
|
|
|
|
journal_pos_decode(&raw->h.begin, &cooked->begin);
|
|
|
|
|
journal_pos_decode(&raw->h.end, &cooked->end);
|
|
|
|
@@ -366,6 +391,7 @@ journal_header_encode(journal_header_t *cooked, journal_rawheader_t *raw) {
|
|
|
|
|
unsigned char flags = 0;
|
|
|
|
|
|
|
|
|
|
INSIST(sizeof(cooked->format) == sizeof(raw->h.format));
|
|
|
|
|
|
|
|
|
|
memset(raw->pad, 0, sizeof(raw->pad));
|
|
|
|
|
memmove(raw->h.format, cooked->format, sizeof(raw->h.format));
|
|
|
|
|
journal_pos_encode(&raw->h.begin, &cooked->begin);
|
|
|
|
@@ -432,6 +458,7 @@ journal_write(dns_journal_t *j, void *mem, size_t nbytes) {
|
|
|
|
|
static isc_result_t
|
|
|
|
|
journal_fsync(dns_journal_t *j) {
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
|
|
result = isc_stdio_flush(j->fp);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
|
|
|
|
@@ -452,11 +479,27 @@ journal_fsync(dns_journal_t *j) {
|
|
|
|
|
/*
|
|
|
|
|
* Read/write a transaction header at the current file position.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
|
journal_read_xhdr(dns_journal_t *j, journal_xhdr_t *xhdr) {
|
|
|
|
|
journal_rawxhdr_t raw;
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
|
|
switch (j->xhdr_version) {
|
|
|
|
|
case XHDR_VERSION1: {
|
|
|
|
|
journal_rawxhdr_ver1_t raw;
|
|
|
|
|
result = journal_read(j, &raw, sizeof(raw));
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
xhdr->size = decode_uint32(raw.size);
|
|
|
|
|
xhdr->count = 0;
|
|
|
|
|
xhdr->serial0 = decode_uint32(raw.serial0);
|
|
|
|
|
xhdr->serial1 = decode_uint32(raw.serial1);
|
|
|
|
|
j->curxhdr = *xhdr;
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case XHDR_VERSION2: {
|
|
|
|
|
journal_rawxhdr_t raw;
|
|
|
|
|
result = journal_read(j, &raw, sizeof(raw));
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
return (result);
|
|
|
|
@@ -465,13 +508,20 @@ journal_read_xhdr(dns_journal_t *j, journal_xhdr_t *xhdr) {
|
|
|
|
|
xhdr->count = decode_uint32(raw.count);
|
|
|
|
|
xhdr->serial0 = decode_uint32(raw.serial0);
|
|
|
|
|
xhdr->serial1 = decode_uint32(raw.serial1);
|
|
|
|
|
j->curxhdr = *xhdr;
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return (ISC_R_NOTIMPLEMENTED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
|
journal_write_xhdr(dns_journal_t *j, uint32_t size, uint32_t count,
|
|
|
|
|
uint32_t serial0, uint32_t serial1) {
|
|
|
|
|
journal_rawxhdr_t raw;
|
|
|
|
|
|
|
|
|
|
encode_uint32(size, raw.size);
|
|
|
|
|
encode_uint32(count, raw.count);
|
|
|
|
|
encode_uint32(serial0, raw.serial0);
|
|
|
|
@@ -487,6 +537,7 @@ static isc_result_t
|
|
|
|
|
journal_read_rrhdr(dns_journal_t *j, journal_rrhdr_t *rrhdr) {
|
|
|
|
|
journal_rawrrhdr_t raw;
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
|
|
result = journal_read(j, &raw, sizeof(raw));
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
return (result);
|
|
|
|
@@ -503,7 +554,7 @@ journal_file_create(isc_mem_t *mctx, const char *filename) {
|
|
|
|
|
journal_rawheader_t rawheader;
|
|
|
|
|
int index_size = 56; /* XXX configurable */
|
|
|
|
|
int size;
|
|
|
|
|
void *mem; /* Memory for temporary index image. */
|
|
|
|
|
void *mem = NULL; /* Memory for temporary index image. */
|
|
|
|
|
|
|
|
|
|
INSIST(sizeof(journal_rawheader_t) == JOURNAL_HEADER_SIZE);
|
|
|
|
|
|
|
|
|
@@ -558,23 +609,15 @@ journal_open(isc_mem_t *mctx, const char *filename, bool writable, bool create,
|
|
|
|
|
journal_rawheader_t rawheader;
|
|
|
|
|
dns_journal_t *j;
|
|
|
|
|
|
|
|
|
|
INSIST(journalp != NULL && *journalp == NULL);
|
|
|
|
|
REQUIRE(journalp != NULL && *journalp == NULL);
|
|
|
|
|
|
|
|
|
|
j = isc_mem_get(mctx, sizeof(*j));
|
|
|
|
|
|
|
|
|
|
j->mctx = NULL;
|
|
|
|
|
*j = (dns_journal_t){ .state = JOURNAL_STATE_INVALID,
|
|
|
|
|
.filename = isc_mem_strdup(mctx, filename),
|
|
|
|
|
.xhdr_version = XHDR_VERSION2 };
|
|
|
|
|
isc_mem_attach(mctx, &j->mctx);
|
|
|
|
|
j->state = JOURNAL_STATE_INVALID;
|
|
|
|
|
j->fp = NULL;
|
|
|
|
|
j->filename = isc_mem_strdup(mctx, filename);
|
|
|
|
|
j->index = NULL;
|
|
|
|
|
j->rawindex = NULL;
|
|
|
|
|
|
|
|
|
|
if (j->filename == NULL) {
|
|
|
|
|
FAIL(ISC_R_NOMEMORY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = isc_stdio_open(j->filename, writable ? "rb+" : "rb", &fp);
|
|
|
|
|
|
|
|
|
|
if (result == ISC_R_FILENOTFOUND) {
|
|
|
|
|
if (create) {
|
|
|
|
|
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_DEBUG(1),
|
|
|
|
@@ -607,9 +650,29 @@ journal_open(isc_mem_t *mctx, const char *filename, bool writable, bool create,
|
|
|
|
|
CHECK(journal_seek(j, 0));
|
|
|
|
|
CHECK(journal_read(j, &rawheader, sizeof(rawheader)));
|
|
|
|
|
|
|
|
|
|
if (memcmp(rawheader.h.format, initial_journal_header.format,
|
|
|
|
|
sizeof(initial_journal_header.format)) != 0)
|
|
|
|
|
if (memcmp(rawheader.h.format, journal_header_ver1.format,
|
|
|
|
|
sizeof(journal_header_ver1.format)) == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The file header says it's the old format, but it
|
|
|
|
|
* still might have the new xhdr format because we
|
|
|
|
|
* forgot to change the format string when we introduced
|
|
|
|
|
* the new xhdr. When we first try to read it, we assume
|
|
|
|
|
* it uses the new xhdr format. If that fails, we'll be
|
|
|
|
|
* called a second time with compat set to true, in which
|
|
|
|
|
* case we can lower xhdr_version to 1 if we find a
|
|
|
|
|
* corrupt transaction.
|
|
|
|
|
*/
|
|
|
|
|
j->header_ver1 = true;
|
|
|
|
|
} else if (memcmp(rawheader.h.format, initial_journal_header.format,
|
|
|
|
|
sizeof(initial_journal_header.format)) == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* File header says this is format version 2; all
|
|
|
|
|
* transactions have to match.
|
|
|
|
|
*/
|
|
|
|
|
j->header_ver1 = false;
|
|
|
|
|
} else {
|
|
|
|
|
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
|
|
|
|
|
"%s: journal format not recognized", j->filename);
|
|
|
|
|
FAIL(ISC_R_UNEXPECTED);
|
|
|
|
@@ -795,9 +858,11 @@ ixfr_order(const void *av, const void *bv) {
|
|
|
|
|
* Other results due to file errors are possible.
|
|
|
|
|
*/
|
|
|
|
|
static isc_result_t
|
|
|
|
|
journal_next(dns_journal_t *j, journal_pos_t *pos) {
|
|
|
|
|
journal_next(dns_journal_t *j, journal_pos_t *pos, bool retry) {
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
journal_xhdr_t xhdr;
|
|
|
|
|
size_t hdrsize;
|
|
|
|
|
|
|
|
|
|
REQUIRE(DNS_JOURNAL_VALID(j));
|
|
|
|
|
|
|
|
|
|
result = journal_seek(j, pos->offset);
|
|
|
|
@@ -808,6 +873,7 @@ journal_next(dns_journal_t *j, journal_pos_t *pos) {
|
|
|
|
|
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.
|
|
|
|
@@ -820,26 +886,59 @@ journal_next(dns_journal_t *j, journal_pos_t *pos) {
|
|
|
|
|
/*
|
|
|
|
|
* Check serial number consistency.
|
|
|
|
|
*/
|
|
|
|
|
if (xhdr.serial0 != pos->serial) {
|
|
|
|
|
if (xhdr.serial0 != pos->serial ||
|
|
|
|
|
isc_serial_le(xhdr.serial1, xhdr.serial0)) {
|
|
|
|
|
if (j->header_ver1 && j->xhdr_version == XHDR_VERSION1 &&
|
|
|
|
|
xhdr.serial1 == pos->serial && !retry)
|
|
|
|
|
{
|
|
|
|
|
/* XHDR_VERSION1 -> XHDR_VERSION2 */
|
|
|
|
|
isc_log_write(
|
|
|
|
|
JOURNAL_COMMON_LOGARGS, ISC_LOG_DEBUG(3),
|
|
|
|
|
"%s: XHDR_VERSION1 -> XHDR_VERSION2 at %u\n",
|
|
|
|
|
j->filename, pos->serial);
|
|
|
|
|
j->xhdr_version = XHDR_VERSION2;
|
|
|
|
|
result = journal_next(j, pos, true);
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
j->recovered = true;
|
|
|
|
|
}
|
|
|
|
|
return (result);
|
|
|
|
|
} else if (j->header_ver1 && j->xhdr_version == XHDR_VERSION2 &&
|
|
|
|
|
xhdr.count == pos->serial && !retry)
|
|
|
|
|
{
|
|
|
|
|
/* XHDR_VERSION2 -> XHDR_VERSION1 */
|
|
|
|
|
isc_log_write(
|
|
|
|
|
JOURNAL_COMMON_LOGARGS, ISC_LOG_DEBUG(3),
|
|
|
|
|
"%s: XHDR_VERSION2 -> XHDR_VERSION1 at %u\n",
|
|
|
|
|
j->filename, pos->serial);
|
|
|
|
|
j->xhdr_version = XHDR_VERSION1;
|
|
|
|
|
result = journal_next(j, pos, true);
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
j->recovered = true;
|
|
|
|
|
}
|
|
|
|
|
return (result);
|
|
|
|
|
} else {
|
|
|
|
|
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
|
|
|
|
|
"%s: journal file corrupt: "
|
|
|
|
|
"expected serial %u, got %u",
|
|
|
|
|
j->filename, pos->serial, xhdr.serial0);
|
|
|
|
|
return (ISC_R_UNEXPECTED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check for offset wraparound.
|
|
|
|
|
*/
|
|
|
|
|
if ((isc_offset_t)(pos->offset + sizeof(journal_rawxhdr_t) +
|
|
|
|
|
xhdr.size) < pos->offset)
|
|
|
|
|
{
|
|
|
|
|
hdrsize = (j->xhdr_version == XHDR_VERSION2)
|
|
|
|
|
? sizeof(journal_rawxhdr_t)
|
|
|
|
|
: sizeof(journal_rawxhdr_ver1_t);
|
|
|
|
|
|
|
|
|
|
if ((isc_offset_t)(pos->offset + hdrsize + xhdr.size) < pos->offset) {
|
|
|
|
|
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
|
|
|
|
|
"%s: offset too large", j->filename);
|
|
|
|
|
return (ISC_R_UNEXPECTED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos->offset += sizeof(journal_rawxhdr_t) + xhdr.size;
|
|
|
|
|
pos->offset += hdrsize + xhdr.size;
|
|
|
|
|
pos->serial = xhdr.serial1;
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
}
|
|
|
|
@@ -879,9 +978,11 @@ index_find(dns_journal_t *j, uint32_t serial, journal_pos_t *best_guess) {
|
|
|
|
|
static void
|
|
|
|
|
index_add(dns_journal_t *j, journal_pos_t *pos) {
|
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
|
|
if (j->index == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Search for a vacant position.
|
|
|
|
|
*/
|
|
|
|
@@ -953,6 +1054,7 @@ static isc_result_t
|
|
|
|
|
journal_find(dns_journal_t *j, uint32_t serial, journal_pos_t *pos) {
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
journal_pos_t current_pos;
|
|
|
|
|
|
|
|
|
|
REQUIRE(DNS_JOURNAL_VALID(j));
|
|
|
|
|
|
|
|
|
|
if (DNS_SERIAL_GT(j->header.begin.serial, serial)) {
|
|
|
|
@@ -973,7 +1075,7 @@ journal_find(dns_journal_t *j, uint32_t serial, journal_pos_t *pos) {
|
|
|
|
|
if (DNS_SERIAL_GT(current_pos.serial, serial)) {
|
|
|
|
|
return (ISC_R_NOTFOUND);
|
|
|
|
|
}
|
|
|
|
|
result = journal_next(j, ¤t_pos);
|
|
|
|
|
result = journal_next(j, ¤t_pos, false);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
@@ -1187,7 +1289,7 @@ dns_journal_commit(dns_journal_t *j) {
|
|
|
|
|
if (!JOURNAL_EMPTY(&j->header)) {
|
|
|
|
|
while (!DNS_SERIAL_GT(j->x.pos[1].serial,
|
|
|
|
|
j->header.begin.serial)) {
|
|
|
|
|
CHECK(journal_next(j, &j->header.begin));
|
|
|
|
|
CHECK(journal_next(j, &j->header.begin, false));
|
|
|
|
|
}
|
|
|
|
|
index_invalidate(j, j->x.pos[1].serial);
|
|
|
|
|
}
|
|
|
|
@@ -1256,6 +1358,7 @@ failure:
|
|
|
|
|
isc_result_t
|
|
|
|
|
dns_journal_write_transaction(dns_journal_t *j, dns_diff_t *diff) {
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
|
|
CHECK(dns_diff_sort(diff, ixfr_order));
|
|
|
|
|
CHECK(dns_journal_begin_transaction(j));
|
|
|
|
|
CHECK(dns_journal_writediff(j, diff));
|
|
|
|
@@ -1267,9 +1370,13 @@ failure:
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_journal_destroy(dns_journal_t **journalp) {
|
|
|
|
|
dns_journal_t *j = *journalp;
|
|
|
|
|
dns_journal_t *j = NULL;
|
|
|
|
|
|
|
|
|
|
REQUIRE(journalp != NULL);
|
|
|
|
|
REQUIRE(DNS_JOURNAL_VALID(*journalp));
|
|
|
|
|
|
|
|
|
|
j = *journalp;
|
|
|
|
|
*journalp = NULL;
|
|
|
|
|
REQUIRE(DNS_JOURNAL_VALID(j));
|
|
|
|
|
|
|
|
|
|
j->it.result = ISC_R_FAILURE;
|
|
|
|
|
dns_name_invalidate(&j->it.name);
|
|
|
|
@@ -1346,33 +1453,38 @@ roll_forward(dns_journal_t *j, dns_db_t *db, unsigned int options) {
|
|
|
|
|
* Locate a journal entry for the current database serial.
|
|
|
|
|
*/
|
|
|
|
|
CHECK(journal_find(j, db_serial, &pos));
|
|
|
|
|
/*
|
|
|
|
|
* XXX do more drastic things, like marking zone stale,
|
|
|
|
|
* if this fails?
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
* XXXRTH The zone code should probably mark the zone as bad and
|
|
|
|
|
* scream loudly into the log if this is a dynamic update
|
|
|
|
|
* log reply that failed.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
end_serial = dns_journal_last_serial(j);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we're reading a version 1 file, scan all the transactions
|
|
|
|
|
* to see if the journal needs rewriting: if any outdated
|
|
|
|
|
* transaction headers are found, j->recovered will be set.
|
|
|
|
|
*/
|
|
|
|
|
if (j->header_ver1) {
|
|
|
|
|
uint32_t start_serial = dns_journal_first_serial(j);
|
|
|
|
|
|
|
|
|
|
CHECK(dns_journal_iter_init(j, start_serial, db_serial, NULL));
|
|
|
|
|
for (result = dns_journal_first_rr(j); result == ISC_R_SUCCESS;
|
|
|
|
|
result = dns_journal_next_rr(j))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (db_serial == end_serial) {
|
|
|
|
|
CHECK(DNS_R_UPTODATE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHECK(dns_journal_iter_init(j, db_serial, end_serial, NULL));
|
|
|
|
|
|
|
|
|
|
for (result = dns_journal_first_rr(j); result == ISC_R_SUCCESS;
|
|
|
|
|
result = dns_journal_next_rr(j))
|
|
|
|
|
{
|
|
|
|
|
dns_name_t *name;
|
|
|
|
|
uint32_t ttl;
|
|
|
|
|
dns_rdata_t *rdata;
|
|
|
|
|
dns_name_t *name = NULL;
|
|
|
|
|
dns_rdata_t *rdata = NULL;
|
|
|
|
|
dns_difftuple_t *tuple = NULL;
|
|
|
|
|
uint32_t ttl;
|
|
|
|
|
|
|
|
|
|
name = NULL;
|
|
|
|
|
rdata = NULL;
|
|
|
|
|
dns_journal_current_rr(j, &name, &ttl, &rdata);
|
|
|
|
|
|
|
|
|
|
if (rdata->type == dns_rdatatype_soa) {
|
|
|
|
@@ -1450,13 +1562,12 @@ failure:
|
|
|
|
|
isc_result_t
|
|
|
|
|
dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, unsigned int options,
|
|
|
|
|
const char *filename) {
|
|
|
|
|
dns_journal_t *j;
|
|
|
|
|
dns_journal_t *j = NULL;
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
|
|
REQUIRE(DNS_DB_VALID(db));
|
|
|
|
|
REQUIRE(filename != NULL);
|
|
|
|
|
|
|
|
|
|
j = NULL;
|
|
|
|
|
result = dns_journal_open(mctx, filename, DNS_JOURNAL_READ, &j);
|
|
|
|
|
if (result == ISC_R_NOTFOUND) {
|
|
|
|
|
isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no journal file, but "
|
|
|
|
@@ -1466,20 +1577,26 @@ dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, unsigned int options,
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (JOURNAL_EMPTY(&j->header)) {
|
|
|
|
|
result = DNS_R_UPTODATE;
|
|
|
|
|
} else {
|
|
|
|
|
result = roll_forward(j, db, options);
|
|
|
|
|
CHECK(DNS_R_UPTODATE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dns_journal_destroy(&j);
|
|
|
|
|
result = roll_forward(j, db, options);
|
|
|
|
|
if ((result == ISC_R_SUCCESS || result == DNS_R_UPTODATE) &&
|
|
|
|
|
j->recovered) {
|
|
|
|
|
result = DNS_R_RECOVERABLE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
failure:
|
|
|
|
|
dns_journal_destroy(&j);
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
|
dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
|
|
|
|
|
dns_journal_t *j;
|
|
|
|
|
dns_journal_print(isc_mem_t *mctx, uint32_t flags, const char *filename,
|
|
|
|
|
FILE *file) {
|
|
|
|
|
dns_journal_t *j = NULL;
|
|
|
|
|
isc_buffer_t source; /* Transaction data from disk */
|
|
|
|
|
isc_buffer_t target; /* Ditto after _fromwire check */
|
|
|
|
|
uint32_t start_serial; /* Database SOA serial */
|
|
|
|
@@ -1488,17 +1605,15 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
|
|
|
|
|
dns_diff_t diff;
|
|
|
|
|
unsigned int n_soa = 0;
|
|
|
|
|
unsigned int n_put = 0;
|
|
|
|
|
bool printxhdr = ((flags & DNS_JOURNAL_PRINTXHDR) != 0);
|
|
|
|
|
|
|
|
|
|
REQUIRE(filename != NULL);
|
|
|
|
|
|
|
|
|
|
j = NULL;
|
|
|
|
|
result = dns_journal_open(mctx, filename, DNS_JOURNAL_READ, &j);
|
|
|
|
|
if (result == ISC_R_NOTFOUND) {
|
|
|
|
|
isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no journal file");
|
|
|
|
|
return (DNS_R_NOJOURNAL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
} else if (result != ISC_R_SUCCESS) {
|
|
|
|
|
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
|
|
|
|
|
"journal open failure: %s: %s",
|
|
|
|
|
isc_result_totext(result), filename);
|
|
|
|
@@ -1526,13 +1641,11 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
|
|
|
|
|
for (result = dns_journal_first_rr(j); result == ISC_R_SUCCESS;
|
|
|
|
|
result = dns_journal_next_rr(j))
|
|
|
|
|
{
|
|
|
|
|
dns_name_t *name;
|
|
|
|
|
uint32_t ttl;
|
|
|
|
|
dns_rdata_t *rdata;
|
|
|
|
|
dns_name_t *name = NULL;
|
|
|
|
|
dns_rdata_t *rdata = NULL;
|
|
|
|
|
dns_difftuple_t *tuple = NULL;
|
|
|
|
|
uint32_t ttl;
|
|
|
|
|
|
|
|
|
|
name = NULL;
|
|
|
|
|
rdata = NULL;
|
|
|
|
|
dns_journal_current_rr(j, &name, &ttl, &rdata);
|
|
|
|
|
|
|
|
|
|
if (rdata->type == dns_rdatatype_soa) {
|
|
|
|
@@ -1549,12 +1662,21 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
|
|
|
|
|
j->filename);
|
|
|
|
|
FAIL(ISC_R_UNEXPECTED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (printxhdr && n_soa == 1) {
|
|
|
|
|
fprintf(file,
|
|
|
|
|
"Transaction: version %d size %u rrcount %u "
|
|
|
|
|
"startserial %u endserial %u\n",
|
|
|
|
|
j->xhdr_version, j->curxhdr.size,
|
|
|
|
|
j->curxhdr.count, j->curxhdr.serial0,
|
|
|
|
|
j->curxhdr.serial1);
|
|
|
|
|
}
|
|
|
|
|
CHECK(dns_difftuple_create(
|
|
|
|
|
diff.mctx, n_soa == 1 ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD,
|
|
|
|
|
name, ttl, rdata, &tuple));
|
|
|
|
|
dns_diff_append(&diff, &tuple);
|
|
|
|
|
|
|
|
|
|
if (++n_put > 100) {
|
|
|
|
|
if (++n_put != 0 || printxhdr) {
|
|
|
|
|
result = dns_diff_print(&diff, file);
|
|
|
|
|
dns_diff_clear(&diff);
|
|
|
|
|
n_put = 0;
|
|
|
|
@@ -1568,7 +1690,7 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
|
|
|
|
|
}
|
|
|
|
|
CHECK(result);
|
|
|
|
|
|
|
|
|
|
if (n_put != 0) {
|
|
|
|
|
if (!printxhdr && n_put != 0) {
|
|
|
|
|
result = dns_diff_print(&diff, file);
|
|
|
|
|
dns_diff_clear(&diff);
|
|
|
|
|
}
|
|
|
|
@@ -1648,7 +1770,7 @@ dns_journal_get_sourceserial(dns_journal_t *j, uint32_t *sourceserial) {
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
|
read_one_rr(dns_journal_t *j);
|
|
|
|
|
read_one_rr(dns_journal_t *j, bool retry);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure the buffer 'b' is has at least 'size' bytes
|
|
|
|
@@ -1706,7 +1828,7 @@ dns_journal_iter_init(dns_journal_t *j, uint32_t begin_serial,
|
|
|
|
|
size += xhdr.size;
|
|
|
|
|
count += xhdr.count;
|
|
|
|
|
|
|
|
|
|
result = journal_next(j, &pos);
|
|
|
|
|
result = journal_next(j, &pos, false);
|
|
|
|
|
if (result == ISC_R_NOMORE) {
|
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
}
|
|
|
|
@@ -1742,22 +1864,22 @@ dns_journal_first_rr(dns_journal_t *j) {
|
|
|
|
|
j->it.xsize = 0; /* We have no transaction data yet... */
|
|
|
|
|
j->it.xpos = 0; /* ...and haven't used any of it. */
|
|
|
|
|
|
|
|
|
|
return (read_one_rr(j));
|
|
|
|
|
return (read_one_rr(j, false));
|
|
|
|
|
|
|
|
|
|
failure:
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
|
read_one_rr(dns_journal_t *j) {
|
|
|
|
|
read_one_rr(dns_journal_t *j, bool retry) {
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
|
|
dns_rdatatype_t rdtype;
|
|
|
|
|
dns_rdataclass_t rdclass;
|
|
|
|
|
unsigned int rdlen;
|
|
|
|
|
uint32_t ttl;
|
|
|
|
|
journal_xhdr_t xhdr;
|
|
|
|
|
journal_rrhdr_t rrhdr;
|
|
|
|
|
dns_journal_t save = *j;
|
|
|
|
|
|
|
|
|
|
if (j->offset > j->it.epos.offset) {
|
|
|
|
|
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
|
|
|
|
@@ -1780,7 +1902,34 @@ read_one_rr(dns_journal_t *j) {
|
|
|
|
|
j->filename);
|
|
|
|
|
FAIL(ISC_R_UNEXPECTED);
|
|
|
|
|
}
|
|
|
|
|
if (xhdr.serial0 != j->it.current_serial) {
|
|
|
|
|
if (xhdr.serial0 != j->it.current_serial ||
|
|
|
|
|
isc_serial_le(xhdr.serial1, xhdr.serial0))
|
|
|
|
|
{
|
|
|
|
|
if (!retry && j->header_ver1 &&
|
|
|
|
|
j->xhdr_version == XHDR_VERSION2 &&
|
|
|
|
|
xhdr.count == j->it.current_serial)
|
|
|
|
|
{
|
|
|
|
|
/* XHDR_VERSION2 -> XHDR_VERSION1 */
|
|
|
|
|
j->xhdr_version = XHDR_VERSION1;
|
|
|
|
|
CHECK(journal_seek(j, save.offset));
|
|
|
|
|
result = read_one_rr(j, true);
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
j->recovered = true;
|
|
|
|
|
}
|
|
|
|
|
return (result);
|
|
|
|
|
} else if (!retry && j->header_ver1 &&
|
|
|
|
|
j->xhdr_version == XHDR_VERSION1 &&
|
|
|
|
|
xhdr.serial1 == j->it.current_serial)
|
|
|
|
|
{
|
|
|
|
|
/* XHDR_VERSION1 -> XHDR_VERSION2 */
|
|
|
|
|
j->xhdr_version = XHDR_VERSION2;
|
|
|
|
|
CHECK(journal_seek(j, save.offset));
|
|
|
|
|
result = read_one_rr(j, true);
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
j->recovered = true;
|
|
|
|
|
}
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
|
|
|
|
|
"%s: journal file corrupt: "
|
|
|
|
|
"expected serial %u, got %u",
|
|
|
|
@@ -1871,7 +2020,7 @@ failure:
|
|
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
|
dns_journal_next_rr(dns_journal_t *j) {
|
|
|
|
|
j->it.result = read_one_rr(j);
|
|
|
|
|
j->it.result = read_one_rr(j, false);
|
|
|
|
|
return (j->it.result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2200,16 +2349,33 @@ failure:
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
|
rrcount(char *buf, unsigned int size) {
|
|
|
|
|
isc_buffer_t b;
|
|
|
|
|
uint32_t rrsize, count = 0;
|
|
|
|
|
|
|
|
|
|
isc_buffer_init(&b, buf, size);
|
|
|
|
|
isc_buffer_add(&b, size);
|
|
|
|
|
while (isc_buffer_remaininglength(&b) > 0) {
|
|
|
|
|
rrsize = isc_buffer_getuint32(&b);
|
|
|
|
|
INSIST(isc_buffer_remaininglength(&b) >= rrsize);
|
|
|
|
|
isc_buffer_forward(&b, rrsize);
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
|
dns_journal_compact(isc_mem_t *mctx, char *filename, uint32_t serial,
|
|
|
|
|
uint32_t target_size) {
|
|
|
|
|
uint32_t flags, uint32_t target_size) {
|
|
|
|
|
unsigned int i;
|
|
|
|
|
journal_pos_t best_guess;
|
|
|
|
|
journal_pos_t current_pos;
|
|
|
|
|
dns_journal_t *j1 = NULL;
|
|
|
|
|
dns_journal_t *j2 = NULL;
|
|
|
|
|
journal_rawheader_t rawheader;
|
|
|
|
|
unsigned int copy_length;
|
|
|
|
|
unsigned int len;
|
|
|
|
|
size_t namelen;
|
|
|
|
|
char *buf = NULL;
|
|
|
|
|
unsigned int size = 0;
|
|
|
|
@@ -2218,6 +2384,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, uint32_t serial,
|
|
|
|
|
char newname[PATH_MAX];
|
|
|
|
|
char backup[PATH_MAX];
|
|
|
|
|
bool is_backup = false;
|
|
|
|
|
bool rewrite = false;
|
|
|
|
|
|
|
|
|
|
REQUIRE(filename != NULL);
|
|
|
|
|
|
|
|
|
@@ -2243,7 +2410,14 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, uint32_t serial,
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (JOURNAL_EMPTY(&j1->header)) {
|
|
|
|
|
/*
|
|
|
|
|
* Check whether we need to rewrite the whole journal
|
|
|
|
|
* file (for example, to upversion it).
|
|
|
|
|
*/
|
|
|
|
|
if ((flags & DNS_JOURNAL_COMPACTALL) != 0) {
|
|
|
|
|
rewrite = true;
|
|
|
|
|
serial = dns_journal_first_serial(j1);
|
|
|
|
|
} else if (JOURNAL_EMPTY(&j1->header)) {
|
|
|
|
|
dns_journal_destroy(&j1);
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
}
|
|
|
|
@@ -2270,12 +2444,13 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, uint32_t serial,
|
|
|
|
|
/*
|
|
|
|
|
* See if there is any work to do.
|
|
|
|
|
*/
|
|
|
|
|
if ((uint32_t)j1->header.end.offset < target_size) {
|
|
|
|
|
if (!rewrite && (uint32_t)j1->header.end.offset < target_size) {
|
|
|
|
|
dns_journal_destroy(&j1);
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHECK(journal_open(mctx, newname, true, true, &j2));
|
|
|
|
|
CHECK(journal_seek(j2, indexend));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Remove overhead so space test below can succeed.
|
|
|
|
@@ -2301,7 +2476,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, uint32_t serial,
|
|
|
|
|
|
|
|
|
|
current_pos = best_guess;
|
|
|
|
|
while (current_pos.serial != serial) {
|
|
|
|
|
CHECK(journal_next(j1, ¤t_pos));
|
|
|
|
|
CHECK(journal_next(j1, ¤t_pos, false));
|
|
|
|
|
if (current_pos.serial == j1->header.end.serial) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@@ -2319,7 +2494,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, uint32_t serial,
|
|
|
|
|
|
|
|
|
|
INSIST(best_guess.serial != j1->header.end.serial);
|
|
|
|
|
if (best_guess.serial != serial) {
|
|
|
|
|
CHECK(journal_next(j1, &best_guess));
|
|
|
|
|
CHECK(journal_next(j1, &best_guess, false));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -2327,40 +2502,98 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, uint32_t serial,
|
|
|
|
|
* we did not reach 'serial'. If not we will just copy
|
|
|
|
|
* all uncommitted deltas regardless of the size.
|
|
|
|
|
*/
|
|
|
|
|
copy_length = j1->header.end.offset - best_guess.offset;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
len = j1->header.end.offset - best_guess.offset;
|
|
|
|
|
if (len != 0) {
|
|
|
|
|
CHECK(journal_seek(j1, best_guess.offset));
|
|
|
|
|
CHECK(journal_seek(j2, indexend));
|
|
|
|
|
for (i = 0; i < copy_length; i += size) {
|
|
|
|
|
unsigned int len = (copy_length - i) > size
|
|
|
|
|
? size
|
|
|
|
|
: (copy_length - i);
|
|
|
|
|
CHECK(journal_read(j1, buf, len));
|
|
|
|
|
CHECK(journal_write(j2, buf, len));
|
|
|
|
|
|
|
|
|
|
/* Prepare new header */
|
|
|
|
|
j2->header.begin.serial = best_guess.serial;
|
|
|
|
|
j2->header.begin.offset = indexend;
|
|
|
|
|
j2->header.sourceserial = j1->header.sourceserial;
|
|
|
|
|
j2->header.serialset = j1->header.serialset;
|
|
|
|
|
j2->header.end.serial = j1->header.end.serial;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Only use this method if we're rewriting the
|
|
|
|
|
* journal to fix outdated transaction headers;
|
|
|
|
|
* otherwise we'll copy the whole journal without
|
|
|
|
|
* parsing individual deltas below.
|
|
|
|
|
*/
|
|
|
|
|
while (rewrite && len > 0) {
|
|
|
|
|
journal_xhdr_t xhdr;
|
|
|
|
|
isc_offset_t offset = j1->offset;
|
|
|
|
|
uint32_t count;
|
|
|
|
|
|
|
|
|
|
result = journal_read_xhdr(j1, &xhdr);
|
|
|
|
|
if (rewrite && result == ISC_R_NOMORE) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
CHECK(result);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we're repairing an outdated journal, the
|
|
|
|
|
* xhdr format may be wrong.
|
|
|
|
|
*/
|
|
|
|
|
if (rewrite &&
|
|
|
|
|
(xhdr.serial0 != serial ||
|
|
|
|
|
isc_serial_le(xhdr.serial1, xhdr.serial0)))
|
|
|
|
|
{
|
|
|
|
|
if (j1->xhdr_version == XHDR_VERSION2 &&
|
|
|
|
|
xhdr.count == serial) {
|
|
|
|
|
/* XHDR_VERSION2 -> XHDR_VERSION1 */
|
|
|
|
|
j1->xhdr_version = XHDR_VERSION1;
|
|
|
|
|
CHECK(journal_seek(j1, offset));
|
|
|
|
|
CHECK(journal_read_xhdr(j1, &xhdr));
|
|
|
|
|
} else if (j1->xhdr_version == XHDR_VERSION1 &&
|
|
|
|
|
xhdr.serial1 == serial) {
|
|
|
|
|
/* XHDR_VERSION1 -> XHDR_VERSION2 */
|
|
|
|
|
j1->xhdr_version = XHDR_VERSION2;
|
|
|
|
|
CHECK(journal_seek(j1, offset));
|
|
|
|
|
CHECK(journal_read_xhdr(j1, &xhdr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check again */
|
|
|
|
|
if (xhdr.serial0 != serial ||
|
|
|
|
|
isc_serial_le(xhdr.serial1, xhdr.serial0)) {
|
|
|
|
|
CHECK(ISC_R_UNEXPECTED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = xhdr.size;
|
|
|
|
|
buf = isc_mem_get(mctx, size);
|
|
|
|
|
CHECK(journal_read(j1, buf, size));
|
|
|
|
|
|
|
|
|
|
count = rrcount(buf, size);
|
|
|
|
|
CHECK(journal_write_xhdr(j2, xhdr.size, count,
|
|
|
|
|
xhdr.serial0, xhdr.serial1));
|
|
|
|
|
CHECK(journal_write(j2, buf, size));
|
|
|
|
|
|
|
|
|
|
j2->header.end.offset = j2->offset;
|
|
|
|
|
|
|
|
|
|
serial = xhdr.serial1;
|
|
|
|
|
|
|
|
|
|
len = j1->header.end.offset - j1->offset;
|
|
|
|
|
isc_mem_put(mctx, buf, size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we're not rewriting transaction headers, we can use
|
|
|
|
|
* this faster method instead.
|
|
|
|
|
*/
|
|
|
|
|
if (!rewrite) {
|
|
|
|
|
size = ISC_MIN(64 * 1024, len);
|
|
|
|
|
buf = isc_mem_get(mctx, size);
|
|
|
|
|
for (i = 0; i < len; i += size) {
|
|
|
|
|
unsigned int blob = ISC_MIN(size, len - i);
|
|
|
|
|
CHECK(journal_read(j1, buf, blob));
|
|
|
|
|
CHECK(journal_write(j2, buf, blob));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
j2->header.end.offset = indexend + len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHECK(journal_fsync(j2));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Compute new header.
|
|
|
|
|
*/
|
|
|
|
|
j2->header.begin.serial = best_guess.serial;
|
|
|
|
|
j2->header.begin.offset = indexend;
|
|
|
|
|
j2->header.end.serial = j1->header.end.serial;
|
|
|
|
|
j2->header.end.offset = indexend + copy_length;
|
|
|
|
|
j2->header.sourceserial = j1->header.sourceserial;
|
|
|
|
|
j2->header.serialset = j1->header.serialset;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Update the journal header.
|
|
|
|
|
*/
|
|
|
|
@@ -2375,7 +2608,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, uint32_t serial,
|
|
|
|
|
current_pos = j2->header.begin;
|
|
|
|
|
while (current_pos.serial != j2->header.end.serial) {
|
|
|
|
|
index_add(j2, ¤t_pos);
|
|
|
|
|
CHECK(journal_next(j2, ¤t_pos));
|
|
|
|
|
CHECK(journal_next(j2, ¤t_pos, false));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|