]> 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)
committerEvan Hunt <each@isc.org>
Fri, 6 Mar 2020 01:20:16 +0000 (17:20 -0800)
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 f05e6ce3cba716c8b2e4676352f571aba3b6bf63..34ba91ac3e7f691ad0f5021e0849128ac2406635 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 e28dd61031608f1e356e3152b61662dfc869c5aa..d864010c7db37185fc14ad3afbca0ee0d6b2f133 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 e408e7ff4d791f83b04cc0fc2fdae89792aabe6a..17cbdeff241dcc3f0441a2f346cfde5176afb78f 100644 (file)
@@ -15299,7 +15299,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 a92783cf1bb55e78082e7c955a860cfb068c059b..eb8b49103317f1b8bfbda8ea999fcb254bc59992 100644 (file)
@@ -242,7 +242,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);