]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
dns_journal_iter_init() can now return the size of the delta
authorEvan Hunt <each@isc.org>
Sat, 22 Feb 2020 01:05:04 +0000 (17:05 -0800)
committerOndřej Surý <ondrej@sury.org>
Tue, 26 Jan 2021 11:38:32 +0000 (12:38 +0100)
the call initailizing a journal iterator can now optionally return
to the caller the size in bytes of an IXFR message (not including
DNS header overhead, signatures etc) containing the differences from
the beginning to the ending serial number.

this is calculated by scanning the journal transaction headers to
calculate the transfer size. since journal file records contain a length
field that is not included in IXFR messages, we subtract out the length
of those fields from the overall transaction length.

this necessitated adding an "RR count" field to the journal transaction
header, so we know how many length fields to subract. NOTE: this will
make existing journal files stop working!

lib/dns/include/dns/journal.h
lib/dns/journal.c
lib/dns/zone.c
lib/ns/xfrout.c

index a086aaa62fe084d67af8a991d1a00f12d7d40aba..8acf9ab44eab2b6bac71d395bc096d8cefe66896 100644 (file)
@@ -190,11 +190,17 @@ dns_journal_last_serial(dns_journal_t *j);
 
 isc_result_t
 dns_journal_iter_init(dns_journal_t *j, uint32_t begin_serial,
-                     uint32_t end_serial);
+                     uint32_t end_serial, size_t *xfrsizep);
 /*%<
  * Prepare to iterate over the transactions that will bring the database
  * from SOA serial number 'begin_serial' to 'end_serial'.
  *
+ * If 'xfrsizep' is not NULL, then on success it will be set to the
+ * total size of all records in the iteration (excluding headers). This
+ * is meant to be a rough approximation of the size of an incremental
+ * zone transfer, though it does not account for DNS message overhead
+ * or name compression.)
+ *
  * Returns:
  *\li  ISC_R_SUCCESS
  *\li  ISC_R_RANGE     begin_serial is outside the addressable range.
index c1e3a7a4df8861babd1860c05f79754845705b22..bc1ad96314e06492dcd4f3bc74b9ad152ad4f592 100644 (file)
@@ -221,6 +221,7 @@ typedef union {
  */
 typedef struct {
        unsigned char size[4];    /*%< In bytes, excluding header. */
+       unsigned char count[4];   /*%< Number of records in transaction */
        unsigned char serial0[4]; /*%< SOA serial before update. */
        unsigned char serial1[4]; /*%< SOA serial after update. */
 } journal_rawxhdr_t;
