load the journal file if it already exists

apply the existing journal file, if any, to the old version of the
database before diffing it against the new version. then, append
the diff to the end of the journal. this allows easy creation of
a journal file with multiple deltas, by running named-makejournal
successively.
This commit is contained in:
Evan Hunt 2025-02-05 23:08:27 -08:00
parent 669e304bd1
commit 365e4de077
2 changed files with 69 additions and 10 deletions

View file

@ -22,6 +22,7 @@
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/result.h>
#include <isc/serial.h>
#include <isc/util.h>
#include <dns/db.h>
@ -67,6 +68,48 @@ loadzone(dns_db_t **db, const char *origin, const char *filename) {
return result;
}
static isc_result_t
loadjournal(dns_db_t *db, const char *file) {
dns_journal_t *jnl = NULL;
isc_result_t result;
result = dns_journal_open(mctx, file, DNS_JOURNAL_READ, &jnl);
if (result == ISC_R_NOTFOUND) {
return ISC_R_SUCCESS;
} else if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Error: unable to open journal %s: %s\n", file,
isc_result_totext(result));
return result;
}
if (dns_journal_empty(jnl)) {
dns_journal_destroy(&jnl);
return ISC_R_SUCCESS;
}
result = dns_journal_rollforward(jnl, db, 0);
switch (result) {
case ISC_R_SUCCESS:
break;
case DNS_R_UPTODATE:
result = ISC_R_SUCCESS;
break;
case ISC_R_NOTFOUND:
case ISC_R_RANGE:
fprintf(stderr, "Error: journal %s out of sync with zone",
file);
break;
default:
fprintf(stderr, "Error: journal %s: %s\n", file,
isc_result_totext(result));
}
dns_journal_destroy(&jnl);
return result;
}
int
main(int argc, char **argv) {
isc_result_t result;
@ -75,6 +118,7 @@ main(int argc, char **argv) {
const char *journal = NULL;
dns_db_t *olddb = NULL, *newdb = NULL;
isc_logconfig_t *logconfig = NULL;
uint32_t s1, s2, s3;
int ch;
isc_commandline_init(argc, argv);
@ -130,22 +174,35 @@ main(int argc, char **argv) {
goto cleanup;
}
uint32_t s1, s2;
result = dns_db_getsoaserial(olddb, NULL, &s1);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Error: no SOA found in %s\n", file1);
fprintf(stderr, "Error: %s: SOA lookup failed\n", file1);
goto cleanup;
}
result = dns_db_getsoaserial(newdb, NULL, &s2);
result = loadjournal(olddb, journal);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Error: no SOA found in %s\n", file2);
goto cleanup;
}
if (s1 == s2) {
result = dns_db_getsoaserial(olddb, NULL, &s2);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = dns_db_getsoaserial(newdb, NULL, &s3);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Error: %s: SOA lookup failed\n", file2);
goto cleanup;
}
if (isc_serial_eq(s1, s3)) {
fprintf(stderr,
"Error: SOA serial (%u) unchanged between files\n", s1);
result = ISC_R_FAILURE;
goto cleanup;
} else if (isc_serial_eq(s2, s3)) {
fprintf(stderr, "Journal %s already has serial %u\n", journal,
s3);
goto cleanup;
}
result = dns_db_diff(mctx, newdb, NULL, olddb, NULL, journal);
@ -166,5 +223,5 @@ cleanup:
isc_mem_detach(&mctx);
}
return result != ISC_R_SUCCESS ? 1 : 0;
return (result != ISC_R_SUCCESS) ? 1 : 0;
}

View file

@ -40,10 +40,12 @@ If the optional argument ``journal`` is not specified, then the journal
file name will be formed by appending the extension ``.jnl`` to the
zone file name specified as ``oldfile``.
If the journal file already exists, a new transaction will be appended
onto the end of it. (Note, however, that the most recent serial number in
the existing journal file must match the serial number in ``oldfile``.
This will be corrected later.)
If the journal file already exists, then it will be applied to ``oldfile``
immediately after loading. The difference between the resulting zone and
the one in ``newfile`` will then be appended onto the end of the journal.
This allows creation of journal files with multiple transactions, by
running ``named-makejournal`` multiple times, updating ``newfile`` each
time.
Options
~~~~~~~