@@ -256,9 +257,9 @@ typedef struct {
 /*%
  * The in-core representation of the transaction header.
  */
-
 typedef struct {
        uint32_t size;
+       uint32_t count;
        uint32_t serial0;
        uint32_t serial1;
 } journal_xhdr_t;
@@ -304,13 +305,13 @@ struct dns_journal {
        isc_offset_t offset;     /*%< Current file offset */
        journal_header_t header; /*%< In-core journal header */
        unsigned char *rawindex; /*%< In-core buffer for journal index
-                                 * in
-                                 * on-disk format */
+                                 * in on-disk format */
        journal_pos_t *index;    /*%< In-core journal index */
 
        /*% Current transaction state (when writing). */
        struct {
                unsigned int n_soa;   /*%< Number of SOAs seen */
+               unsigned int n_rr;    /*%< Number of RRs to write */
                journal_pos_t pos[2]; /*%< Begin/end position */
        } x;
 
@@ -323,8 +324,7 @@ struct dns_journal {
                uint32_t current_serial; /*%< Current SOA serial
                                          * */
                isc_buffer_t source;     /*%< Data from disk */
-               isc_buffer_t target;     /*%< Data from _fromwire check
-                                         * */
+               isc_buffer_t target;     /*%< Data from _fromwire check */
                dns_decompress_t dctx;   /*%< Dummy decompression ctx */
                dns_name_t name;         /*%< Current domain name */
                dns_rdata_t rdata;       /*%< Current rdata */
@@ -462,16 +462,18 @@ journal_read_xhdr(dns_journal_t *j, journal_xhdr_t *xhdr) {
                return (result);
        }
        xhdr->size = decode_uint32(raw.size);
+       xhdr->count = decode_uint32(raw.count);
        xhdr->serial0 = decode_uint32(raw.serial0);
        xhdr->serial1 = decode_uint32(raw.serial1);
        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
-journal_write_xhdr(dns_journal_t *j, uint32_t size, uint32_t serial0,
-                  uint32_t serial1) {
+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);
        encode_uint32(serial1, raw.serial1);
        return (journal_write(j, &raw, sizeof(raw)));
@@ -1026,7 +1028,8 @@ dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff) {
        dns_difftuple_t *t;
        isc_buffer_t buffer;
        void *mem = NULL;
-       uint64_t size;
+       uint64_t size = 0;
+       uint32_t rrcount = 0;
        isc_result_t result;
        isc_region_t used;
 
@@ -1040,7 +1043,6 @@ dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff) {
         * Pass 1: determine the buffer size needed, and
         * keep track of SOA serial numbers.
         */
-       size = 0;
        for (t = ISC_LIST_HEAD(diff->tuples); t != NULL;
             t = ISC_LIST_NEXT(t, link)) {
                if (t->rdata.type == dns_rdatatype_soa) {
@@ -1089,12 +1091,15 @@ dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff) {
                isc_buffer_putuint16(&buffer, (uint16_t)t->rdata.length);
                INSIST(isc_buffer_availablelength(&buffer) >= t->rdata.length);
                isc_buffer_putmem(&buffer, t->rdata.data, t->rdata.length);
+
+               rrcount++;
        }
 
        isc_buffer_usedregion(&buffer, &used);
        INSIST(used.length == size);
 
        j->x.pos[1].offset += used.length;
+       j->x.n_rr = rrcount;
 
        /*
         * Write the buffer contents to the journal file.
@@ -1205,7 +1210,8 @@ dns_journal_commit(dns_journal_t *j) {
                 * Update the transaction header.
                 */
                CHECK(journal_seek(j, j->x.pos[0].offset));
-               CHECK(journal_write_xhdr(j, offset, j->x.pos[0].serial,
+               CHECK(journal_write_xhdr(j, offset, j->x.n_rr,
+                                        j->x.pos[0].serial,
                                         j->x.pos[1].serial));
        }
 
@@ -1355,7 +1361,7 @@ roll_forward(dns_journal_t *j, dns_db_t *db, unsigned int options) {
                CHECK(DNS_R_UPTODATE);
        }
 
-       CHECK(dns_journal_iter_init(j, db_serial, end_serial));
+       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))
@@ -1515,7 +1521,7 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
        start_serial = dns_journal_first_serial(j);
        end_serial = dns_journal_last_serial(j);
 
-       CHECK(dns_journal_iter_init(j, start_serial, end_serial));
+       CHECK(dns_journal_iter_init(j, start_serial, end_serial, NULL));
 
        for (result = dns_journal_first_rr(j); result == ISC_R_SUCCESS;
             result = dns_journal_next_rr(j))
@@ -1672,7 +1678,7 @@ size_buffer(isc_mem_t *mctx, isc_buffer_t *b, unsigned size) {
 
 isc_result_t
 dns_journal_iter_init(dns_journal_t *j, uint32_t begin_serial,
-                     uint32_t end_serial) {
+                     uint32_t end_serial, size_t *xfrsizep) {
        isc_result_t result;
 
        CHECK(journal_find(j, begin_serial, &j->it.bpos));
@@ -1681,6 +1687,41 @@ dns_journal_iter_init(dns_journal_t *j, uint32_t begin_serial,
        CHECK(journal_find(j, end_serial, &j->it.epos));
        INSIST(j->it.epos.serial == end_serial);
 
+       if (xfrsizep != NULL) {
+               journal_pos_t pos = j->it.bpos;
+               journal_xhdr_t xhdr;
+               uint64_t size = 0;
+               uint32_t count = 0;
+
+               /*
+                * We already know the beginning and ending serial
+                * numbers are in the journal. Scan through them,
+                * adding up sizes and RR counts so we can calculate
+                * the IXFR size.
+                */
+               CHECK(journal_seek(j, pos.offset));
+               do {
+                       CHECK(journal_read_xhdr(j, &xhdr));
+
+                       size += xhdr.size;
+                       count += xhdr.count;
+
+                       result = journal_next(j, &pos);
+                       if (result == ISC_R_NOMORE) {
+                               result = ISC_R_SUCCESS;
+                       }
+                       CHECK(result);
+               } while (pos.serial != end_serial);
+
+               /*
+                * For each RR, subtract the length of the RR header,
+                * as this would not be present in IXFR messages.
+                * (We don't need to worry about the transaction header
+                * because that was already excluded from xdr.size.)
+                */
+               *xfrsizep = size - (count * sizeof(journal_rawrrhdr_t));
+       }
+
        result = ISC_R_SUCCESS;
 failure:
        j->it.result = result;
index 94c9365f9cd6c5f52bcff6fcbfbb47d99d5e2ee5..656bbf74a0b6a946a0ad837809d4f8a5c59c7ca5 100644 (file)
@@ -15743,7 +15743,7 @@ sync_secure_journal(dns_zone_t *zone, dns_zone_t *raw, dns_journal_t *journal,
                return (DNS_R_UNCHANGED);
        }
 
-       CHECK(dns_journal_iter_init(journal, start, end));
+       CHECK(dns_journal_iter_init(journal, start, end, NULL));
        for (result = dns_journal_first_rr(journal); result == ISC_R_SUCCESS;
             result = dns_journal_next_rr(journal))
        {
index 3227c5eaa79615f61c0c5d94d60fb029f1296ecd..3b8ce93c51f3833b51f11447356f7606a0d3476b 100644 (file)
@@ -240,7 +240,8 @@ ixfr_rrstream_create(isc_mem_t *mctx, const char *journal_filename,
 
        CHECK(dns_journal_open(mctx, journal_filename, DNS_JOURNAL_READ,
                               &s->journal));
-       CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial));
+       CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial,
+                                   NULL));
 
        *sp = (rrstream_t *)s;
        return (ISC_R_SUCCESS);