1*00b67f09SDavid van Moolenbroek /* $NetBSD: journal.c,v 1.9 2015/07/08 17:28:58 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004, 2005, 2007-2011, 2013, 2014 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 1999-2002 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: journal.c,v 1.120 2011/12/22 07:32:41 each Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek #include <config.h>
23*00b67f09SDavid van Moolenbroek
24*00b67f09SDavid van Moolenbroek #include <stdlib.h>
25*00b67f09SDavid van Moolenbroek #include <unistd.h>
26*00b67f09SDavid van Moolenbroek #include <errno.h>
27*00b67f09SDavid van Moolenbroek
28*00b67f09SDavid van Moolenbroek #include <isc/file.h>
29*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
30*00b67f09SDavid van Moolenbroek #include <isc/stdio.h>
31*00b67f09SDavid van Moolenbroek #include <isc/string.h>
32*00b67f09SDavid van Moolenbroek #include <isc/util.h>
33*00b67f09SDavid van Moolenbroek
34*00b67f09SDavid van Moolenbroek #include <dns/compress.h>
35*00b67f09SDavid van Moolenbroek #include <dns/db.h>
36*00b67f09SDavid van Moolenbroek #include <dns/dbiterator.h>
37*00b67f09SDavid van Moolenbroek #include <dns/diff.h>
38*00b67f09SDavid van Moolenbroek #include <dns/fixedname.h>
39*00b67f09SDavid van Moolenbroek #include <dns/journal.h>
40*00b67f09SDavid van Moolenbroek #include <dns/log.h>
41*00b67f09SDavid van Moolenbroek #include <dns/rdataset.h>
42*00b67f09SDavid van Moolenbroek #include <dns/rdatasetiter.h>
43*00b67f09SDavid van Moolenbroek #include <dns/result.h>
44*00b67f09SDavid van Moolenbroek #include <dns/soa.h>
45*00b67f09SDavid van Moolenbroek
46*00b67f09SDavid van Moolenbroek /*! \file
47*00b67f09SDavid van Moolenbroek * \brief Journaling.
48*00b67f09SDavid van Moolenbroek *
49*00b67f09SDavid van Moolenbroek * A journal file consists of
50*00b67f09SDavid van Moolenbroek *
51*00b67f09SDavid van Moolenbroek * \li A fixed-size header of type journal_rawheader_t.
52*00b67f09SDavid van Moolenbroek *
53*00b67f09SDavid van Moolenbroek * \li The index. This is an unordered array of index entries
54*00b67f09SDavid van Moolenbroek * of type journal_rawpos_t giving the locations
55*00b67f09SDavid van Moolenbroek * of some arbitrary subset of the journal's addressable
56*00b67f09SDavid van Moolenbroek * transactions. The index entries are used as hints to
57*00b67f09SDavid van Moolenbroek * speed up the process of locating a transaction with a given
58*00b67f09SDavid van Moolenbroek * serial number. Unused index entries have an "offset"
59*00b67f09SDavid van Moolenbroek * field of zero. The size of the index can vary between
60*00b67f09SDavid van Moolenbroek * journal files, but does not change during the lifetime
61*00b67f09SDavid van Moolenbroek * of a file. The size can be zero.
62*00b67f09SDavid van Moolenbroek *
63*00b67f09SDavid van Moolenbroek * \li The journal data. This consists of one or more transactions.
64*00b67f09SDavid van Moolenbroek * Each transaction begins with a transaction header of type
65*00b67f09SDavid van Moolenbroek * journal_rawxhdr_t. The transaction header is followed by a
66*00b67f09SDavid van Moolenbroek * sequence of RRs, similar in structure to an IXFR difference
67*00b67f09SDavid van Moolenbroek * sequence (RFC1995). That is, the pre-transaction SOA,
68*00b67f09SDavid van Moolenbroek * zero or more other deleted RRs, the post-transaction SOA,
69*00b67f09SDavid van Moolenbroek * and zero or more other added RRs. Unlike in IXFR, each RR
70*00b67f09SDavid van Moolenbroek * is prefixed with a 32-bit length.
71*00b67f09SDavid van Moolenbroek *
72*00b67f09SDavid van Moolenbroek * The journal data part grows as new transactions are
73*00b67f09SDavid van Moolenbroek * appended to the file. Only those transactions
74*00b67f09SDavid van Moolenbroek * whose serial number is current-(2^31-1) to current
75*00b67f09SDavid van Moolenbroek * are considered "addressable" and may be pointed
76*00b67f09SDavid van Moolenbroek * to from the header or index. They may be preceded
77*00b67f09SDavid van Moolenbroek * by old transactions that are no longer addressable,
78*00b67f09SDavid van Moolenbroek * and they may be followed by transactions that were
79*00b67f09SDavid van Moolenbroek * appended to the journal but never committed by updating
80*00b67f09SDavid van Moolenbroek * the "end" position in the header. The latter will
81*00b67f09SDavid van Moolenbroek * be overwritten when new transactions are added.
82*00b67f09SDavid van Moolenbroek */
83*00b67f09SDavid van Moolenbroek /*%
84*00b67f09SDavid van Moolenbroek * When true, accept IXFR difference sequences where the
85*00b67f09SDavid van Moolenbroek * SOA serial number does not change (BIND 8 sends such
86*00b67f09SDavid van Moolenbroek * sequences).
87*00b67f09SDavid van Moolenbroek */
88*00b67f09SDavid van Moolenbroek static isc_boolean_t bind8_compat = ISC_TRUE; /* XXX config */
89*00b67f09SDavid van Moolenbroek
90*00b67f09SDavid van Moolenbroek /**************************************************************************/
91*00b67f09SDavid van Moolenbroek /*
92*00b67f09SDavid van Moolenbroek * Miscellaneous utilities.
93*00b67f09SDavid van Moolenbroek */
94*00b67f09SDavid van Moolenbroek
95*00b67f09SDavid van Moolenbroek #define JOURNAL_COMMON_LOGARGS \
96*00b67f09SDavid van Moolenbroek dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_JOURNAL
97*00b67f09SDavid van Moolenbroek
98*00b67f09SDavid van Moolenbroek #define JOURNAL_DEBUG_LOGARGS(n) \
99*00b67f09SDavid van Moolenbroek JOURNAL_COMMON_LOGARGS, ISC_LOG_DEBUG(n)
100*00b67f09SDavid van Moolenbroek
101*00b67f09SDavid van Moolenbroek /*%
102*00b67f09SDavid van Moolenbroek * It would be non-sensical (or at least obtuse) to use FAIL() with an
103*00b67f09SDavid van Moolenbroek * ISC_R_SUCCESS code, but the test is there to keep the Solaris compiler
104*00b67f09SDavid van Moolenbroek * from complaining about "end-of-loop code not reached".
105*00b67f09SDavid van Moolenbroek */
106*00b67f09SDavid van Moolenbroek #define FAIL(code) \
107*00b67f09SDavid van Moolenbroek do { result = (code); \
108*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) goto failure; \
109*00b67f09SDavid van Moolenbroek } while (/*CONSTCOND*/0)
110*00b67f09SDavid van Moolenbroek
111*00b67f09SDavid van Moolenbroek #define CHECK(op) \
112*00b67f09SDavid van Moolenbroek do { result = (op); \
113*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) goto failure; \
114*00b67f09SDavid van Moolenbroek } while (/*CONSTCOND*/0)
115*00b67f09SDavid van Moolenbroek
116*00b67f09SDavid van Moolenbroek #define JOURNAL_SERIALSET 0x01U
117*00b67f09SDavid van Moolenbroek
118*00b67f09SDavid van Moolenbroek static isc_result_t index_to_disk(dns_journal_t *);
119*00b67f09SDavid van Moolenbroek
120*00b67f09SDavid van Moolenbroek static inline isc_uint32_t
decode_uint32(unsigned char * p)121*00b67f09SDavid van Moolenbroek decode_uint32(unsigned char *p) {
122*00b67f09SDavid van Moolenbroek return ((p[0] << 24) +
123*00b67f09SDavid van Moolenbroek (p[1] << 16) +
124*00b67f09SDavid van Moolenbroek (p[2] << 8) +
125*00b67f09SDavid van Moolenbroek (p[3] << 0));
126*00b67f09SDavid van Moolenbroek }
127*00b67f09SDavid van Moolenbroek
128*00b67f09SDavid van Moolenbroek static inline void
encode_uint32(isc_uint32_t val,unsigned char * p)129*00b67f09SDavid van Moolenbroek encode_uint32(isc_uint32_t val, unsigned char *p) {
130*00b67f09SDavid van Moolenbroek p[0] = (isc_uint8_t)(val >> 24);
131*00b67f09SDavid van Moolenbroek p[1] = (isc_uint8_t)(val >> 16);
132*00b67f09SDavid van Moolenbroek p[2] = (isc_uint8_t)(val >> 8);
133*00b67f09SDavid van Moolenbroek p[3] = (isc_uint8_t)(val >> 0);
134*00b67f09SDavid van Moolenbroek }
135*00b67f09SDavid van Moolenbroek
136*00b67f09SDavid van Moolenbroek isc_result_t
dns_db_createsoatuple(dns_db_t * db,dns_dbversion_t * ver,isc_mem_t * mctx,dns_diffop_t op,dns_difftuple_t ** tp)137*00b67f09SDavid van Moolenbroek dns_db_createsoatuple(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx,
138*00b67f09SDavid van Moolenbroek dns_diffop_t op, dns_difftuple_t **tp)
139*00b67f09SDavid van Moolenbroek {
140*00b67f09SDavid van Moolenbroek isc_result_t result;
141*00b67f09SDavid van Moolenbroek dns_dbnode_t *node;
142*00b67f09SDavid van Moolenbroek dns_rdataset_t rdataset;
143*00b67f09SDavid van Moolenbroek dns_rdata_t rdata = DNS_RDATA_INIT;
144*00b67f09SDavid van Moolenbroek dns_name_t *zonename;
145*00b67f09SDavid van Moolenbroek
146*00b67f09SDavid van Moolenbroek zonename = dns_db_origin(db);
147*00b67f09SDavid van Moolenbroek
148*00b67f09SDavid van Moolenbroek node = NULL;
149*00b67f09SDavid van Moolenbroek result = dns_db_findnode(db, zonename, ISC_FALSE, &node);
150*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
151*00b67f09SDavid van Moolenbroek goto nonode;
152*00b67f09SDavid van Moolenbroek
153*00b67f09SDavid van Moolenbroek dns_rdataset_init(&rdataset);
154*00b67f09SDavid van Moolenbroek result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0,
155*00b67f09SDavid van Moolenbroek (isc_stdtime_t)0, &rdataset, NULL);
156*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
157*00b67f09SDavid van Moolenbroek goto freenode;
158*00b67f09SDavid van Moolenbroek
159*00b67f09SDavid van Moolenbroek result = dns_rdataset_first(&rdataset);
160*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
161*00b67f09SDavid van Moolenbroek goto freenode;
162*00b67f09SDavid van Moolenbroek
163*00b67f09SDavid van Moolenbroek dns_rdataset_current(&rdataset, &rdata);
164*00b67f09SDavid van Moolenbroek
165*00b67f09SDavid van Moolenbroek result = dns_difftuple_create(mctx, op, zonename, rdataset.ttl,
166*00b67f09SDavid van Moolenbroek &rdata, tp);
167*00b67f09SDavid van Moolenbroek
168*00b67f09SDavid van Moolenbroek dns_rdataset_disassociate(&rdataset);
169*00b67f09SDavid van Moolenbroek dns_db_detachnode(db, &node);
170*00b67f09SDavid van Moolenbroek return (result);
171*00b67f09SDavid van Moolenbroek
172*00b67f09SDavid van Moolenbroek freenode:
173*00b67f09SDavid van Moolenbroek dns_db_detachnode(db, &node);
174*00b67f09SDavid van Moolenbroek nonode:
175*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__, "missing SOA");
176*00b67f09SDavid van Moolenbroek return (result);
177*00b67f09SDavid van Moolenbroek }
178*00b67f09SDavid van Moolenbroek
179*00b67f09SDavid van Moolenbroek /* Journaling */
180*00b67f09SDavid van Moolenbroek
181*00b67f09SDavid van Moolenbroek /*%
182*00b67f09SDavid van Moolenbroek * On-disk representation of a "pointer" to a journal entry.
183*00b67f09SDavid van Moolenbroek * These are used in the journal header to locate the beginning
184*00b67f09SDavid van Moolenbroek * and end of the journal, and in the journal index to locate
185*00b67f09SDavid van Moolenbroek * other transactions.
186*00b67f09SDavid van Moolenbroek */
187*00b67f09SDavid van Moolenbroek typedef struct {
188*00b67f09SDavid van Moolenbroek unsigned char serial[4]; /*%< SOA serial before update. */
189*00b67f09SDavid van Moolenbroek /*
190*00b67f09SDavid van Moolenbroek * XXXRTH Should offset be 8 bytes?
191*00b67f09SDavid van Moolenbroek * XXXDCL ... probably, since isc_offset_t is 8 bytes on many OSs.
192*00b67f09SDavid van Moolenbroek * XXXAG ... but we will not be able to seek >2G anyway on many
193*00b67f09SDavid van Moolenbroek * platforms as long as we are using fseek() rather
194*00b67f09SDavid van Moolenbroek * than lseek().
195*00b67f09SDavid van Moolenbroek */
196*00b67f09SDavid van Moolenbroek unsigned char offset[4]; /*%< Offset from beginning of file. */
197*00b67f09SDavid van Moolenbroek } journal_rawpos_t;
198*00b67f09SDavid van Moolenbroek
199*00b67f09SDavid van Moolenbroek
200*00b67f09SDavid van Moolenbroek /*%
201*00b67f09SDavid van Moolenbroek * The header is of a fixed size, with some spare room for future
202*00b67f09SDavid van Moolenbroek * extensions.
203*00b67f09SDavid van Moolenbroek */
204*00b67f09SDavid van Moolenbroek #define JOURNAL_HEADER_SIZE 64 /* Bytes. */
205*00b67f09SDavid van Moolenbroek
206*00b67f09SDavid van Moolenbroek /*%
207*00b67f09SDavid van Moolenbroek * The on-disk representation of the journal header.
208*00b67f09SDavid van Moolenbroek * All numbers are stored in big-endian order.
209*00b67f09SDavid van Moolenbroek */
210*00b67f09SDavid van Moolenbroek typedef union {
211*00b67f09SDavid van Moolenbroek struct {
212*00b67f09SDavid van Moolenbroek /*% File format version ID. */
213*00b67f09SDavid van Moolenbroek unsigned char format[16];
214*00b67f09SDavid van Moolenbroek /*% Position of the first addressable transaction */
215*00b67f09SDavid van Moolenbroek journal_rawpos_t begin;
216*00b67f09SDavid van Moolenbroek /*% Position of the next (yet nonexistent) transaction. */
217*00b67f09SDavid van Moolenbroek journal_rawpos_t end;
218*00b67f09SDavid van Moolenbroek /*% Number of index entries following the header. */
219*00b67f09SDavid van Moolenbroek unsigned char index_size[4];
220*00b67f09SDavid van Moolenbroek /*% Source serial number. */
221*00b67f09SDavid van Moolenbroek unsigned char sourceserial[4];
222*00b67f09SDavid van Moolenbroek unsigned char flags;
223*00b67f09SDavid van Moolenbroek } h;
224*00b67f09SDavid van Moolenbroek /* Pad the header to a fixed size. */
225*00b67f09SDavid van Moolenbroek unsigned char pad[JOURNAL_HEADER_SIZE];
226*00b67f09SDavid van Moolenbroek } journal_rawheader_t;
227*00b67f09SDavid van Moolenbroek
228*00b67f09SDavid van Moolenbroek /*%
229*00b67f09SDavid van Moolenbroek * The on-disk representation of the transaction header.
230*00b67f09SDavid van Moolenbroek * There is one of these at the beginning of each transaction.
231*00b67f09SDavid van Moolenbroek */
232*00b67f09SDavid van Moolenbroek typedef struct {
233*00b67f09SDavid van Moolenbroek unsigned char size[4]; /*%< In bytes, excluding header. */
234*00b67f09SDavid van Moolenbroek unsigned char serial0[4]; /*%< SOA serial before update. */
235*00b67f09SDavid van Moolenbroek unsigned char serial1[4]; /*%< SOA serial after update. */
236*00b67f09SDavid van Moolenbroek } journal_rawxhdr_t;
237*00b67f09SDavid van Moolenbroek
238*00b67f09SDavid van Moolenbroek /*%
239*00b67f09SDavid van Moolenbroek * The on-disk representation of the RR header.
240*00b67f09SDavid van Moolenbroek * There is one of these at the beginning of each RR.
241*00b67f09SDavid van Moolenbroek */
242*00b67f09SDavid van Moolenbroek typedef struct {
243*00b67f09SDavid van Moolenbroek unsigned char size[4]; /*%< In bytes, excluding header. */
244*00b67f09SDavid van Moolenbroek } journal_rawrrhdr_t;
245*00b67f09SDavid van Moolenbroek
246*00b67f09SDavid van Moolenbroek /*%
247*00b67f09SDavid van Moolenbroek * The in-core representation of the journal header.
248*00b67f09SDavid van Moolenbroek */
249*00b67f09SDavid van Moolenbroek typedef struct {
250*00b67f09SDavid van Moolenbroek isc_uint32_t serial;
251*00b67f09SDavid van Moolenbroek isc_offset_t offset;
252*00b67f09SDavid van Moolenbroek } journal_pos_t;
253*00b67f09SDavid van Moolenbroek
254*00b67f09SDavid van Moolenbroek #define POS_VALID(pos) ((pos).offset != 0)
255*00b67f09SDavid van Moolenbroek #define POS_INVALIDATE(pos) ((pos).offset = 0, (pos).serial = 0)
256*00b67f09SDavid van Moolenbroek
257*00b67f09SDavid van Moolenbroek typedef struct {
258*00b67f09SDavid van Moolenbroek unsigned char format[16];
259*00b67f09SDavid van Moolenbroek journal_pos_t begin;
260*00b67f09SDavid van Moolenbroek journal_pos_t end;
261*00b67f09SDavid van Moolenbroek isc_uint32_t index_size;
262*00b67f09SDavid van Moolenbroek isc_uint32_t sourceserial;
263*00b67f09SDavid van Moolenbroek isc_boolean_t serialset;
264*00b67f09SDavid van Moolenbroek } journal_header_t;
265*00b67f09SDavid van Moolenbroek
266*00b67f09SDavid van Moolenbroek /*%
267*00b67f09SDavid van Moolenbroek * The in-core representation of the transaction header.
268*00b67f09SDavid van Moolenbroek */
269*00b67f09SDavid van Moolenbroek
270*00b67f09SDavid van Moolenbroek typedef struct {
271*00b67f09SDavid van Moolenbroek isc_uint32_t size;
272*00b67f09SDavid van Moolenbroek isc_uint32_t serial0;
273*00b67f09SDavid van Moolenbroek isc_uint32_t serial1;
274*00b67f09SDavid van Moolenbroek } journal_xhdr_t;
275*00b67f09SDavid van Moolenbroek
276*00b67f09SDavid van Moolenbroek /*%
277*00b67f09SDavid van Moolenbroek * The in-core representation of the RR header.
278*00b67f09SDavid van Moolenbroek */
279*00b67f09SDavid van Moolenbroek typedef struct {
280*00b67f09SDavid van Moolenbroek isc_uint32_t size;
281*00b67f09SDavid van Moolenbroek } journal_rrhdr_t;
282*00b67f09SDavid van Moolenbroek
283*00b67f09SDavid van Moolenbroek
284*00b67f09SDavid van Moolenbroek /*%
285*00b67f09SDavid van Moolenbroek * Initial contents to store in the header of a newly created
286*00b67f09SDavid van Moolenbroek * journal file.
287*00b67f09SDavid van Moolenbroek *
288*00b67f09SDavid van Moolenbroek * The header starts with the magic string ";BIND LOG V9\n"
289*00b67f09SDavid van Moolenbroek * to identify the file as a BIND 9 journal file. An ASCII
290*00b67f09SDavid van Moolenbroek * identification string is used rather than a binary magic
291*00b67f09SDavid van Moolenbroek * number to be consistent with BIND 8 (BIND 8 journal files
292*00b67f09SDavid van Moolenbroek * are ASCII text files).
293*00b67f09SDavid van Moolenbroek */
294*00b67f09SDavid van Moolenbroek
295*00b67f09SDavid van Moolenbroek static journal_header_t
296*00b67f09SDavid van Moolenbroek initial_journal_header = { ";BIND LOG V9\n", { 0, 0 }, { 0, 0 }, 0, 0, 0 };
297*00b67f09SDavid van Moolenbroek
298*00b67f09SDavid van Moolenbroek #define JOURNAL_EMPTY(h) ((h)->begin.offset == (h)->end.offset)
299*00b67f09SDavid van Moolenbroek
300*00b67f09SDavid van Moolenbroek typedef enum {
301*00b67f09SDavid van Moolenbroek JOURNAL_STATE_INVALID,
302*00b67f09SDavid van Moolenbroek JOURNAL_STATE_READ,
303*00b67f09SDavid van Moolenbroek JOURNAL_STATE_WRITE,
304*00b67f09SDavid van Moolenbroek JOURNAL_STATE_TRANSACTION,
305*00b67f09SDavid van Moolenbroek JOURNAL_STATE_INLINE
306*00b67f09SDavid van Moolenbroek } journal_state_t;
307*00b67f09SDavid van Moolenbroek
308*00b67f09SDavid van Moolenbroek struct dns_journal {
309*00b67f09SDavid van Moolenbroek unsigned int magic; /*%< JOUR */
310*00b67f09SDavid van Moolenbroek isc_mem_t *mctx; /*%< Memory context */
311*00b67f09SDavid van Moolenbroek journal_state_t state;
312*00b67f09SDavid van Moolenbroek char *filename; /*%< Journal file name */
313*00b67f09SDavid van Moolenbroek FILE * fp; /*%< File handle */
314*00b67f09SDavid van Moolenbroek isc_offset_t offset; /*%< Current file offset */
315*00b67f09SDavid van Moolenbroek journal_header_t header; /*%< In-core journal header */
316*00b67f09SDavid van Moolenbroek unsigned char *rawindex; /*%< In-core buffer for journal index in on-disk format */
317*00b67f09SDavid van Moolenbroek journal_pos_t *index; /*%< In-core journal index */
318*00b67f09SDavid van Moolenbroek
319*00b67f09SDavid van Moolenbroek /*% Current transaction state (when writing). */
320*00b67f09SDavid van Moolenbroek struct {
321*00b67f09SDavid van Moolenbroek unsigned int n_soa; /*%< Number of SOAs seen */
322*00b67f09SDavid van Moolenbroek journal_pos_t pos[2]; /*%< Begin/end position */
323*00b67f09SDavid van Moolenbroek } x;
324*00b67f09SDavid van Moolenbroek
325*00b67f09SDavid van Moolenbroek /*% Iteration state (when reading). */
326*00b67f09SDavid van Moolenbroek struct {
327*00b67f09SDavid van Moolenbroek /* These define the part of the journal we iterate over. */
328*00b67f09SDavid van Moolenbroek journal_pos_t bpos; /*%< Position before first, */
329*00b67f09SDavid van Moolenbroek journal_pos_t epos; /*%< and after last transaction */
330*00b67f09SDavid van Moolenbroek /* The rest is iterator state. */
331*00b67f09SDavid van Moolenbroek isc_uint32_t current_serial; /*%< Current SOA serial */
332*00b67f09SDavid van Moolenbroek isc_buffer_t source; /*%< Data from disk */
333*00b67f09SDavid van Moolenbroek isc_buffer_t target; /*%< Data from _fromwire check */
334*00b67f09SDavid van Moolenbroek dns_decompress_t dctx; /*%< Dummy decompression ctx */
335*00b67f09SDavid van Moolenbroek dns_name_t name; /*%< Current domain name */
336*00b67f09SDavid van Moolenbroek dns_rdata_t rdata; /*%< Current rdata */
337*00b67f09SDavid van Moolenbroek isc_uint32_t ttl; /*%< Current TTL */
338*00b67f09SDavid van Moolenbroek unsigned int xsize; /*%< Size of transaction data */
339*00b67f09SDavid van Moolenbroek unsigned int xpos; /*%< Current position in it */
340*00b67f09SDavid van Moolenbroek isc_result_t result; /*%< Result of last call */
341*00b67f09SDavid van Moolenbroek } it;
342*00b67f09SDavid van Moolenbroek };
343*00b67f09SDavid van Moolenbroek
344*00b67f09SDavid van Moolenbroek #define DNS_JOURNAL_MAGIC ISC_MAGIC('J', 'O', 'U', 'R')
345*00b67f09SDavid van Moolenbroek #define DNS_JOURNAL_VALID(t) ISC_MAGIC_VALID(t, DNS_JOURNAL_MAGIC)
346*00b67f09SDavid van Moolenbroek
347*00b67f09SDavid van Moolenbroek static void
journal_pos_decode(journal_rawpos_t * raw,journal_pos_t * cooked)348*00b67f09SDavid van Moolenbroek journal_pos_decode(journal_rawpos_t *raw, journal_pos_t *cooked) {
349*00b67f09SDavid van Moolenbroek cooked->serial = decode_uint32(raw->serial);
350*00b67f09SDavid van Moolenbroek cooked->offset = decode_uint32(raw->offset);
351*00b67f09SDavid van Moolenbroek }
352*00b67f09SDavid van Moolenbroek
353*00b67f09SDavid van Moolenbroek static void
journal_pos_encode(journal_rawpos_t * raw,journal_pos_t * cooked)354*00b67f09SDavid van Moolenbroek journal_pos_encode(journal_rawpos_t *raw, journal_pos_t *cooked) {
355*00b67f09SDavid van Moolenbroek encode_uint32(cooked->serial, raw->serial);
356*00b67f09SDavid van Moolenbroek encode_uint32(cooked->offset, raw->offset);
357*00b67f09SDavid van Moolenbroek }
358*00b67f09SDavid van Moolenbroek
359*00b67f09SDavid van Moolenbroek static void
journal_header_decode(journal_rawheader_t * raw,journal_header_t * cooked)360*00b67f09SDavid van Moolenbroek journal_header_decode(journal_rawheader_t *raw, journal_header_t *cooked) {
361*00b67f09SDavid van Moolenbroek INSIST(sizeof(cooked->format) == sizeof(raw->h.format));
362*00b67f09SDavid van Moolenbroek memmove(cooked->format, raw->h.format, sizeof(cooked->format));
363*00b67f09SDavid van Moolenbroek journal_pos_decode(&raw->h.begin, &cooked->begin);
364*00b67f09SDavid van Moolenbroek journal_pos_decode(&raw->h.end, &cooked->end);
365*00b67f09SDavid van Moolenbroek cooked->index_size = decode_uint32(raw->h.index_size);
366*00b67f09SDavid van Moolenbroek cooked->sourceserial = decode_uint32(raw->h.sourceserial);
367*00b67f09SDavid van Moolenbroek cooked->serialset = ISC_TF(raw->h.flags & JOURNAL_SERIALSET);
368*00b67f09SDavid van Moolenbroek }
369*00b67f09SDavid van Moolenbroek
370*00b67f09SDavid van Moolenbroek static void
journal_header_encode(journal_header_t * cooked,journal_rawheader_t * raw)371*00b67f09SDavid van Moolenbroek journal_header_encode(journal_header_t *cooked, journal_rawheader_t *raw) {
372*00b67f09SDavid van Moolenbroek unsigned char flags = 0;
373*00b67f09SDavid van Moolenbroek
374*00b67f09SDavid van Moolenbroek INSIST(sizeof(cooked->format) == sizeof(raw->h.format));
375*00b67f09SDavid van Moolenbroek memset(raw->pad, 0, sizeof(raw->pad));
376*00b67f09SDavid van Moolenbroek memmove(raw->h.format, cooked->format, sizeof(raw->h.format));
377*00b67f09SDavid van Moolenbroek journal_pos_encode(&raw->h.begin, &cooked->begin);
378*00b67f09SDavid van Moolenbroek journal_pos_encode(&raw->h.end, &cooked->end);
379*00b67f09SDavid van Moolenbroek encode_uint32(cooked->index_size, raw->h.index_size);
380*00b67f09SDavid van Moolenbroek encode_uint32(cooked->sourceserial, raw->h.sourceserial);
381*00b67f09SDavid van Moolenbroek if (cooked->serialset)
382*00b67f09SDavid van Moolenbroek flags |= JOURNAL_SERIALSET;
383*00b67f09SDavid van Moolenbroek raw->h.flags = flags;
384*00b67f09SDavid van Moolenbroek }
385*00b67f09SDavid van Moolenbroek
386*00b67f09SDavid van Moolenbroek /*
387*00b67f09SDavid van Moolenbroek * Journal file I/O subroutines, with error checking and reporting.
388*00b67f09SDavid van Moolenbroek */
389*00b67f09SDavid van Moolenbroek static isc_result_t
journal_seek(dns_journal_t * j,isc_uint32_t offset)390*00b67f09SDavid van Moolenbroek journal_seek(dns_journal_t *j, isc_uint32_t offset) {
391*00b67f09SDavid van Moolenbroek isc_result_t result;
392*00b67f09SDavid van Moolenbroek
393*00b67f09SDavid van Moolenbroek result = isc_stdio_seek(j->fp, (off_t)offset, SEEK_SET);
394*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
395*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
396*00b67f09SDavid van Moolenbroek "%s: seek: %s", j->filename,
397*00b67f09SDavid van Moolenbroek isc_result_totext(result));
398*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
399*00b67f09SDavid van Moolenbroek }
400*00b67f09SDavid van Moolenbroek j->offset = offset;
401*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
402*00b67f09SDavid van Moolenbroek }
403*00b67f09SDavid van Moolenbroek
404*00b67f09SDavid van Moolenbroek static isc_result_t
journal_read(dns_journal_t * j,void * mem,size_t nbytes)405*00b67f09SDavid van Moolenbroek journal_read(dns_journal_t *j, void *mem, size_t nbytes) {
406*00b67f09SDavid van Moolenbroek isc_result_t result;
407*00b67f09SDavid van Moolenbroek
408*00b67f09SDavid van Moolenbroek result = isc_stdio_read(mem, 1, nbytes, j->fp, NULL);
409*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
410*00b67f09SDavid van Moolenbroek if (result == ISC_R_EOF)
411*00b67f09SDavid van Moolenbroek return (ISC_R_NOMORE);
412*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
413*00b67f09SDavid van Moolenbroek "%s: read: %s",
414*00b67f09SDavid van Moolenbroek j->filename, isc_result_totext(result));
415*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
416*00b67f09SDavid van Moolenbroek }
417*00b67f09SDavid van Moolenbroek j->offset += (isc_offset_t)nbytes;
418*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
419*00b67f09SDavid van Moolenbroek }
420*00b67f09SDavid van Moolenbroek
421*00b67f09SDavid van Moolenbroek static isc_result_t
journal_write(dns_journal_t * j,void * mem,size_t nbytes)422*00b67f09SDavid van Moolenbroek journal_write(dns_journal_t *j, void *mem, size_t nbytes) {
423*00b67f09SDavid van Moolenbroek isc_result_t result;
424*00b67f09SDavid van Moolenbroek
425*00b67f09SDavid van Moolenbroek result = isc_stdio_write(mem, 1, nbytes, j->fp, NULL);
426*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
427*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
428*00b67f09SDavid van Moolenbroek "%s: write: %s",
429*00b67f09SDavid van Moolenbroek j->filename, isc_result_totext(result));
430*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
431*00b67f09SDavid van Moolenbroek }
432*00b67f09SDavid van Moolenbroek j->offset += (isc_offset_t)nbytes;
433*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
434*00b67f09SDavid van Moolenbroek }
435*00b67f09SDavid van Moolenbroek
436*00b67f09SDavid van Moolenbroek static isc_result_t
journal_fsync(dns_journal_t * j)437*00b67f09SDavid van Moolenbroek journal_fsync(dns_journal_t *j) {
438*00b67f09SDavid van Moolenbroek isc_result_t result;
439*00b67f09SDavid van Moolenbroek result = isc_stdio_flush(j->fp);
440*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
441*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
442*00b67f09SDavid van Moolenbroek "%s: flush: %s",
443*00b67f09SDavid van Moolenbroek j->filename, isc_result_totext(result));
444*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
445*00b67f09SDavid van Moolenbroek }
446*00b67f09SDavid van Moolenbroek result = isc_stdio_sync(j->fp);
447*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
448*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
449*00b67f09SDavid van Moolenbroek "%s: fsync: %s",
450*00b67f09SDavid van Moolenbroek j->filename, isc_result_totext(result));
451*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
452*00b67f09SDavid van Moolenbroek }
453*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
454*00b67f09SDavid van Moolenbroek }
455*00b67f09SDavid van Moolenbroek
456*00b67f09SDavid van Moolenbroek /*
457*00b67f09SDavid van Moolenbroek * Read/write a transaction header at the current file position.
458*00b67f09SDavid van Moolenbroek */
459*00b67f09SDavid van Moolenbroek
460*00b67f09SDavid van Moolenbroek static isc_result_t
journal_read_xhdr(dns_journal_t * j,journal_xhdr_t * xhdr)461*00b67f09SDavid van Moolenbroek journal_read_xhdr(dns_journal_t *j, journal_xhdr_t *xhdr) {
462*00b67f09SDavid van Moolenbroek journal_rawxhdr_t raw;
463*00b67f09SDavid van Moolenbroek isc_result_t result;
464*00b67f09SDavid van Moolenbroek result = journal_read(j, &raw, sizeof(raw));
465*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
466*00b67f09SDavid van Moolenbroek return (result);
467*00b67f09SDavid van Moolenbroek xhdr->size = decode_uint32(raw.size);
468*00b67f09SDavid van Moolenbroek xhdr->serial0 = decode_uint32(raw.serial0);
469*00b67f09SDavid van Moolenbroek xhdr->serial1 = decode_uint32(raw.serial1);
470*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
471*00b67f09SDavid van Moolenbroek }
472*00b67f09SDavid van Moolenbroek
473*00b67f09SDavid van Moolenbroek static isc_result_t
journal_write_xhdr(dns_journal_t * j,isc_uint32_t size,isc_uint32_t serial0,isc_uint32_t serial1)474*00b67f09SDavid van Moolenbroek journal_write_xhdr(dns_journal_t *j, isc_uint32_t size,
475*00b67f09SDavid van Moolenbroek isc_uint32_t serial0, isc_uint32_t serial1)
476*00b67f09SDavid van Moolenbroek {
477*00b67f09SDavid van Moolenbroek journal_rawxhdr_t raw;
478*00b67f09SDavid van Moolenbroek encode_uint32(size, raw.size);
479*00b67f09SDavid van Moolenbroek encode_uint32(serial0, raw.serial0);
480*00b67f09SDavid van Moolenbroek encode_uint32(serial1, raw.serial1);
481*00b67f09SDavid van Moolenbroek return (journal_write(j, &raw, sizeof(raw)));
482*00b67f09SDavid van Moolenbroek }
483*00b67f09SDavid van Moolenbroek
484*00b67f09SDavid van Moolenbroek
485*00b67f09SDavid van Moolenbroek /*
486*00b67f09SDavid van Moolenbroek * Read an RR header at the current file position.
487*00b67f09SDavid van Moolenbroek */
488*00b67f09SDavid van Moolenbroek
489*00b67f09SDavid van Moolenbroek static isc_result_t
journal_read_rrhdr(dns_journal_t * j,journal_rrhdr_t * rrhdr)490*00b67f09SDavid van Moolenbroek journal_read_rrhdr(dns_journal_t *j, journal_rrhdr_t *rrhdr) {
491*00b67f09SDavid van Moolenbroek journal_rawrrhdr_t raw;
492*00b67f09SDavid van Moolenbroek isc_result_t result;
493*00b67f09SDavid van Moolenbroek result = journal_read(j, &raw, sizeof(raw));
494*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
495*00b67f09SDavid van Moolenbroek return (result);
496*00b67f09SDavid van Moolenbroek rrhdr->size = decode_uint32(raw.size);
497*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
498*00b67f09SDavid van Moolenbroek }
499*00b67f09SDavid van Moolenbroek
500*00b67f09SDavid van Moolenbroek static isc_result_t
journal_file_create(isc_mem_t * mctx,const char * filename)501*00b67f09SDavid van Moolenbroek journal_file_create(isc_mem_t *mctx, const char *filename) {
502*00b67f09SDavid van Moolenbroek FILE *fp = NULL;
503*00b67f09SDavid van Moolenbroek isc_result_t result;
504*00b67f09SDavid van Moolenbroek journal_header_t header;
505*00b67f09SDavid van Moolenbroek journal_rawheader_t rawheader;
506*00b67f09SDavid van Moolenbroek int index_size = 56; /* XXX configurable */
507*00b67f09SDavid van Moolenbroek int size;
508*00b67f09SDavid van Moolenbroek void *mem; /* Memory for temporary index image. */
509*00b67f09SDavid van Moolenbroek
510*00b67f09SDavid van Moolenbroek INSIST(sizeof(journal_rawheader_t) == JOURNAL_HEADER_SIZE);
511*00b67f09SDavid van Moolenbroek
512*00b67f09SDavid van Moolenbroek result = isc_stdio_open(filename, "wb", &fp);
513*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
514*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
515*00b67f09SDavid van Moolenbroek "%s: create: %s",
516*00b67f09SDavid van Moolenbroek filename, isc_result_totext(result));
517*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
518*00b67f09SDavid van Moolenbroek }
519*00b67f09SDavid van Moolenbroek
520*00b67f09SDavid van Moolenbroek header = initial_journal_header;
521*00b67f09SDavid van Moolenbroek header.index_size = index_size;
522*00b67f09SDavid van Moolenbroek journal_header_encode(&header, &rawheader);
523*00b67f09SDavid van Moolenbroek
524*00b67f09SDavid van Moolenbroek size = sizeof(journal_rawheader_t) +
525*00b67f09SDavid van Moolenbroek index_size * sizeof(journal_rawpos_t);
526*00b67f09SDavid van Moolenbroek
527*00b67f09SDavid van Moolenbroek mem = isc_mem_get(mctx, size);
528*00b67f09SDavid van Moolenbroek if (mem == NULL) {
529*00b67f09SDavid van Moolenbroek (void)isc_stdio_close(fp);
530*00b67f09SDavid van Moolenbroek (void)isc_file_remove(filename);
531*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
532*00b67f09SDavid van Moolenbroek }
533*00b67f09SDavid van Moolenbroek memset(mem, 0, size);
534*00b67f09SDavid van Moolenbroek memmove(mem, &rawheader, sizeof(rawheader));
535*00b67f09SDavid van Moolenbroek
536*00b67f09SDavid van Moolenbroek result = isc_stdio_write(mem, 1, (size_t) size, fp, NULL);
537*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
538*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
539*00b67f09SDavid van Moolenbroek "%s: write: %s",
540*00b67f09SDavid van Moolenbroek filename, isc_result_totext(result));
541*00b67f09SDavid van Moolenbroek (void)isc_stdio_close(fp);
542*00b67f09SDavid van Moolenbroek (void)isc_file_remove(filename);
543*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, mem, size);
544*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
545*00b67f09SDavid van Moolenbroek }
546*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, mem, size);
547*00b67f09SDavid van Moolenbroek
548*00b67f09SDavid van Moolenbroek result = isc_stdio_close(fp);
549*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
550*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
551*00b67f09SDavid van Moolenbroek "%s: close: %s",
552*00b67f09SDavid van Moolenbroek filename, isc_result_totext(result));
553*00b67f09SDavid van Moolenbroek (void)isc_file_remove(filename);
554*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
555*00b67f09SDavid van Moolenbroek }
556*00b67f09SDavid van Moolenbroek
557*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
558*00b67f09SDavid van Moolenbroek }
559*00b67f09SDavid van Moolenbroek
560*00b67f09SDavid van Moolenbroek 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)561*00b67f09SDavid van Moolenbroek journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
562*00b67f09SDavid van Moolenbroek isc_boolean_t create, dns_journal_t **journalp)
563*00b67f09SDavid van Moolenbroek {
564*00b67f09SDavid van Moolenbroek FILE *fp = NULL;
565*00b67f09SDavid van Moolenbroek isc_result_t result;
566*00b67f09SDavid van Moolenbroek journal_rawheader_t rawheader;
567*00b67f09SDavid van Moolenbroek dns_journal_t *j;
568*00b67f09SDavid van Moolenbroek
569*00b67f09SDavid van Moolenbroek INSIST(journalp != NULL && *journalp == NULL);
570*00b67f09SDavid van Moolenbroek j = isc_mem_get(mctx, sizeof(*j));
571*00b67f09SDavid van Moolenbroek if (j == NULL)
572*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
573*00b67f09SDavid van Moolenbroek
574*00b67f09SDavid van Moolenbroek j->mctx = NULL;
575*00b67f09SDavid van Moolenbroek isc_mem_attach(mctx, &j->mctx);
576*00b67f09SDavid van Moolenbroek j->state = JOURNAL_STATE_INVALID;
577*00b67f09SDavid van Moolenbroek j->fp = NULL;
578*00b67f09SDavid van Moolenbroek j->filename = isc_mem_strdup(mctx, filename);
579*00b67f09SDavid van Moolenbroek j->index = NULL;
580*00b67f09SDavid van Moolenbroek j->rawindex = NULL;
581*00b67f09SDavid van Moolenbroek
582*00b67f09SDavid van Moolenbroek if (j->filename == NULL)
583*00b67f09SDavid van Moolenbroek FAIL(ISC_R_NOMEMORY);
584*00b67f09SDavid van Moolenbroek
585*00b67f09SDavid van Moolenbroek result = isc_stdio_open(j->filename, write ? "rb+" : "rb", &fp);
586*00b67f09SDavid van Moolenbroek
587*00b67f09SDavid van Moolenbroek if (result == ISC_R_FILENOTFOUND) {
588*00b67f09SDavid van Moolenbroek if (create) {
589*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_DEBUG(1),
590*00b67f09SDavid van Moolenbroek "journal file %s does not exist, "
591*00b67f09SDavid van Moolenbroek "creating it", j->filename);
592*00b67f09SDavid van Moolenbroek CHECK(journal_file_create(mctx, filename));
593*00b67f09SDavid van Moolenbroek /*
594*00b67f09SDavid van Moolenbroek * Retry.
595*00b67f09SDavid van Moolenbroek */
596*00b67f09SDavid van Moolenbroek result = isc_stdio_open(j->filename, "rb+", &fp);
597*00b67f09SDavid van Moolenbroek } else {
598*00b67f09SDavid van Moolenbroek FAIL(ISC_R_NOTFOUND);
599*00b67f09SDavid van Moolenbroek }
600*00b67f09SDavid van Moolenbroek }
601*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
602*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
603*00b67f09SDavid van Moolenbroek "%s: open: %s",
604*00b67f09SDavid van Moolenbroek j->filename, isc_result_totext(result));
605*00b67f09SDavid van Moolenbroek FAIL(ISC_R_UNEXPECTED);
606*00b67f09SDavid van Moolenbroek }
607*00b67f09SDavid van Moolenbroek
608*00b67f09SDavid van Moolenbroek j->fp = fp;
609*00b67f09SDavid van Moolenbroek
610*00b67f09SDavid van Moolenbroek /*
611*00b67f09SDavid van Moolenbroek * Set magic early so that seek/read can succeed.
612*00b67f09SDavid van Moolenbroek */
613*00b67f09SDavid van Moolenbroek j->magic = DNS_JOURNAL_MAGIC;
614*00b67f09SDavid van Moolenbroek
615*00b67f09SDavid van Moolenbroek CHECK(journal_seek(j, 0));
616*00b67f09SDavid van Moolenbroek CHECK(journal_read(j, &rawheader, sizeof(rawheader)));
617*00b67f09SDavid van Moolenbroek
618*00b67f09SDavid van Moolenbroek if (memcmp(rawheader.h.format, initial_journal_header.format,
619*00b67f09SDavid van Moolenbroek sizeof(initial_journal_header.format)) != 0) {
620*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
621*00b67f09SDavid van Moolenbroek "%s: journal format not recognized",
622*00b67f09SDavid van Moolenbroek j->filename);
623*00b67f09SDavid van Moolenbroek FAIL(ISC_R_UNEXPECTED);
624*00b67f09SDavid van Moolenbroek }
625*00b67f09SDavid van Moolenbroek journal_header_decode(&rawheader, &j->header);
626*00b67f09SDavid van Moolenbroek
627*00b67f09SDavid van Moolenbroek /*
628*00b67f09SDavid van Moolenbroek * If there is an index, read the raw index into a dynamically
629*00b67f09SDavid van Moolenbroek * allocated buffer and then convert it into a cooked index.
630*00b67f09SDavid van Moolenbroek */
631*00b67f09SDavid van Moolenbroek if (j->header.index_size != 0) {
632*00b67f09SDavid van Moolenbroek unsigned int i;
633*00b67f09SDavid van Moolenbroek unsigned int rawbytes;
634*00b67f09SDavid van Moolenbroek unsigned char *p;
635*00b67f09SDavid van Moolenbroek
636*00b67f09SDavid van Moolenbroek rawbytes = j->header.index_size * sizeof(journal_rawpos_t);
637*00b67f09SDavid van Moolenbroek j->rawindex = isc_mem_get(mctx, rawbytes);
638*00b67f09SDavid van Moolenbroek if (j->rawindex == NULL)
639*00b67f09SDavid van Moolenbroek FAIL(ISC_R_NOMEMORY);
640*00b67f09SDavid van Moolenbroek
641*00b67f09SDavid van Moolenbroek CHECK(journal_read(j, j->rawindex, rawbytes));
642*00b67f09SDavid van Moolenbroek
643*00b67f09SDavid van Moolenbroek j->index = isc_mem_get(mctx, j->header.index_size *
644*00b67f09SDavid van Moolenbroek sizeof(journal_pos_t));
645*00b67f09SDavid van Moolenbroek if (j->index == NULL)
646*00b67f09SDavid van Moolenbroek FAIL(ISC_R_NOMEMORY);
647*00b67f09SDavid van Moolenbroek
648*00b67f09SDavid van Moolenbroek p = j->rawindex;
649*00b67f09SDavid van Moolenbroek for (i = 0; i < j->header.index_size; i++) {
650*00b67f09SDavid van Moolenbroek j->index[i].serial = decode_uint32(p);
651*00b67f09SDavid van Moolenbroek p += 4;
652*00b67f09SDavid van Moolenbroek j->index[i].offset = decode_uint32(p);
653*00b67f09SDavid van Moolenbroek p += 4;
654*00b67f09SDavid van Moolenbroek }
655*00b67f09SDavid van Moolenbroek INSIST(p == j->rawindex + rawbytes);
656*00b67f09SDavid van Moolenbroek }
657*00b67f09SDavid van Moolenbroek j->offset = -1; /* Invalid, must seek explicitly. */
658*00b67f09SDavid van Moolenbroek
659*00b67f09SDavid van Moolenbroek /*
660*00b67f09SDavid van Moolenbroek * Initialize the iterator.
661*00b67f09SDavid van Moolenbroek */
662*00b67f09SDavid van Moolenbroek dns_name_init(&j->it.name, NULL);
663*00b67f09SDavid van Moolenbroek dns_rdata_init(&j->it.rdata);
664*00b67f09SDavid van Moolenbroek
665*00b67f09SDavid van Moolenbroek /*
666*00b67f09SDavid van Moolenbroek * Set up empty initial buffers for unchecked and checked
667*00b67f09SDavid van Moolenbroek * wire format RR data. They will be reallocated
668*00b67f09SDavid van Moolenbroek * later.
669*00b67f09SDavid van Moolenbroek */
670*00b67f09SDavid van Moolenbroek isc_buffer_init(&j->it.source, NULL, 0);
671*00b67f09SDavid van Moolenbroek isc_buffer_init(&j->it.target, NULL, 0);
672*00b67f09SDavid van Moolenbroek dns_decompress_init(&j->it.dctx, -1, DNS_DECOMPRESS_NONE);
673*00b67f09SDavid van Moolenbroek
674*00b67f09SDavid van Moolenbroek j->state =
675*00b67f09SDavid van Moolenbroek write ? JOURNAL_STATE_WRITE : JOURNAL_STATE_READ;
676*00b67f09SDavid van Moolenbroek
677*00b67f09SDavid van Moolenbroek *journalp = j;
678*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
679*00b67f09SDavid van Moolenbroek
680*00b67f09SDavid van Moolenbroek failure:
681*00b67f09SDavid van Moolenbroek j->magic = 0;
682*00b67f09SDavid van Moolenbroek if (j->index != NULL) {
683*00b67f09SDavid van Moolenbroek isc_mem_put(j->mctx, j->index, j->header.index_size *
684*00b67f09SDavid van Moolenbroek sizeof(journal_rawpos_t));
685*00b67f09SDavid van Moolenbroek j->index = NULL;
686*00b67f09SDavid van Moolenbroek }
687*00b67f09SDavid van Moolenbroek if (j->filename != NULL)
688*00b67f09SDavid van Moolenbroek isc_mem_free(j->mctx, j->filename);
689*00b67f09SDavid van Moolenbroek if (j->fp != NULL)
690*00b67f09SDavid van Moolenbroek (void)isc_stdio_close(j->fp);
691*00b67f09SDavid van Moolenbroek isc_mem_putanddetach(&j->mctx, j, sizeof(*j));
692*00b67f09SDavid van Moolenbroek return (result);
693*00b67f09SDavid van Moolenbroek }
694*00b67f09SDavid van Moolenbroek
695*00b67f09SDavid van Moolenbroek isc_result_t
dns_journal_open(isc_mem_t * mctx,const char * filename,unsigned int mode,dns_journal_t ** journalp)696*00b67f09SDavid van Moolenbroek dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode,
697*00b67f09SDavid van Moolenbroek dns_journal_t **journalp)
698*00b67f09SDavid van Moolenbroek {
699*00b67f09SDavid van Moolenbroek isc_result_t result;
700*00b67f09SDavid van Moolenbroek size_t namelen;
701*00b67f09SDavid van Moolenbroek char backup[1024];
702*00b67f09SDavid van Moolenbroek isc_boolean_t write, create;
703*00b67f09SDavid van Moolenbroek
704*00b67f09SDavid van Moolenbroek create = ISC_TF(mode & DNS_JOURNAL_CREATE);
705*00b67f09SDavid van Moolenbroek write = ISC_TF(mode & (DNS_JOURNAL_WRITE|DNS_JOURNAL_CREATE));
706*00b67f09SDavid van Moolenbroek
707*00b67f09SDavid van Moolenbroek result = journal_open(mctx, filename, write, create, journalp);
708*00b67f09SDavid van Moolenbroek if (result == ISC_R_NOTFOUND) {
709*00b67f09SDavid van Moolenbroek namelen = strlen(filename);
710*00b67f09SDavid van Moolenbroek if (namelen > 4U && strcmp(filename + namelen - 4, ".jnl") == 0)
711*00b67f09SDavid van Moolenbroek namelen -= 4;
712*00b67f09SDavid van Moolenbroek
713*00b67f09SDavid van Moolenbroek result = isc_string_printf(backup, sizeof(backup), "%.*s.jbk",
714*00b67f09SDavid van Moolenbroek (int)namelen, filename);
715*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
716*00b67f09SDavid van Moolenbroek return (result);
717*00b67f09SDavid van Moolenbroek result = journal_open(mctx, backup, write, write, journalp);
718*00b67f09SDavid van Moolenbroek }
719*00b67f09SDavid van Moolenbroek return (result);
720*00b67f09SDavid van Moolenbroek }
721*00b67f09SDavid van Moolenbroek
722*00b67f09SDavid van Moolenbroek /*
723*00b67f09SDavid van Moolenbroek * A comparison function defining the sorting order for
724*00b67f09SDavid van Moolenbroek * entries in the IXFR-style journal file.
725*00b67f09SDavid van Moolenbroek *
726*00b67f09SDavid van Moolenbroek * The IXFR format requires that deletions are sorted before
727*00b67f09SDavid van Moolenbroek * additions, and within either one, SOA records are sorted
728*00b67f09SDavid van Moolenbroek * before others.
729*00b67f09SDavid van Moolenbroek *
730*00b67f09SDavid van Moolenbroek * Also sort the non-SOA records by type as a courtesy to the
731*00b67f09SDavid van Moolenbroek * server receiving the IXFR - it may help reduce the amount of
732*00b67f09SDavid van Moolenbroek * rdataset merging it has to do.
733*00b67f09SDavid van Moolenbroek */
734*00b67f09SDavid van Moolenbroek static int
ixfr_order(const void * av,const void * bv)735*00b67f09SDavid van Moolenbroek ixfr_order(const void *av, const void *bv) {
736*00b67f09SDavid van Moolenbroek dns_difftuple_t const * const *ap = av;
737*00b67f09SDavid van Moolenbroek dns_difftuple_t const * const *bp = bv;
738*00b67f09SDavid van Moolenbroek dns_difftuple_t const *a = *ap;
739*00b67f09SDavid van Moolenbroek dns_difftuple_t const *b = *bp;
740*00b67f09SDavid van Moolenbroek int r;
741*00b67f09SDavid van Moolenbroek int bop = 0, aop = 0;
742*00b67f09SDavid van Moolenbroek
743*00b67f09SDavid van Moolenbroek switch (a->op) {
744*00b67f09SDavid van Moolenbroek case DNS_DIFFOP_DEL:
745*00b67f09SDavid van Moolenbroek case DNS_DIFFOP_DELRESIGN:
746*00b67f09SDavid van Moolenbroek aop = 1;
747*00b67f09SDavid van Moolenbroek break;
748*00b67f09SDavid van Moolenbroek case DNS_DIFFOP_ADD:
749*00b67f09SDavid van Moolenbroek case DNS_DIFFOP_ADDRESIGN:
750*00b67f09SDavid van Moolenbroek aop = 0;
751*00b67f09SDavid van Moolenbroek break;
752*00b67f09SDavid van Moolenbroek default:
753*00b67f09SDavid van Moolenbroek INSIST(0);
754*00b67f09SDavid van Moolenbroek }
755*00b67f09SDavid van Moolenbroek
756*00b67f09SDavid van Moolenbroek switch (b->op) {
757*00b67f09SDavid van Moolenbroek case DNS_DIFFOP_DEL:
758*00b67f09SDavid van Moolenbroek case DNS_DIFFOP_DELRESIGN:
759*00b67f09SDavid van Moolenbroek bop = 1;
760*00b67f09SDavid van Moolenbroek break;
761*00b67f09SDavid van Moolenbroek case DNS_DIFFOP_ADD:
762*00b67f09SDavid van Moolenbroek case DNS_DIFFOP_ADDRESIGN:
763*00b67f09SDavid van Moolenbroek bop = 0;
764*00b67f09SDavid van Moolenbroek break;
765*00b67f09SDavid van Moolenbroek default:
766*00b67f09SDavid van Moolenbroek INSIST(0);
767*00b67f09SDavid van Moolenbroek }
768*00b67f09SDavid van Moolenbroek
769*00b67f09SDavid van Moolenbroek r = bop - aop;
770*00b67f09SDavid van Moolenbroek if (r != 0)
771*00b67f09SDavid van Moolenbroek return (r);
772*00b67f09SDavid van Moolenbroek
773*00b67f09SDavid van Moolenbroek r = (b->rdata.type == dns_rdatatype_soa) -
774*00b67f09SDavid van Moolenbroek (a->rdata.type == dns_rdatatype_soa);
775*00b67f09SDavid van Moolenbroek if (r != 0)
776*00b67f09SDavid van Moolenbroek return (r);
777*00b67f09SDavid van Moolenbroek
778*00b67f09SDavid van Moolenbroek r = (a->rdata.type - b->rdata.type);
779*00b67f09SDavid van Moolenbroek return (r);
780*00b67f09SDavid van Moolenbroek }
781*00b67f09SDavid van Moolenbroek
782*00b67f09SDavid van Moolenbroek /*
783*00b67f09SDavid van Moolenbroek * Advance '*pos' to the next journal transaction.
784*00b67f09SDavid van Moolenbroek *
785*00b67f09SDavid van Moolenbroek * Requires:
786*00b67f09SDavid van Moolenbroek * *pos refers to a valid journal transaction.
787*00b67f09SDavid van Moolenbroek *
788*00b67f09SDavid van Moolenbroek * Ensures:
789*00b67f09SDavid van Moolenbroek * When ISC_R_SUCCESS is returned,
790*00b67f09SDavid van Moolenbroek * *pos refers to the next journal transaction.
791*00b67f09SDavid van Moolenbroek *
792*00b67f09SDavid van Moolenbroek * Returns one of:
793*00b67f09SDavid van Moolenbroek *
794*00b67f09SDavid van Moolenbroek * ISC_R_SUCCESS
795*00b67f09SDavid van Moolenbroek * ISC_R_NOMORE *pos pointed at the last transaction
796*00b67f09SDavid van Moolenbroek * Other results due to file errors are possible.
797*00b67f09SDavid van Moolenbroek */
798*00b67f09SDavid van Moolenbroek static isc_result_t
journal_next(dns_journal_t * j,journal_pos_t * pos)799*00b67f09SDavid van Moolenbroek journal_next(dns_journal_t *j, journal_pos_t *pos) {
800*00b67f09SDavid van Moolenbroek isc_result_t result;
801*00b67f09SDavid van Moolenbroek journal_xhdr_t xhdr;
802*00b67f09SDavid van Moolenbroek REQUIRE(DNS_JOURNAL_VALID(j));
803*00b67f09SDavid van Moolenbroek
804*00b67f09SDavid van Moolenbroek result = journal_seek(j, pos->offset);
805*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
806*00b67f09SDavid van Moolenbroek return (result);
807*00b67f09SDavid van Moolenbroek
808*00b67f09SDavid van Moolenbroek if (pos->serial == j->header.end.serial)
809*00b67f09SDavid van Moolenbroek return (ISC_R_NOMORE);
810*00b67f09SDavid van Moolenbroek /*
811*00b67f09SDavid van Moolenbroek * Read the header of the current transaction.
812*00b67f09SDavid van Moolenbroek * This will return ISC_R_NOMORE if we are at EOF.
813*00b67f09SDavid van Moolenbroek */
814*00b67f09SDavid van Moolenbroek result = journal_read_xhdr(j, &xhdr);
815*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
816*00b67f09SDavid van Moolenbroek return (result);
817*00b67f09SDavid van Moolenbroek
818*00b67f09SDavid van Moolenbroek /*
819*00b67f09SDavid van Moolenbroek * Check serial number consistency.
820*00b67f09SDavid van Moolenbroek */
821*00b67f09SDavid van Moolenbroek if (xhdr.serial0 != pos->serial) {
822*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
823*00b67f09SDavid van Moolenbroek "%s: journal file corrupt: "
824*00b67f09SDavid van Moolenbroek "expected serial %u, got %u",
825*00b67f09SDavid van Moolenbroek j->filename, pos->serial, xhdr.serial0);
826*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
827*00b67f09SDavid van Moolenbroek }
828*00b67f09SDavid van Moolenbroek
829*00b67f09SDavid van Moolenbroek /*
830*00b67f09SDavid van Moolenbroek * Check for offset wraparound.
831*00b67f09SDavid van Moolenbroek */
832*00b67f09SDavid van Moolenbroek if ((isc_offset_t)(pos->offset + sizeof(journal_rawxhdr_t) + xhdr.size)
833*00b67f09SDavid van Moolenbroek < pos->offset) {
834*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
835*00b67f09SDavid van Moolenbroek "%s: offset too large", j->filename);
836*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
837*00b67f09SDavid van Moolenbroek }
838*00b67f09SDavid van Moolenbroek
839*00b67f09SDavid van Moolenbroek pos->offset += sizeof(journal_rawxhdr_t) + xhdr.size;
840*00b67f09SDavid van Moolenbroek pos->serial = xhdr.serial1;
841*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
842*00b67f09SDavid van Moolenbroek }
843*00b67f09SDavid van Moolenbroek
844*00b67f09SDavid van Moolenbroek /*
845*00b67f09SDavid van Moolenbroek * If the index of the journal 'j' contains an entry "better"
846*00b67f09SDavid van Moolenbroek * than '*best_guess', replace '*best_guess' with it.
847*00b67f09SDavid van Moolenbroek *
848*00b67f09SDavid van Moolenbroek * "Better" means having a serial number closer to 'serial'
849*00b67f09SDavid van Moolenbroek * but not greater than 'serial'.
850*00b67f09SDavid van Moolenbroek */
851*00b67f09SDavid van Moolenbroek static void
index_find(dns_journal_t * j,isc_uint32_t serial,journal_pos_t * best_guess)852*00b67f09SDavid van Moolenbroek index_find(dns_journal_t *j, isc_uint32_t serial, journal_pos_t *best_guess) {
853*00b67f09SDavid van Moolenbroek unsigned int i;
854*00b67f09SDavid van Moolenbroek if (j->index == NULL)
855*00b67f09SDavid van Moolenbroek return;
856*00b67f09SDavid van Moolenbroek for (i = 0; i < j->header.index_size; i++) {
857*00b67f09SDavid van Moolenbroek if (POS_VALID(j->index[i]) &&
858*00b67f09SDavid van Moolenbroek DNS_SERIAL_GE(serial, j->index[i].serial) &&
859*00b67f09SDavid van Moolenbroek DNS_SERIAL_GT(j->index[i].serial, best_guess->serial))
860*00b67f09SDavid van Moolenbroek *best_guess = j->index[i];
861*00b67f09SDavid van Moolenbroek }
862*00b67f09SDavid van Moolenbroek }
863*00b67f09SDavid van Moolenbroek
864*00b67f09SDavid van Moolenbroek /*
865*00b67f09SDavid van Moolenbroek * Add a new index entry. If there is no room, make room by removing
866*00b67f09SDavid van Moolenbroek * the odd-numbered entries and compacting the others into the first
867*00b67f09SDavid van Moolenbroek * half of the index. This decimates old index entries exponentially
868*00b67f09SDavid van Moolenbroek * over time, so that the index always contains a much larger fraction
869*00b67f09SDavid van Moolenbroek * of recent serial numbers than of old ones. This is deliberate -
870*00b67f09SDavid van Moolenbroek * most index searches are for outgoing IXFR, and IXFR tends to request
871*00b67f09SDavid van Moolenbroek * recent versions more often than old ones.
872*00b67f09SDavid van Moolenbroek */
873*00b67f09SDavid van Moolenbroek static void
index_add(dns_journal_t * j,journal_pos_t * pos)874*00b67f09SDavid van Moolenbroek index_add(dns_journal_t *j, journal_pos_t *pos) {
875*00b67f09SDavid van Moolenbroek unsigned int i;
876*00b67f09SDavid van Moolenbroek if (j->index == NULL)
877*00b67f09SDavid van Moolenbroek return;
878*00b67f09SDavid van Moolenbroek /*
879*00b67f09SDavid van Moolenbroek * Search for a vacant position.
880*00b67f09SDavid van Moolenbroek */
881*00b67f09SDavid van Moolenbroek for (i = 0; i < j->header.index_size; i++) {
882*00b67f09SDavid van Moolenbroek if (! POS_VALID(j->index[i]))
883*00b67f09SDavid van Moolenbroek break;
884*00b67f09SDavid van Moolenbroek }
885*00b67f09SDavid van Moolenbroek if (i == j->header.index_size) {
886*00b67f09SDavid van Moolenbroek unsigned int k = 0;
887*00b67f09SDavid van Moolenbroek /*
888*00b67f09SDavid van Moolenbroek * Found no vacant position. Make some room.
889*00b67f09SDavid van Moolenbroek */
890*00b67f09SDavid van Moolenbroek for (i = 0; i < j->header.index_size; i += 2) {
891*00b67f09SDavid van Moolenbroek j->index[k++] = j->index[i];
892*00b67f09SDavid van Moolenbroek }
893*00b67f09SDavid van Moolenbroek i = k; /* 'i' identifies the first vacant position. */
894*00b67f09SDavid van Moolenbroek while (k < j->header.index_size) {
895*00b67f09SDavid van Moolenbroek POS_INVALIDATE(j->index[k]);
896*00b67f09SDavid van Moolenbroek k++;
897*00b67f09SDavid van Moolenbroek }
898*00b67f09SDavid van Moolenbroek }
899*00b67f09SDavid van Moolenbroek INSIST(i < j->header.index_size);
900*00b67f09SDavid van Moolenbroek INSIST(! POS_VALID(j->index[i]));
901*00b67f09SDavid van Moolenbroek
902*00b67f09SDavid van Moolenbroek /*
903*00b67f09SDavid van Moolenbroek * Store the new index entry.
904*00b67f09SDavid van Moolenbroek */
905*00b67f09SDavid van Moolenbroek j->index[i] = *pos;
906*00b67f09SDavid van Moolenbroek }
907*00b67f09SDavid van Moolenbroek
908*00b67f09SDavid van Moolenbroek /*
909*00b67f09SDavid van Moolenbroek * Invalidate any existing index entries that could become
910*00b67f09SDavid van Moolenbroek * ambiguous when a new transaction with number 'serial' is added.
911*00b67f09SDavid van Moolenbroek */
912*00b67f09SDavid van Moolenbroek static void
index_invalidate(dns_journal_t * j,isc_uint32_t serial)913*00b67f09SDavid van Moolenbroek index_invalidate(dns_journal_t *j, isc_uint32_t serial) {
914*00b67f09SDavid van Moolenbroek unsigned int i;
915*00b67f09SDavid van Moolenbroek if (j->index == NULL)
916*00b67f09SDavid van Moolenbroek return;
917*00b67f09SDavid van Moolenbroek for (i = 0; i < j->header.index_size; i++) {
918*00b67f09SDavid van Moolenbroek if (! DNS_SERIAL_GT(serial, j->index[i].serial))
919*00b67f09SDavid van Moolenbroek POS_INVALIDATE(j->index[i]);
920*00b67f09SDavid van Moolenbroek }
921*00b67f09SDavid van Moolenbroek }
922*00b67f09SDavid van Moolenbroek
923*00b67f09SDavid van Moolenbroek /*
924*00b67f09SDavid van Moolenbroek * Try to find a transaction with initial serial number 'serial'
925*00b67f09SDavid van Moolenbroek * in the journal 'j'.
926*00b67f09SDavid van Moolenbroek *
927*00b67f09SDavid van Moolenbroek * If found, store its position at '*pos' and return ISC_R_SUCCESS.
928*00b67f09SDavid van Moolenbroek *
929*00b67f09SDavid van Moolenbroek * If 'serial' is current (= the ending serial number of the
930*00b67f09SDavid van Moolenbroek * last transaction in the journal), set '*pos' to
931*00b67f09SDavid van Moolenbroek * the position immediately following the last transaction and
932*00b67f09SDavid van Moolenbroek * return ISC_R_SUCCESS.
933*00b67f09SDavid van Moolenbroek *
934*00b67f09SDavid van Moolenbroek * If 'serial' is within the range of addressable serial numbers
935*00b67f09SDavid van Moolenbroek * covered by the journal but that particular serial number is missing
936*00b67f09SDavid van Moolenbroek * (from the journal, not just from the index), return ISC_R_NOTFOUND.
937*00b67f09SDavid van Moolenbroek *
938*00b67f09SDavid van Moolenbroek * If 'serial' is outside the range of addressable serial numbers
939*00b67f09SDavid van Moolenbroek * covered by the journal, return ISC_R_RANGE.
940*00b67f09SDavid van Moolenbroek *
941*00b67f09SDavid van Moolenbroek */
942*00b67f09SDavid van Moolenbroek static isc_result_t
journal_find(dns_journal_t * j,isc_uint32_t serial,journal_pos_t * pos)943*00b67f09SDavid van Moolenbroek journal_find(dns_journal_t *j, isc_uint32_t serial, journal_pos_t *pos) {
944*00b67f09SDavid van Moolenbroek isc_result_t result;
945*00b67f09SDavid van Moolenbroek journal_pos_t current_pos;
946*00b67f09SDavid van Moolenbroek REQUIRE(DNS_JOURNAL_VALID(j));
947*00b67f09SDavid van Moolenbroek
948*00b67f09SDavid van Moolenbroek if (DNS_SERIAL_GT(j->header.begin.serial, serial))
949*00b67f09SDavid van Moolenbroek return (ISC_R_RANGE);
950*00b67f09SDavid van Moolenbroek if (DNS_SERIAL_GT(serial, j->header.end.serial))
951*00b67f09SDavid van Moolenbroek return (ISC_R_RANGE);
952*00b67f09SDavid van Moolenbroek if (serial == j->header.end.serial) {
953*00b67f09SDavid van Moolenbroek *pos = j->header.end;
954*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
955*00b67f09SDavid van Moolenbroek }
956*00b67f09SDavid van Moolenbroek
957*00b67f09SDavid van Moolenbroek current_pos = j->header.begin;
958*00b67f09SDavid van Moolenbroek index_find(j, serial, ¤t_pos);
959*00b67f09SDavid van Moolenbroek
960*00b67f09SDavid van Moolenbroek while (current_pos.serial != serial) {
961*00b67f09SDavid van Moolenbroek if (DNS_SERIAL_GT(current_pos.serial, serial))
962*00b67f09SDavid van Moolenbroek return (ISC_R_NOTFOUND);
963*00b67f09SDavid van Moolenbroek result = journal_next(j, ¤t_pos);
964*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
965*00b67f09SDavid van Moolenbroek return (result);
966*00b67f09SDavid van Moolenbroek }
967*00b67f09SDavid van Moolenbroek *pos = current_pos;
968*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
969*00b67f09SDavid van Moolenbroek }
970*00b67f09SDavid van Moolenbroek
971*00b67f09SDavid van Moolenbroek isc_result_t
dns_journal_begin_transaction(dns_journal_t * j)972*00b67f09SDavid van Moolenbroek dns_journal_begin_transaction(dns_journal_t *j) {
973*00b67f09SDavid van Moolenbroek isc_uint32_t offset;
974*00b67f09SDavid van Moolenbroek isc_result_t result;
975*00b67f09SDavid van Moolenbroek journal_rawxhdr_t hdr;
976*00b67f09SDavid van Moolenbroek
977*00b67f09SDavid van Moolenbroek REQUIRE(DNS_JOURNAL_VALID(j));
978*00b67f09SDavid van Moolenbroek REQUIRE(j->state == JOURNAL_STATE_WRITE ||
979*00b67f09SDavid van Moolenbroek j->state == JOURNAL_STATE_INLINE);
980*00b67f09SDavid van Moolenbroek
981*00b67f09SDavid van Moolenbroek /*
982*00b67f09SDavid van Moolenbroek * Find the file offset where the new transaction should
983*00b67f09SDavid van Moolenbroek * be written, and seek there.
984*00b67f09SDavid van Moolenbroek */
985*00b67f09SDavid van Moolenbroek if (JOURNAL_EMPTY(&j->header)) {
986*00b67f09SDavid van Moolenbroek offset = sizeof(journal_rawheader_t) +
987*00b67f09SDavid van Moolenbroek j->header.index_size * sizeof(journal_rawpos_t);
988*00b67f09SDavid van Moolenbroek } else {
989*00b67f09SDavid van Moolenbroek offset = j->header.end.offset;
990*00b67f09SDavid van Moolenbroek }
991*00b67f09SDavid van Moolenbroek j->x.pos[0].offset = offset;
992*00b67f09SDavid van Moolenbroek j->x.pos[1].offset = offset; /* Initial value, will be incremented. */
993*00b67f09SDavid van Moolenbroek j->x.n_soa = 0;
994*00b67f09SDavid van Moolenbroek
995*00b67f09SDavid van Moolenbroek CHECK(journal_seek(j, offset));
996*00b67f09SDavid van Moolenbroek
997*00b67f09SDavid van Moolenbroek /*
998*00b67f09SDavid van Moolenbroek * Write a dummy transaction header of all zeroes to reserve
999*00b67f09SDavid van Moolenbroek * space. It will be filled in when the transaction is
1000*00b67f09SDavid van Moolenbroek * finished.
1001*00b67f09SDavid van Moolenbroek */
1002*00b67f09SDavid van Moolenbroek memset(&hdr, 0, sizeof(hdr));
1003*00b67f09SDavid van Moolenbroek CHECK(journal_write(j, &hdr, sizeof(hdr)));
1004*00b67f09SDavid van Moolenbroek j->x.pos[1].offset = j->offset;
1005*00b67f09SDavid van Moolenbroek
1006*00b67f09SDavid van Moolenbroek j->state = JOURNAL_STATE_TRANSACTION;
1007*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
1008*00b67f09SDavid van Moolenbroek failure:
1009*00b67f09SDavid van Moolenbroek return (result);
1010*00b67f09SDavid van Moolenbroek }
1011*00b67f09SDavid van Moolenbroek
1012*00b67f09SDavid van Moolenbroek isc_result_t
dns_journal_writediff(dns_journal_t * j,dns_diff_t * diff)1013*00b67f09SDavid van Moolenbroek dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff) {
1014*00b67f09SDavid van Moolenbroek dns_difftuple_t *t;
1015*00b67f09SDavid van Moolenbroek isc_buffer_t buffer;
1016*00b67f09SDavid van Moolenbroek void *mem = NULL;
1017*00b67f09SDavid van Moolenbroek unsigned int size;
1018*00b67f09SDavid van Moolenbroek isc_result_t result;
1019*00b67f09SDavid van Moolenbroek isc_region_t used;
1020*00b67f09SDavid van Moolenbroek
1021*00b67f09SDavid van Moolenbroek REQUIRE(DNS_DIFF_VALID(diff));
1022*00b67f09SDavid van Moolenbroek REQUIRE(j->state == JOURNAL_STATE_TRANSACTION);
1023*00b67f09SDavid van Moolenbroek
1024*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "writing to journal");
1025*00b67f09SDavid van Moolenbroek (void)dns_diff_print(diff, NULL);
1026*00b67f09SDavid van Moolenbroek
1027*00b67f09SDavid van Moolenbroek /*
1028*00b67f09SDavid van Moolenbroek * Pass 1: determine the buffer size needed, and
1029*00b67f09SDavid van Moolenbroek * keep track of SOA serial numbers.
1030*00b67f09SDavid van Moolenbroek */
1031*00b67f09SDavid van Moolenbroek size = 0;
1032*00b67f09SDavid van Moolenbroek for (t = ISC_LIST_HEAD(diff->tuples); t != NULL;
1033*00b67f09SDavid van Moolenbroek t = ISC_LIST_NEXT(t, link))
1034*00b67f09SDavid van Moolenbroek {
1035*00b67f09SDavid van Moolenbroek if (t->rdata.type == dns_rdatatype_soa) {
1036*00b67f09SDavid van Moolenbroek if (j->x.n_soa < 2)
1037*00b67f09SDavid van Moolenbroek j->x.pos[j->x.n_soa].serial =
1038*00b67f09SDavid van Moolenbroek dns_soa_getserial(&t->rdata);
1039*00b67f09SDavid van Moolenbroek j->x.n_soa++;
1040*00b67f09SDavid van Moolenbroek }
1041*00b67f09SDavid van Moolenbroek size += sizeof(journal_rawrrhdr_t);
1042*00b67f09SDavid van Moolenbroek size += t->name.length; /* XXX should have access macro? */
1043*00b67f09SDavid van Moolenbroek size += 10;
1044*00b67f09SDavid van Moolenbroek size += t->rdata.length;
1045*00b67f09SDavid van Moolenbroek }
1046*00b67f09SDavid van Moolenbroek
1047*00b67f09SDavid van Moolenbroek mem = isc_mem_get(j->mctx, size);
1048*00b67f09SDavid van Moolenbroek if (mem == NULL)
1049*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
1050*00b67f09SDavid van Moolenbroek
1051*00b67f09SDavid van Moolenbroek isc_buffer_init(&buffer, mem, size);
1052*00b67f09SDavid van Moolenbroek
1053*00b67f09SDavid van Moolenbroek /*
1054*00b67f09SDavid van Moolenbroek * Pass 2. Write RRs to buffer.
1055*00b67f09SDavid van Moolenbroek */
1056*00b67f09SDavid van Moolenbroek for (t = ISC_LIST_HEAD(diff->tuples); t != NULL;
1057*00b67f09SDavid van Moolenbroek t = ISC_LIST_NEXT(t, link))
1058*00b67f09SDavid van Moolenbroek {
1059*00b67f09SDavid van Moolenbroek /*
1060*00b67f09SDavid van Moolenbroek * Write the RR header.
1061*00b67f09SDavid van Moolenbroek */
1062*00b67f09SDavid van Moolenbroek isc_buffer_putuint32(&buffer, t->name.length + 10 +
1063*00b67f09SDavid van Moolenbroek t->rdata.length);
1064*00b67f09SDavid van Moolenbroek /*
1065*00b67f09SDavid van Moolenbroek * Write the owner name, RR header, and RR data.
1066*00b67f09SDavid van Moolenbroek */
1067*00b67f09SDavid van Moolenbroek isc_buffer_putmem(&buffer, t->name.ndata, t->name.length);
1068*00b67f09SDavid van Moolenbroek isc_buffer_putuint16(&buffer, t->rdata.type);
1069*00b67f09SDavid van Moolenbroek isc_buffer_putuint16(&buffer, t->rdata.rdclass);
1070*00b67f09SDavid van Moolenbroek isc_buffer_putuint32(&buffer, t->ttl);
1071*00b67f09SDavid van Moolenbroek INSIST(t->rdata.length < 65536);
1072*00b67f09SDavid van Moolenbroek isc_buffer_putuint16(&buffer, (isc_uint16_t)t->rdata.length);
1073*00b67f09SDavid van Moolenbroek INSIST(isc_buffer_availablelength(&buffer) >= t->rdata.length);
1074*00b67f09SDavid van Moolenbroek isc_buffer_putmem(&buffer, t->rdata.data, t->rdata.length);
1075*00b67f09SDavid van Moolenbroek }
1076*00b67f09SDavid van Moolenbroek
1077*00b67f09SDavid van Moolenbroek isc_buffer_usedregion(&buffer, &used);
1078*00b67f09SDavid van Moolenbroek INSIST(used.length == size);
1079*00b67f09SDavid van Moolenbroek
1080*00b67f09SDavid van Moolenbroek j->x.pos[1].offset += used.length;
1081*00b67f09SDavid van Moolenbroek
1082*00b67f09SDavid van Moolenbroek /*
1083*00b67f09SDavid van Moolenbroek * Write the buffer contents to the journal file.
1084*00b67f09SDavid van Moolenbroek */
1085*00b67f09SDavid van Moolenbroek CHECK(journal_write(j, used.base, used.length));
1086*00b67f09SDavid van Moolenbroek
1087*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
1088*00b67f09SDavid van Moolenbroek
1089*00b67f09SDavid van Moolenbroek failure:
1090*00b67f09SDavid van Moolenbroek if (mem != NULL)
1091*00b67f09SDavid van Moolenbroek isc_mem_put(j->mctx, mem, size);
1092*00b67f09SDavid van Moolenbroek return (result);
1093*00b67f09SDavid van Moolenbroek
1094*00b67f09SDavid van Moolenbroek }
1095*00b67f09SDavid van Moolenbroek
1096*00b67f09SDavid van Moolenbroek isc_result_t
dns_journal_commit(dns_journal_t * j)1097*00b67f09SDavid van Moolenbroek dns_journal_commit(dns_journal_t *j) {
1098*00b67f09SDavid van Moolenbroek isc_result_t result;
1099*00b67f09SDavid van Moolenbroek journal_rawheader_t rawheader;
1100*00b67f09SDavid van Moolenbroek
1101*00b67f09SDavid van Moolenbroek REQUIRE(DNS_JOURNAL_VALID(j));
1102*00b67f09SDavid van Moolenbroek REQUIRE(j->state == JOURNAL_STATE_TRANSACTION ||
1103*00b67f09SDavid van Moolenbroek j->state == JOURNAL_STATE_INLINE);
1104*00b67f09SDavid van Moolenbroek
1105*00b67f09SDavid van Moolenbroek /*
1106*00b67f09SDavid van Moolenbroek * Just write out a updated header.
1107*00b67f09SDavid van Moolenbroek */
1108*00b67f09SDavid van Moolenbroek if (j->state == JOURNAL_STATE_INLINE) {
1109*00b67f09SDavid van Moolenbroek CHECK(journal_fsync(j));
1110*00b67f09SDavid van Moolenbroek journal_header_encode(&j->header, &rawheader);
1111*00b67f09SDavid van Moolenbroek CHECK(journal_seek(j, 0));
1112*00b67f09SDavid van Moolenbroek CHECK(journal_write(j, &rawheader, sizeof(rawheader)));
1113*00b67f09SDavid van Moolenbroek CHECK(journal_fsync(j));
1114*00b67f09SDavid van Moolenbroek j->state = JOURNAL_STATE_WRITE;
1115*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
1116*00b67f09SDavid van Moolenbroek }
1117*00b67f09SDavid van Moolenbroek
1118*00b67f09SDavid van Moolenbroek /*
1119*00b67f09SDavid van Moolenbroek * Perform some basic consistency checks.
1120*00b67f09SDavid van Moolenbroek */
1121*00b67f09SDavid van Moolenbroek if (j->x.n_soa != 2) {
1122*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
1123*00b67f09SDavid van Moolenbroek "%s: malformed transaction: %d SOAs",
1124*00b67f09SDavid van Moolenbroek j->filename, j->x.n_soa);
1125*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
1126*00b67f09SDavid van Moolenbroek }
1127*00b67f09SDavid van Moolenbroek if (! (DNS_SERIAL_GT(j->x.pos[1].serial, j->x.pos[0].serial) ||
1128*00b67f09SDavid van Moolenbroek (bind8_compat &&
1129*00b67f09SDavid van Moolenbroek j->x.pos[1].serial == j->x.pos[0].serial)))
1130*00b67f09SDavid van Moolenbroek {
1131*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
1132*00b67f09SDavid van Moolenbroek "%s: malformed transaction: serial number "
1133*00b67f09SDavid van Moolenbroek "would decrease", j->filename);
1134*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
1135*00b67f09SDavid van Moolenbroek }
1136*00b67f09SDavid van Moolenbroek if (! JOURNAL_EMPTY(&j->header)) {
1137*00b67f09SDavid van Moolenbroek if (j->x.pos[0].serial != j->header.end.serial) {
1138*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
1139*00b67f09SDavid van Moolenbroek "malformed transaction: "
1140*00b67f09SDavid van Moolenbroek "%s last serial %u != "
1141*00b67f09SDavid van Moolenbroek "transaction first serial %u",
1142*00b67f09SDavid van Moolenbroek j->filename,
1143*00b67f09SDavid van Moolenbroek j->header.end.serial,
1144*00b67f09SDavid van Moolenbroek j->x.pos[0].serial);
1145*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
1146*00b67f09SDavid van Moolenbroek }
1147*00b67f09SDavid van Moolenbroek }
1148*00b67f09SDavid van Moolenbroek
1149*00b67f09SDavid van Moolenbroek /*
1150*00b67f09SDavid van Moolenbroek * Some old journal entries may become non-addressable
1151*00b67f09SDavid van Moolenbroek * when we increment the current serial number. Purge them
1152*00b67f09SDavid van Moolenbroek * by stepping header.begin forward to the first addressable
1153*00b67f09SDavid van Moolenbroek * transaction. Also purge them from the index.
1154*00b67f09SDavid van Moolenbroek */
1155*00b67f09SDavid van Moolenbroek if (! JOURNAL_EMPTY(&j->header)) {
1156*00b67f09SDavid van Moolenbroek while (! DNS_SERIAL_GT(j->x.pos[1].serial,
1157*00b67f09SDavid van Moolenbroek j->header.begin.serial)) {
1158*00b67f09SDavid van Moolenbroek CHECK(journal_next(j, &j->header.begin));
1159*00b67f09SDavid van Moolenbroek }
1160*00b67f09SDavid van Moolenbroek index_invalidate(j, j->x.pos[1].serial);
1161*00b67f09SDavid van Moolenbroek }
1162*00b67f09SDavid van Moolenbroek #ifdef notyet
1163*00b67f09SDavid van Moolenbroek if (DNS_SERIAL_GT(last_dumped_serial, j->x.pos[1].serial)) {
1164*00b67f09SDavid van Moolenbroek force_dump(...);
1165*00b67f09SDavid van Moolenbroek }
1166*00b67f09SDavid van Moolenbroek #endif
1167*00b67f09SDavid van Moolenbroek
1168*00b67f09SDavid van Moolenbroek /*
1169*00b67f09SDavid van Moolenbroek * Commit the transaction data to stable storage.
1170*00b67f09SDavid van Moolenbroek */
1171*00b67f09SDavid van Moolenbroek CHECK(journal_fsync(j));
1172*00b67f09SDavid van Moolenbroek
1173*00b67f09SDavid van Moolenbroek if (j->state == JOURNAL_STATE_TRANSACTION) {
1174*00b67f09SDavid van Moolenbroek isc_offset_t offset;
1175*00b67f09SDavid van Moolenbroek offset = (j->x.pos[1].offset - j->x.pos[0].offset) -
1176*00b67f09SDavid van Moolenbroek sizeof(journal_rawxhdr_t);
1177*00b67f09SDavid van Moolenbroek /*
1178*00b67f09SDavid van Moolenbroek * Update the transaction header.
1179*00b67f09SDavid van Moolenbroek */
1180*00b67f09SDavid van Moolenbroek CHECK(journal_seek(j, j->x.pos[0].offset));
1181*00b67f09SDavid van Moolenbroek CHECK(journal_write_xhdr(j, offset, j->x.pos[0].serial,
1182*00b67f09SDavid van Moolenbroek j->x.pos[1].serial));
1183*00b67f09SDavid van Moolenbroek }
1184*00b67f09SDavid van Moolenbroek
1185*00b67f09SDavid van Moolenbroek /*
1186*00b67f09SDavid van Moolenbroek * Update the journal header.
1187*00b67f09SDavid van Moolenbroek */
1188*00b67f09SDavid van Moolenbroek if (JOURNAL_EMPTY(&j->header))
1189*00b67f09SDavid van Moolenbroek j->header.begin = j->x.pos[0];
1190*00b67f09SDavid van Moolenbroek j->header.end = j->x.pos[1];
1191*00b67f09SDavid van Moolenbroek journal_header_encode(&j->header, &rawheader);
1192*00b67f09SDavid van Moolenbroek CHECK(journal_seek(j, 0));
1193*00b67f09SDavid van Moolenbroek CHECK(journal_write(j, &rawheader, sizeof(rawheader)));
1194*00b67f09SDavid van Moolenbroek
1195*00b67f09SDavid van Moolenbroek /*
1196*00b67f09SDavid van Moolenbroek * Update the index.
1197*00b67f09SDavid van Moolenbroek */
1198*00b67f09SDavid van Moolenbroek index_add(j, &j->x.pos[0]);
1199*00b67f09SDavid van Moolenbroek
1200*00b67f09SDavid van Moolenbroek /*
1201*00b67f09SDavid van Moolenbroek * Convert the index into on-disk format and write
1202*00b67f09SDavid van Moolenbroek * it to disk.
1203*00b67f09SDavid van Moolenbroek */
1204*00b67f09SDavid van Moolenbroek CHECK(index_to_disk(j));
1205*00b67f09SDavid van Moolenbroek
1206*00b67f09SDavid van Moolenbroek /*
1207*00b67f09SDavid van Moolenbroek * Commit the header to stable storage.
1208*00b67f09SDavid van Moolenbroek */
1209*00b67f09SDavid van Moolenbroek CHECK(journal_fsync(j));
1210*00b67f09SDavid van Moolenbroek
1211*00b67f09SDavid van Moolenbroek /*
1212*00b67f09SDavid van Moolenbroek * We no longer have a transaction open.
1213*00b67f09SDavid van Moolenbroek */
1214*00b67f09SDavid van Moolenbroek j->state = JOURNAL_STATE_WRITE;
1215*00b67f09SDavid van Moolenbroek
1216*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
1217*00b67f09SDavid van Moolenbroek
1218*00b67f09SDavid van Moolenbroek failure:
1219*00b67f09SDavid van Moolenbroek return (result);
1220*00b67f09SDavid van Moolenbroek }
1221*00b67f09SDavid van Moolenbroek
1222*00b67f09SDavid van Moolenbroek isc_result_t
dns_journal_write_transaction(dns_journal_t * j,dns_diff_t * diff)1223*00b67f09SDavid van Moolenbroek dns_journal_write_transaction(dns_journal_t *j, dns_diff_t *diff) {
1224*00b67f09SDavid van Moolenbroek isc_result_t result;
1225*00b67f09SDavid van Moolenbroek CHECK(dns_diff_sort(diff, ixfr_order));
1226*00b67f09SDavid van Moolenbroek CHECK(dns_journal_begin_transaction(j));
1227*00b67f09SDavid van Moolenbroek CHECK(dns_journal_writediff(j, diff));
1228*00b67f09SDavid van Moolenbroek CHECK(dns_journal_commit(j));
1229*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
1230*00b67f09SDavid van Moolenbroek failure:
1231*00b67f09SDavid van Moolenbroek return (result);
1232*00b67f09SDavid van Moolenbroek }
1233*00b67f09SDavid van Moolenbroek
1234*00b67f09SDavid van Moolenbroek void
dns_journal_destroy(dns_journal_t ** journalp)1235*00b67f09SDavid van Moolenbroek dns_journal_destroy(dns_journal_t **journalp) {
1236*00b67f09SDavid van Moolenbroek dns_journal_t *j = *journalp;
1237*00b67f09SDavid van Moolenbroek REQUIRE(DNS_JOURNAL_VALID(j));
1238*00b67f09SDavid van Moolenbroek
1239*00b67f09SDavid van Moolenbroek j->it.result = ISC_R_FAILURE;
1240*00b67f09SDavid van Moolenbroek dns_name_invalidate(&j->it.name);
1241*00b67f09SDavid van Moolenbroek dns_decompress_invalidate(&j->it.dctx);
1242*00b67f09SDavid van Moolenbroek if (j->rawindex != NULL)
1243*00b67f09SDavid van Moolenbroek isc_mem_put(j->mctx, j->rawindex, j->header.index_size *
1244*00b67f09SDavid van Moolenbroek sizeof(journal_rawpos_t));
1245*00b67f09SDavid van Moolenbroek if (j->index != NULL)
1246*00b67f09SDavid van Moolenbroek isc_mem_put(j->mctx, j->index, j->header.index_size *
1247*00b67f09SDavid van Moolenbroek sizeof(journal_pos_t));
1248*00b67f09SDavid van Moolenbroek if (j->it.target.base != NULL)
1249*00b67f09SDavid van Moolenbroek isc_mem_put(j->mctx, j->it.target.base, j->it.target.length);
1250*00b67f09SDavid van Moolenbroek if (j->it.source.base != NULL)
1251*00b67f09SDavid van Moolenbroek isc_mem_put(j->mctx, j->it.source.base, j->it.source.length);
1252*00b67f09SDavid van Moolenbroek if (j->filename != NULL)
1253*00b67f09SDavid van Moolenbroek isc_mem_free(j->mctx, j->filename);
1254*00b67f09SDavid van Moolenbroek if (j->fp != NULL)
1255*00b67f09SDavid van Moolenbroek (void)isc_stdio_close(j->fp);
1256*00b67f09SDavid van Moolenbroek j->magic = 0;
1257*00b67f09SDavid van Moolenbroek isc_mem_putanddetach(&j->mctx, j, sizeof(*j));
1258*00b67f09SDavid van Moolenbroek *journalp = NULL;
1259*00b67f09SDavid van Moolenbroek }
1260*00b67f09SDavid van Moolenbroek
1261*00b67f09SDavid van Moolenbroek /*
1262*00b67f09SDavid van Moolenbroek * Roll the open journal 'j' into the database 'db'.
1263*00b67f09SDavid van Moolenbroek * A new database version will be created.
1264*00b67f09SDavid van Moolenbroek */
1265*00b67f09SDavid van Moolenbroek
1266*00b67f09SDavid van Moolenbroek /* XXX Share code with incoming IXFR? */
1267*00b67f09SDavid van Moolenbroek
1268*00b67f09SDavid van Moolenbroek static isc_result_t
roll_forward(dns_journal_t * j,dns_db_t * db,unsigned int options)1269*00b67f09SDavid van Moolenbroek roll_forward(dns_journal_t *j, dns_db_t *db, unsigned int options) {
1270*00b67f09SDavid van Moolenbroek isc_buffer_t source; /* Transaction data from disk */
1271*00b67f09SDavid van Moolenbroek isc_buffer_t target; /* Ditto after _fromwire check */
1272*00b67f09SDavid van Moolenbroek isc_uint32_t db_serial; /* Database SOA serial */
1273*00b67f09SDavid van Moolenbroek isc_uint32_t end_serial; /* Last journal SOA serial */
1274*00b67f09SDavid van Moolenbroek isc_result_t result;
1275*00b67f09SDavid van Moolenbroek dns_dbversion_t *ver = NULL;
1276*00b67f09SDavid van Moolenbroek journal_pos_t pos;
1277*00b67f09SDavid van Moolenbroek dns_diff_t diff;
1278*00b67f09SDavid van Moolenbroek unsigned int n_soa = 0;
1279*00b67f09SDavid van Moolenbroek unsigned int n_put = 0;
1280*00b67f09SDavid van Moolenbroek dns_diffop_t op;
1281*00b67f09SDavid van Moolenbroek
1282*00b67f09SDavid van Moolenbroek REQUIRE(DNS_JOURNAL_VALID(j));
1283*00b67f09SDavid van Moolenbroek REQUIRE(DNS_DB_VALID(db));
1284*00b67f09SDavid van Moolenbroek
1285*00b67f09SDavid van Moolenbroek dns_diff_init(j->mctx, &diff);
1286*00b67f09SDavid van Moolenbroek
1287*00b67f09SDavid van Moolenbroek /*
1288*00b67f09SDavid van Moolenbroek * Set up empty initial buffers for unchecked and checked
1289*00b67f09SDavid van Moolenbroek * wire format transaction data. They will be reallocated
1290*00b67f09SDavid van Moolenbroek * later.
1291*00b67f09SDavid van Moolenbroek */
1292*00b67f09SDavid van Moolenbroek isc_buffer_init(&source, NULL, 0);
1293*00b67f09SDavid van Moolenbroek isc_buffer_init(&target, NULL, 0);
1294*00b67f09SDavid van Moolenbroek
1295*00b67f09SDavid van Moolenbroek /*
1296*00b67f09SDavid van Moolenbroek * Create the new database version.
1297*00b67f09SDavid van Moolenbroek */
1298*00b67f09SDavid van Moolenbroek CHECK(dns_db_newversion(db, &ver));
1299*00b67f09SDavid van Moolenbroek
1300*00b67f09SDavid van Moolenbroek /*
1301*00b67f09SDavid van Moolenbroek * Get the current database SOA serial number.
1302*00b67f09SDavid van Moolenbroek */
1303*00b67f09SDavid van Moolenbroek CHECK(dns_db_getsoaserial(db, ver, &db_serial));
1304*00b67f09SDavid van Moolenbroek
1305*00b67f09SDavid van Moolenbroek /*
1306*00b67f09SDavid van Moolenbroek * Locate a journal entry for the current database serial.
1307*00b67f09SDavid van Moolenbroek */
1308*00b67f09SDavid van Moolenbroek CHECK(journal_find(j, db_serial, &pos));
1309*00b67f09SDavid van Moolenbroek /*
1310*00b67f09SDavid van Moolenbroek * XXX do more drastic things, like marking zone stale,
1311*00b67f09SDavid van Moolenbroek * if this fails?
1312*00b67f09SDavid van Moolenbroek */
1313*00b67f09SDavid van Moolenbroek /*
1314*00b67f09SDavid van Moolenbroek * XXXRTH The zone code should probably mark the zone as bad and
1315*00b67f09SDavid van Moolenbroek * scream loudly into the log if this is a dynamic update
1316*00b67f09SDavid van Moolenbroek * log reply that failed.
1317*00b67f09SDavid van Moolenbroek */
1318*00b67f09SDavid van Moolenbroek
1319*00b67f09SDavid van Moolenbroek end_serial = dns_journal_last_serial(j);
1320*00b67f09SDavid van Moolenbroek if (db_serial == end_serial)
1321*00b67f09SDavid van Moolenbroek CHECK(DNS_R_UPTODATE);
1322*00b67f09SDavid van Moolenbroek
1323*00b67f09SDavid van Moolenbroek CHECK(dns_journal_iter_init(j, db_serial, end_serial));
1324*00b67f09SDavid van Moolenbroek
1325*00b67f09SDavid van Moolenbroek for (result = dns_journal_first_rr(j);
1326*00b67f09SDavid van Moolenbroek result == ISC_R_SUCCESS;
1327*00b67f09SDavid van Moolenbroek result = dns_journal_next_rr(j))
1328*00b67f09SDavid van Moolenbroek {
1329*00b67f09SDavid van Moolenbroek dns_name_t *name;
1330*00b67f09SDavid van Moolenbroek isc_uint32_t ttl;
1331*00b67f09SDavid van Moolenbroek dns_rdata_t *rdata;
1332*00b67f09SDavid van Moolenbroek dns_difftuple_t *tuple = NULL;
1333*00b67f09SDavid van Moolenbroek
1334*00b67f09SDavid van Moolenbroek name = NULL;
1335*00b67f09SDavid van Moolenbroek rdata = NULL;
1336*00b67f09SDavid van Moolenbroek dns_journal_current_rr(j, &name, &ttl, &rdata);
1337*00b67f09SDavid van Moolenbroek
1338*00b67f09SDavid van Moolenbroek if (rdata->type == dns_rdatatype_soa) {
1339*00b67f09SDavid van Moolenbroek n_soa++;
1340*00b67f09SDavid van Moolenbroek if (n_soa == 2)
1341*00b67f09SDavid van Moolenbroek db_serial = j->it.current_serial;
1342*00b67f09SDavid van Moolenbroek }
1343*00b67f09SDavid van Moolenbroek
1344*00b67f09SDavid van Moolenbroek if (n_soa == 3)
1345*00b67f09SDavid van Moolenbroek n_soa = 1;
1346*00b67f09SDavid van Moolenbroek if (n_soa == 0) {
1347*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
1348*00b67f09SDavid van Moolenbroek "%s: journal file corrupt: missing "
1349*00b67f09SDavid van Moolenbroek "initial SOA", j->filename);
1350*00b67f09SDavid van Moolenbroek FAIL(ISC_R_UNEXPECTED);
1351*00b67f09SDavid van Moolenbroek }
1352*00b67f09SDavid van Moolenbroek if ((options & DNS_JOURNALOPT_RESIGN) != 0)
1353*00b67f09SDavid van Moolenbroek op = (n_soa == 1) ? DNS_DIFFOP_DELRESIGN :
1354*00b67f09SDavid van Moolenbroek DNS_DIFFOP_ADDRESIGN;
1355*00b67f09SDavid van Moolenbroek else
1356*00b67f09SDavid van Moolenbroek op = (n_soa == 1) ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD;
1357*00b67f09SDavid van Moolenbroek
1358*00b67f09SDavid van Moolenbroek CHECK(dns_difftuple_create(diff.mctx, op, name, ttl, rdata,
1359*00b67f09SDavid van Moolenbroek &tuple));
1360*00b67f09SDavid van Moolenbroek dns_diff_append(&diff, &tuple);
1361*00b67f09SDavid van Moolenbroek
1362*00b67f09SDavid van Moolenbroek if (++n_put > 100) {
1363*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_DEBUG_LOGARGS(3),
1364*00b67f09SDavid van Moolenbroek "%s: applying diff to database (%u)",
1365*00b67f09SDavid van Moolenbroek j->filename, db_serial);
1366*00b67f09SDavid van Moolenbroek (void)dns_diff_print(&diff, NULL);
1367*00b67f09SDavid van Moolenbroek CHECK(dns_diff_apply(&diff, db, ver));
1368*00b67f09SDavid van Moolenbroek dns_diff_clear(&diff);
1369*00b67f09SDavid van Moolenbroek n_put = 0;
1370*00b67f09SDavid van Moolenbroek }
1371*00b67f09SDavid van Moolenbroek }
1372*00b67f09SDavid van Moolenbroek if (result == ISC_R_NOMORE)
1373*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
1374*00b67f09SDavid van Moolenbroek CHECK(result);
1375*00b67f09SDavid van Moolenbroek
1376*00b67f09SDavid van Moolenbroek if (n_put != 0) {
1377*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_DEBUG_LOGARGS(3),
1378*00b67f09SDavid van Moolenbroek "%s: applying final diff to database (%u)",
1379*00b67f09SDavid van Moolenbroek j->filename, db_serial);
1380*00b67f09SDavid van Moolenbroek (void)dns_diff_print(&diff, NULL);
1381*00b67f09SDavid van Moolenbroek CHECK(dns_diff_apply(&diff, db, ver));
1382*00b67f09SDavid van Moolenbroek dns_diff_clear(&diff);
1383*00b67f09SDavid van Moolenbroek }
1384*00b67f09SDavid van Moolenbroek
1385*00b67f09SDavid van Moolenbroek failure:
1386*00b67f09SDavid van Moolenbroek if (ver != NULL)
1387*00b67f09SDavid van Moolenbroek dns_db_closeversion(db, &ver, result == ISC_R_SUCCESS ?
1388*00b67f09SDavid van Moolenbroek ISC_TRUE : ISC_FALSE);
1389*00b67f09SDavid van Moolenbroek
1390*00b67f09SDavid van Moolenbroek if (source.base != NULL)
1391*00b67f09SDavid van Moolenbroek isc_mem_put(j->mctx, source.base, source.length);
1392*00b67f09SDavid van Moolenbroek if (target.base != NULL)
1393*00b67f09SDavid van Moolenbroek isc_mem_put(j->mctx, target.base, target.length);
1394*00b67f09SDavid van Moolenbroek
1395*00b67f09SDavid van Moolenbroek dns_diff_clear(&diff);
1396*00b67f09SDavid van Moolenbroek
1397*00b67f09SDavid van Moolenbroek INSIST(ver == NULL);
1398*00b67f09SDavid van Moolenbroek
1399*00b67f09SDavid van Moolenbroek return (result);
1400*00b67f09SDavid van Moolenbroek }
1401*00b67f09SDavid van Moolenbroek
1402*00b67f09SDavid van Moolenbroek isc_result_t
dns_journal_rollforward(isc_mem_t * mctx,dns_db_t * db,unsigned int options,const char * filename)1403*00b67f09SDavid van Moolenbroek dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, unsigned int options,
1404*00b67f09SDavid van Moolenbroek const char *filename)
1405*00b67f09SDavid van Moolenbroek {
1406*00b67f09SDavid van Moolenbroek dns_journal_t *j;
1407*00b67f09SDavid van Moolenbroek isc_result_t result;
1408*00b67f09SDavid van Moolenbroek
1409*00b67f09SDavid van Moolenbroek REQUIRE(DNS_DB_VALID(db));
1410*00b67f09SDavid van Moolenbroek REQUIRE(filename != NULL);
1411*00b67f09SDavid van Moolenbroek
1412*00b67f09SDavid van Moolenbroek j = NULL;
1413*00b67f09SDavid van Moolenbroek result = dns_journal_open(mctx, filename, DNS_JOURNAL_READ, &j);
1414*00b67f09SDavid van Moolenbroek if (result == ISC_R_NOTFOUND) {
1415*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_DEBUG_LOGARGS(3),
1416*00b67f09SDavid van Moolenbroek "no journal file, but that's OK");
1417*00b67f09SDavid van Moolenbroek return (DNS_R_NOJOURNAL);
1418*00b67f09SDavid van Moolenbroek }
1419*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
1420*00b67f09SDavid van Moolenbroek return (result);
1421*00b67f09SDavid van Moolenbroek if (JOURNAL_EMPTY(&j->header))
1422*00b67f09SDavid van Moolenbroek result = DNS_R_UPTODATE;
1423*00b67f09SDavid van Moolenbroek else
1424*00b67f09SDavid van Moolenbroek result = roll_forward(j, db, options);
1425*00b67f09SDavid van Moolenbroek
1426*00b67f09SDavid van Moolenbroek dns_journal_destroy(&j);
1427*00b67f09SDavid van Moolenbroek
1428*00b67f09SDavid van Moolenbroek return (result);
1429*00b67f09SDavid van Moolenbroek }
1430*00b67f09SDavid van Moolenbroek
1431*00b67f09SDavid van Moolenbroek isc_result_t
dns_journal_print(isc_mem_t * mctx,const char * filename,FILE * file)1432*00b67f09SDavid van Moolenbroek dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
1433*00b67f09SDavid van Moolenbroek dns_journal_t *j;
1434*00b67f09SDavid van Moolenbroek isc_buffer_t source; /* Transaction data from disk */
1435*00b67f09SDavid van Moolenbroek isc_buffer_t target; /* Ditto after _fromwire check */
1436*00b67f09SDavid van Moolenbroek isc_uint32_t start_serial; /* Database SOA serial */
1437*00b67f09SDavid van Moolenbroek isc_uint32_t end_serial; /* Last journal SOA serial */
1438*00b67f09SDavid van Moolenbroek isc_result_t result;
1439*00b67f09SDavid van Moolenbroek dns_diff_t diff;
1440*00b67f09SDavid van Moolenbroek unsigned int n_soa = 0;
1441*00b67f09SDavid van Moolenbroek unsigned int n_put = 0;
1442*00b67f09SDavid van Moolenbroek
1443*00b67f09SDavid van Moolenbroek REQUIRE(filename != NULL);
1444*00b67f09SDavid van Moolenbroek
1445*00b67f09SDavid van Moolenbroek j = NULL;
1446*00b67f09SDavid van Moolenbroek result = dns_journal_open(mctx, filename, DNS_JOURNAL_READ, &j);
1447*00b67f09SDavid van Moolenbroek if (result == ISC_R_NOTFOUND) {
1448*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no journal file");
1449*00b67f09SDavid van Moolenbroek return (DNS_R_NOJOURNAL);
1450*00b67f09SDavid van Moolenbroek }
1451*00b67f09SDavid van Moolenbroek
1452*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
1453*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
1454*00b67f09SDavid van Moolenbroek "journal open failure: %s: %s",
1455*00b67f09SDavid van Moolenbroek isc_result_totext(result), filename);
1456*00b67f09SDavid van Moolenbroek return (result);
1457*00b67f09SDavid van Moolenbroek }
1458*00b67f09SDavid van Moolenbroek
1459*00b67f09SDavid van Moolenbroek if (j->header.serialset)
1460*00b67f09SDavid van Moolenbroek fprintf(file, "Source serial = %u\n", j->header.sourceserial);
1461*00b67f09SDavid van Moolenbroek dns_diff_init(j->mctx, &diff);
1462*00b67f09SDavid van Moolenbroek
1463*00b67f09SDavid van Moolenbroek /*
1464*00b67f09SDavid van Moolenbroek * Set up empty initial buffers for unchecked and checked
1465*00b67f09SDavid van Moolenbroek * wire format transaction data. They will be reallocated
1466*00b67f09SDavid van Moolenbroek * later.
1467*00b67f09SDavid van Moolenbroek */
1468*00b67f09SDavid van Moolenbroek isc_buffer_init(&source, NULL, 0);
1469*00b67f09SDavid van Moolenbroek isc_buffer_init(&target, NULL, 0);
1470*00b67f09SDavid van Moolenbroek
1471*00b67f09SDavid van Moolenbroek start_serial = dns_journal_first_serial(j);
1472*00b67f09SDavid van Moolenbroek end_serial = dns_journal_last_serial(j);
1473*00b67f09SDavid van Moolenbroek
1474*00b67f09SDavid van Moolenbroek CHECK(dns_journal_iter_init(j, start_serial, end_serial));
1475*00b67f09SDavid van Moolenbroek
1476*00b67f09SDavid van Moolenbroek for (result = dns_journal_first_rr(j);
1477*00b67f09SDavid van Moolenbroek result == ISC_R_SUCCESS;
1478*00b67f09SDavid van Moolenbroek result = dns_journal_next_rr(j))
1479*00b67f09SDavid van Moolenbroek {
1480*00b67f09SDavid van Moolenbroek dns_name_t *name;
1481*00b67f09SDavid van Moolenbroek isc_uint32_t ttl;
1482*00b67f09SDavid van Moolenbroek dns_rdata_t *rdata;
1483*00b67f09SDavid van Moolenbroek dns_difftuple_t *tuple = NULL;
1484*00b67f09SDavid van Moolenbroek
1485*00b67f09SDavid van Moolenbroek name = NULL;
1486*00b67f09SDavid van Moolenbroek rdata = NULL;
1487*00b67f09SDavid van Moolenbroek dns_journal_current_rr(j, &name, &ttl, &rdata);
1488*00b67f09SDavid van Moolenbroek
1489*00b67f09SDavid van Moolenbroek if (rdata->type == dns_rdatatype_soa)
1490*00b67f09SDavid van Moolenbroek n_soa++;
1491*00b67f09SDavid van Moolenbroek
1492*00b67f09SDavid van Moolenbroek if (n_soa == 3)
1493*00b67f09SDavid van Moolenbroek n_soa = 1;
1494*00b67f09SDavid van Moolenbroek if (n_soa == 0) {
1495*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
1496*00b67f09SDavid van Moolenbroek "%s: journal file corrupt: missing "
1497*00b67f09SDavid van Moolenbroek "initial SOA", j->filename);
1498*00b67f09SDavid van Moolenbroek FAIL(ISC_R_UNEXPECTED);
1499*00b67f09SDavid van Moolenbroek }
1500*00b67f09SDavid van Moolenbroek CHECK(dns_difftuple_create(diff.mctx, n_soa == 1 ?
1501*00b67f09SDavid van Moolenbroek DNS_DIFFOP_DEL : DNS_DIFFOP_ADD,
1502*00b67f09SDavid van Moolenbroek name, ttl, rdata, &tuple));
1503*00b67f09SDavid van Moolenbroek dns_diff_append(&diff, &tuple);
1504*00b67f09SDavid van Moolenbroek
1505*00b67f09SDavid van Moolenbroek if (++n_put > 100) {
1506*00b67f09SDavid van Moolenbroek result = dns_diff_print(&diff, file);
1507*00b67f09SDavid van Moolenbroek dns_diff_clear(&diff);
1508*00b67f09SDavid van Moolenbroek n_put = 0;
1509*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
1510*00b67f09SDavid van Moolenbroek break;
1511*00b67f09SDavid van Moolenbroek }
1512*00b67f09SDavid van Moolenbroek }
1513*00b67f09SDavid van Moolenbroek if (result == ISC_R_NOMORE)
1514*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
1515*00b67f09SDavid van Moolenbroek CHECK(result);
1516*00b67f09SDavid van Moolenbroek
1517*00b67f09SDavid van Moolenbroek if (n_put != 0) {
1518*00b67f09SDavid van Moolenbroek result = dns_diff_print(&diff, file);
1519*00b67f09SDavid van Moolenbroek dns_diff_clear(&diff);
1520*00b67f09SDavid van Moolenbroek }
1521*00b67f09SDavid van Moolenbroek goto cleanup;
1522*00b67f09SDavid van Moolenbroek
1523*00b67f09SDavid van Moolenbroek failure:
1524*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
1525*00b67f09SDavid van Moolenbroek "%s: cannot print: journal file corrupt", j->filename);
1526*00b67f09SDavid van Moolenbroek
1527*00b67f09SDavid van Moolenbroek cleanup:
1528*00b67f09SDavid van Moolenbroek if (source.base != NULL)
1529*00b67f09SDavid van Moolenbroek isc_mem_put(j->mctx, source.base, source.length);
1530*00b67f09SDavid van Moolenbroek if (target.base != NULL)
1531*00b67f09SDavid van Moolenbroek isc_mem_put(j->mctx, target.base, target.length);
1532*00b67f09SDavid van Moolenbroek
1533*00b67f09SDavid van Moolenbroek dns_diff_clear(&diff);
1534*00b67f09SDavid van Moolenbroek dns_journal_destroy(&j);
1535*00b67f09SDavid van Moolenbroek
1536*00b67f09SDavid van Moolenbroek return (result);
1537*00b67f09SDavid van Moolenbroek }
1538*00b67f09SDavid van Moolenbroek
1539*00b67f09SDavid van Moolenbroek /**************************************************************************/
1540*00b67f09SDavid van Moolenbroek /*
1541*00b67f09SDavid van Moolenbroek * Miscellaneous accessors.
1542*00b67f09SDavid van Moolenbroek */
1543*00b67f09SDavid van Moolenbroek isc_uint32_t
dns_journal_first_serial(dns_journal_t * j)1544*00b67f09SDavid van Moolenbroek dns_journal_first_serial(dns_journal_t *j) {
1545*00b67f09SDavid van Moolenbroek return (j->header.begin.serial);
1546*00b67f09SDavid van Moolenbroek }
1547*00b67f09SDavid van Moolenbroek
1548*00b67f09SDavid van Moolenbroek isc_uint32_t
dns_journal_last_serial(dns_journal_t * j)1549*00b67f09SDavid van Moolenbroek dns_journal_last_serial(dns_journal_t *j) {
1550*00b67f09SDavid van Moolenbroek return (j->header.end.serial);
1551*00b67f09SDavid van Moolenbroek }
1552*00b67f09SDavid van Moolenbroek
1553*00b67f09SDavid van Moolenbroek void
dns_journal_set_sourceserial(dns_journal_t * j,isc_uint32_t sourceserial)1554*00b67f09SDavid van Moolenbroek dns_journal_set_sourceserial(dns_journal_t *j, isc_uint32_t sourceserial) {
1555*00b67f09SDavid van Moolenbroek
1556*00b67f09SDavid van Moolenbroek REQUIRE(j->state == JOURNAL_STATE_WRITE ||
1557*00b67f09SDavid van Moolenbroek j->state == JOURNAL_STATE_INLINE ||
1558*00b67f09SDavid van Moolenbroek j->state == JOURNAL_STATE_TRANSACTION);
1559*00b67f09SDavid van Moolenbroek
1560*00b67f09SDavid van Moolenbroek j->header.sourceserial = sourceserial;
1561*00b67f09SDavid van Moolenbroek j->header.serialset = ISC_TRUE;
1562*00b67f09SDavid van Moolenbroek if (j->state == JOURNAL_STATE_WRITE)
1563*00b67f09SDavid van Moolenbroek j->state = JOURNAL_STATE_INLINE;
1564*00b67f09SDavid van Moolenbroek }
1565*00b67f09SDavid van Moolenbroek
1566*00b67f09SDavid van Moolenbroek isc_boolean_t
dns_journal_get_sourceserial(dns_journal_t * j,isc_uint32_t * sourceserial)1567*00b67f09SDavid van Moolenbroek dns_journal_get_sourceserial(dns_journal_t *j, isc_uint32_t *sourceserial) {
1568*00b67f09SDavid van Moolenbroek REQUIRE(sourceserial != NULL);
1569*00b67f09SDavid van Moolenbroek
1570*00b67f09SDavid van Moolenbroek if (!j->header.serialset)
1571*00b67f09SDavid van Moolenbroek return (ISC_FALSE);
1572*00b67f09SDavid van Moolenbroek *sourceserial = j->header.sourceserial;
1573*00b67f09SDavid van Moolenbroek return (ISC_TRUE);
1574*00b67f09SDavid van Moolenbroek }
1575*00b67f09SDavid van Moolenbroek
1576*00b67f09SDavid van Moolenbroek /**************************************************************************/
1577*00b67f09SDavid van Moolenbroek /*
1578*00b67f09SDavid van Moolenbroek * Iteration support.
1579*00b67f09SDavid van Moolenbroek *
1580*00b67f09SDavid van Moolenbroek * When serving an outgoing IXFR, we transmit a part the journal starting
1581*00b67f09SDavid van Moolenbroek * at the serial number in the IXFR request and ending at the serial
1582*00b67f09SDavid van Moolenbroek * number that is current when the IXFR request arrives. The ending
1583*00b67f09SDavid van Moolenbroek * serial number is not necessarily at the end of the journal:
1584*00b67f09SDavid van Moolenbroek * the journal may grow while the IXFR is in progress, but we stop
1585*00b67f09SDavid van Moolenbroek * when we reach the serial number that was current when the IXFR started.
1586*00b67f09SDavid van Moolenbroek */
1587*00b67f09SDavid van Moolenbroek
1588*00b67f09SDavid van Moolenbroek static isc_result_t read_one_rr(dns_journal_t *j);
1589*00b67f09SDavid van Moolenbroek
1590*00b67f09SDavid van Moolenbroek /*
1591*00b67f09SDavid van Moolenbroek * Make sure the buffer 'b' is has at least 'size' bytes
1592*00b67f09SDavid van Moolenbroek * allocated, and clear it.
1593*00b67f09SDavid van Moolenbroek *
1594*00b67f09SDavid van Moolenbroek * Requires:
1595*00b67f09SDavid van Moolenbroek * Either b->base is NULL, or it points to b->length bytes of memory
1596*00b67f09SDavid van Moolenbroek * previously allocated by isc_mem_get().
1597*00b67f09SDavid van Moolenbroek */
1598*00b67f09SDavid van Moolenbroek
1599*00b67f09SDavid van Moolenbroek static isc_result_t
size_buffer(isc_mem_t * mctx,isc_buffer_t * b,unsigned size)1600*00b67f09SDavid van Moolenbroek size_buffer(isc_mem_t *mctx, isc_buffer_t *b, unsigned size) {
1601*00b67f09SDavid van Moolenbroek if (b->length < size) {
1602*00b67f09SDavid van Moolenbroek void *mem = isc_mem_get(mctx, size);
1603*00b67f09SDavid van Moolenbroek if (mem == NULL)
1604*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
1605*00b67f09SDavid van Moolenbroek if (b->base != NULL)
1606*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, b->base, b->length);
1607*00b67f09SDavid van Moolenbroek b->base = mem;
1608*00b67f09SDavid van Moolenbroek b->length = size;
1609*00b67f09SDavid van Moolenbroek }
1610*00b67f09SDavid van Moolenbroek isc_buffer_clear(b);
1611*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
1612*00b67f09SDavid van Moolenbroek }
1613*00b67f09SDavid van Moolenbroek
1614*00b67f09SDavid van Moolenbroek isc_result_t
dns_journal_iter_init(dns_journal_t * j,isc_uint32_t begin_serial,isc_uint32_t end_serial)1615*00b67f09SDavid van Moolenbroek dns_journal_iter_init(dns_journal_t *j,
1616*00b67f09SDavid van Moolenbroek isc_uint32_t begin_serial, isc_uint32_t end_serial)
1617*00b67f09SDavid van Moolenbroek {
1618*00b67f09SDavid van Moolenbroek isc_result_t result;
1619*00b67f09SDavid van Moolenbroek
1620*00b67f09SDavid van Moolenbroek CHECK(journal_find(j, begin_serial, &j->it.bpos));
1621*00b67f09SDavid van Moolenbroek INSIST(j->it.bpos.serial == begin_serial);
1622*00b67f09SDavid van Moolenbroek
1623*00b67f09SDavid van Moolenbroek CHECK(journal_find(j, end_serial, &j->it.epos));
1624*00b67f09SDavid van Moolenbroek INSIST(j->it.epos.serial == end_serial);
1625*00b67f09SDavid van Moolenbroek
1626*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
1627*00b67f09SDavid van Moolenbroek failure:
1628*00b67f09SDavid van Moolenbroek j->it.result = result;
1629*00b67f09SDavid van Moolenbroek return (j->it.result);
1630*00b67f09SDavid van Moolenbroek }
1631*00b67f09SDavid van Moolenbroek
1632*00b67f09SDavid van Moolenbroek
1633*00b67f09SDavid van Moolenbroek isc_result_t
dns_journal_first_rr(dns_journal_t * j)1634*00b67f09SDavid van Moolenbroek dns_journal_first_rr(dns_journal_t *j) {
1635*00b67f09SDavid van Moolenbroek isc_result_t result;
1636*00b67f09SDavid van Moolenbroek
1637*00b67f09SDavid van Moolenbroek /*
1638*00b67f09SDavid van Moolenbroek * Seek to the beginning of the first transaction we are
1639*00b67f09SDavid van Moolenbroek * interested in.
1640*00b67f09SDavid van Moolenbroek */
1641*00b67f09SDavid van Moolenbroek CHECK(journal_seek(j, j->it.bpos.offset));
1642*00b67f09SDavid van Moolenbroek j->it.current_serial = j->it.bpos.serial;
1643*00b67f09SDavid van Moolenbroek
1644*00b67f09SDavid van Moolenbroek j->it.xsize = 0; /* We have no transaction data yet... */
1645*00b67f09SDavid van Moolenbroek j->it.xpos = 0; /* ...and haven't used any of it. */
1646*00b67f09SDavid van Moolenbroek
1647*00b67f09SDavid van Moolenbroek return (read_one_rr(j));
1648*00b67f09SDavid van Moolenbroek
1649*00b67f09SDavid van Moolenbroek failure:
1650*00b67f09SDavid van Moolenbroek return (result);
1651*00b67f09SDavid van Moolenbroek }
1652*00b67f09SDavid van Moolenbroek
1653*00b67f09SDavid van Moolenbroek static isc_result_t
read_one_rr(dns_journal_t * j)1654*00b67f09SDavid van Moolenbroek read_one_rr(dns_journal_t *j) {
1655*00b67f09SDavid van Moolenbroek isc_result_t result;
1656*00b67f09SDavid van Moolenbroek
1657*00b67f09SDavid van Moolenbroek dns_rdatatype_t rdtype;
1658*00b67f09SDavid van Moolenbroek dns_rdataclass_t rdclass;
1659*00b67f09SDavid van Moolenbroek unsigned int rdlen;
1660*00b67f09SDavid van Moolenbroek isc_uint32_t ttl;
1661*00b67f09SDavid van Moolenbroek journal_xhdr_t xhdr;
1662*00b67f09SDavid van Moolenbroek journal_rrhdr_t rrhdr;
1663*00b67f09SDavid van Moolenbroek
1664*00b67f09SDavid van Moolenbroek INSIST(j->offset <= j->it.epos.offset);
1665*00b67f09SDavid van Moolenbroek if (j->offset == j->it.epos.offset)
1666*00b67f09SDavid van Moolenbroek return (ISC_R_NOMORE);
1667*00b67f09SDavid van Moolenbroek if (j->it.xpos == j->it.xsize) {
1668*00b67f09SDavid van Moolenbroek /*
1669*00b67f09SDavid van Moolenbroek * We are at a transaction boundary.
1670*00b67f09SDavid van Moolenbroek * Read another transaction header.
1671*00b67f09SDavid van Moolenbroek */
1672*00b67f09SDavid van Moolenbroek CHECK(journal_read_xhdr(j, &xhdr));
1673*00b67f09SDavid van Moolenbroek if (xhdr.size == 0) {
1674*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
1675*00b67f09SDavid van Moolenbroek "%s: journal corrupt: empty transaction",
1676*00b67f09SDavid van Moolenbroek j->filename);
1677*00b67f09SDavid van Moolenbroek FAIL(ISC_R_UNEXPECTED);
1678*00b67f09SDavid van Moolenbroek }
1679*00b67f09SDavid van Moolenbroek if (xhdr.serial0 != j->it.current_serial) {
1680*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
1681*00b67f09SDavid van Moolenbroek "%s: journal file corrupt: "
1682*00b67f09SDavid van Moolenbroek "expected serial %u, got %u",
1683*00b67f09SDavid van Moolenbroek j->filename,
1684*00b67f09SDavid van Moolenbroek j->it.current_serial, xhdr.serial0);
1685*00b67f09SDavid van Moolenbroek FAIL(ISC_R_UNEXPECTED);
1686*00b67f09SDavid van Moolenbroek }
1687*00b67f09SDavid van Moolenbroek j->it.xsize = xhdr.size;
1688*00b67f09SDavid van Moolenbroek j->it.xpos = 0;
1689*00b67f09SDavid van Moolenbroek }
1690*00b67f09SDavid van Moolenbroek /*
1691*00b67f09SDavid van Moolenbroek * Read an RR.
1692*00b67f09SDavid van Moolenbroek */
1693*00b67f09SDavid van Moolenbroek CHECK(journal_read_rrhdr(j, &rrhdr));
1694*00b67f09SDavid van Moolenbroek /*
1695*00b67f09SDavid van Moolenbroek * Perform a sanity check on the journal RR size.
1696*00b67f09SDavid van Moolenbroek * The smallest possible RR has a 1-byte owner name
1697*00b67f09SDavid van Moolenbroek * and a 10-byte header. The largest possible
1698*00b67f09SDavid van Moolenbroek * RR has 65535 bytes of data, a header, and a maximum-
1699*00b67f09SDavid van Moolenbroek * size owner name, well below 70 k total.
1700*00b67f09SDavid van Moolenbroek */
1701*00b67f09SDavid van Moolenbroek if (rrhdr.size < 1+10 || rrhdr.size > 70000) {
1702*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
1703*00b67f09SDavid van Moolenbroek "%s: journal corrupt: impossible RR size "
1704*00b67f09SDavid van Moolenbroek "(%d bytes)", j->filename, rrhdr.size);
1705*00b67f09SDavid van Moolenbroek FAIL(ISC_R_UNEXPECTED);
1706*00b67f09SDavid van Moolenbroek }
1707*00b67f09SDavid van Moolenbroek
1708*00b67f09SDavid van Moolenbroek CHECK(size_buffer(j->mctx, &j->it.source, rrhdr.size));
1709*00b67f09SDavid van Moolenbroek CHECK(journal_read(j, j->it.source.base, rrhdr.size));
1710*00b67f09SDavid van Moolenbroek isc_buffer_add(&j->it.source, rrhdr.size);
1711*00b67f09SDavid van Moolenbroek
1712*00b67f09SDavid van Moolenbroek /*
1713*00b67f09SDavid van Moolenbroek * The target buffer is made the same size
1714*00b67f09SDavid van Moolenbroek * as the source buffer, with the assumption that when
1715*00b67f09SDavid van Moolenbroek * no compression in present, the output of dns_*_fromwire()
1716*00b67f09SDavid van Moolenbroek * is no larger than the input.
1717*00b67f09SDavid van Moolenbroek */
1718*00b67f09SDavid van Moolenbroek CHECK(size_buffer(j->mctx, &j->it.target, rrhdr.size));
1719*00b67f09SDavid van Moolenbroek
1720*00b67f09SDavid van Moolenbroek /*
1721*00b67f09SDavid van Moolenbroek * Parse the owner name. We don't know where it
1722*00b67f09SDavid van Moolenbroek * ends yet, so we make the entire "remaining"
1723*00b67f09SDavid van Moolenbroek * part of the buffer "active".
1724*00b67f09SDavid van Moolenbroek */
1725*00b67f09SDavid van Moolenbroek isc_buffer_setactive(&j->it.source,
1726*00b67f09SDavid van Moolenbroek j->it.source.used - j->it.source.current);
1727*00b67f09SDavid van Moolenbroek CHECK(dns_name_fromwire(&j->it.name, &j->it.source,
1728*00b67f09SDavid van Moolenbroek &j->it.dctx, 0, &j->it.target));
1729*00b67f09SDavid van Moolenbroek
1730*00b67f09SDavid van Moolenbroek /*
1731*00b67f09SDavid van Moolenbroek * Check that the RR header is there, and parse it.
1732*00b67f09SDavid van Moolenbroek */
1733*00b67f09SDavid van Moolenbroek if (isc_buffer_remaininglength(&j->it.source) < 10)
1734*00b67f09SDavid van Moolenbroek FAIL(DNS_R_FORMERR);
1735*00b67f09SDavid van Moolenbroek
1736*00b67f09SDavid van Moolenbroek rdtype = isc_buffer_getuint16(&j->it.source);
1737*00b67f09SDavid van Moolenbroek rdclass = isc_buffer_getuint16(&j->it.source);
1738*00b67f09SDavid van Moolenbroek ttl = isc_buffer_getuint32(&j->it.source);
1739*00b67f09SDavid van Moolenbroek rdlen = isc_buffer_getuint16(&j->it.source);
1740*00b67f09SDavid van Moolenbroek
1741*00b67f09SDavid van Moolenbroek /*
1742*00b67f09SDavid van Moolenbroek * Parse the rdata.
1743*00b67f09SDavid van Moolenbroek */
1744*00b67f09SDavid van Moolenbroek if (isc_buffer_remaininglength(&j->it.source) != rdlen)
1745*00b67f09SDavid van Moolenbroek FAIL(DNS_R_FORMERR);
1746*00b67f09SDavid van Moolenbroek isc_buffer_setactive(&j->it.source, rdlen);
1747*00b67f09SDavid van Moolenbroek dns_rdata_reset(&j->it.rdata);
1748*00b67f09SDavid van Moolenbroek CHECK(dns_rdata_fromwire(&j->it.rdata, rdclass,
1749*00b67f09SDavid van Moolenbroek rdtype, &j->it.source, &j->it.dctx,
1750*00b67f09SDavid van Moolenbroek 0, &j->it.target));
1751*00b67f09SDavid van Moolenbroek j->it.ttl = ttl;
1752*00b67f09SDavid van Moolenbroek
1753*00b67f09SDavid van Moolenbroek j->it.xpos += sizeof(journal_rawrrhdr_t) + rrhdr.size;
1754*00b67f09SDavid van Moolenbroek if (rdtype == dns_rdatatype_soa) {
1755*00b67f09SDavid van Moolenbroek /* XXX could do additional consistency checks here */
1756*00b67f09SDavid van Moolenbroek j->it.current_serial = dns_soa_getserial(&j->it.rdata);
1757*00b67f09SDavid van Moolenbroek }
1758*00b67f09SDavid van Moolenbroek
1759*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
1760*00b67f09SDavid van Moolenbroek
1761*00b67f09SDavid van Moolenbroek failure:
1762*00b67f09SDavid van Moolenbroek j->it.result = result;
1763*00b67f09SDavid van Moolenbroek return (result);
1764*00b67f09SDavid van Moolenbroek }
1765*00b67f09SDavid van Moolenbroek
1766*00b67f09SDavid van Moolenbroek isc_result_t
dns_journal_next_rr(dns_journal_t * j)1767*00b67f09SDavid van Moolenbroek dns_journal_next_rr(dns_journal_t *j) {
1768*00b67f09SDavid van Moolenbroek j->it.result = read_one_rr(j);
1769*00b67f09SDavid van Moolenbroek return (j->it.result);
1770*00b67f09SDavid van Moolenbroek }
1771*00b67f09SDavid van Moolenbroek
1772*00b67f09SDavid van Moolenbroek void
dns_journal_current_rr(dns_journal_t * j,dns_name_t ** name,isc_uint32_t * ttl,dns_rdata_t ** rdata)1773*00b67f09SDavid van Moolenbroek dns_journal_current_rr(dns_journal_t *j, dns_name_t **name, isc_uint32_t *ttl,
1774*00b67f09SDavid van Moolenbroek dns_rdata_t **rdata)
1775*00b67f09SDavid van Moolenbroek {
1776*00b67f09SDavid van Moolenbroek REQUIRE(j->it.result == ISC_R_SUCCESS);
1777*00b67f09SDavid van Moolenbroek *name = &j->it.name;
1778*00b67f09SDavid van Moolenbroek *ttl = j->it.ttl;
1779*00b67f09SDavid van Moolenbroek *rdata = &j->it.rdata;
1780*00b67f09SDavid van Moolenbroek }
1781*00b67f09SDavid van Moolenbroek
1782*00b67f09SDavid van Moolenbroek /**************************************************************************/
1783*00b67f09SDavid van Moolenbroek /*
1784*00b67f09SDavid van Moolenbroek * Generating diffs from databases
1785*00b67f09SDavid van Moolenbroek */
1786*00b67f09SDavid van Moolenbroek
1787*00b67f09SDavid van Moolenbroek /*
1788*00b67f09SDavid van Moolenbroek * Construct a diff containing all the RRs at the current name of the
1789*00b67f09SDavid van Moolenbroek * database iterator 'dbit' in database 'db', version 'ver'.
1790*00b67f09SDavid van Moolenbroek * Set '*name' to the current name, and append the diff to 'diff'.
1791*00b67f09SDavid van Moolenbroek * All new tuples will have the operation 'op'.
1792*00b67f09SDavid van Moolenbroek *
1793*00b67f09SDavid van Moolenbroek * Requires: 'name' must have buffer large enough to hold the name.
1794*00b67f09SDavid van Moolenbroek * Typically, a dns_fixedname_t would be used.
1795*00b67f09SDavid van Moolenbroek */
1796*00b67f09SDavid van Moolenbroek static isc_result_t
get_name_diff(dns_db_t * db,dns_dbversion_t * ver,isc_stdtime_t now,dns_dbiterator_t * dbit,dns_name_t * name,dns_diffop_t op,dns_diff_t * diff)1797*00b67f09SDavid van Moolenbroek get_name_diff(dns_db_t *db, dns_dbversion_t *ver, isc_stdtime_t now,
1798*00b67f09SDavid van Moolenbroek dns_dbiterator_t *dbit, dns_name_t *name, dns_diffop_t op,
1799*00b67f09SDavid van Moolenbroek dns_diff_t *diff)
1800*00b67f09SDavid van Moolenbroek {
1801*00b67f09SDavid van Moolenbroek isc_result_t result;
1802*00b67f09SDavid van Moolenbroek dns_dbnode_t *node = NULL;
1803*00b67f09SDavid van Moolenbroek dns_rdatasetiter_t *rdsiter = NULL;
1804*00b67f09SDavid van Moolenbroek dns_difftuple_t *tuple = NULL;
1805*00b67f09SDavid van Moolenbroek
1806*00b67f09SDavid van Moolenbroek result = dns_dbiterator_current(dbit, &node, name);
1807*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
1808*00b67f09SDavid van Moolenbroek return (result);
1809*00b67f09SDavid van Moolenbroek
1810*00b67f09SDavid van Moolenbroek result = dns_db_allrdatasets(db, node, ver, now, &rdsiter);
1811*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
1812*00b67f09SDavid van Moolenbroek goto cleanup_node;
1813*00b67f09SDavid van Moolenbroek
1814*00b67f09SDavid van Moolenbroek for (result = dns_rdatasetiter_first(rdsiter);
1815*00b67f09SDavid van Moolenbroek result == ISC_R_SUCCESS;
1816*00b67f09SDavid van Moolenbroek result = dns_rdatasetiter_next(rdsiter))
1817*00b67f09SDavid van Moolenbroek {
1818*00b67f09SDavid van Moolenbroek dns_rdataset_t rdataset;
1819*00b67f09SDavid van Moolenbroek
1820*00b67f09SDavid van Moolenbroek dns_rdataset_init(&rdataset);
1821*00b67f09SDavid van Moolenbroek dns_rdatasetiter_current(rdsiter, &rdataset);
1822*00b67f09SDavid van Moolenbroek
1823*00b67f09SDavid van Moolenbroek for (result = dns_rdataset_first(&rdataset);
1824*00b67f09SDavid van Moolenbroek result == ISC_R_SUCCESS;
1825*00b67f09SDavid van Moolenbroek result = dns_rdataset_next(&rdataset))
1826*00b67f09SDavid van Moolenbroek {
1827*00b67f09SDavid van Moolenbroek dns_rdata_t rdata = DNS_RDATA_INIT;
1828*00b67f09SDavid van Moolenbroek dns_rdataset_current(&rdataset, &rdata);
1829*00b67f09SDavid van Moolenbroek result = dns_difftuple_create(diff->mctx, op, name,
1830*00b67f09SDavid van Moolenbroek rdataset.ttl, &rdata,
1831*00b67f09SDavid van Moolenbroek &tuple);
1832*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
1833*00b67f09SDavid van Moolenbroek dns_rdataset_disassociate(&rdataset);
1834*00b67f09SDavid van Moolenbroek goto cleanup_iterator;
1835*00b67f09SDavid van Moolenbroek }
1836*00b67f09SDavid van Moolenbroek dns_diff_append(diff, &tuple);
1837*00b67f09SDavid van Moolenbroek }
1838*00b67f09SDavid van Moolenbroek dns_rdataset_disassociate(&rdataset);
1839*00b67f09SDavid van Moolenbroek if (result != ISC_R_NOMORE)
1840*00b67f09SDavid van Moolenbroek goto cleanup_iterator;
1841*00b67f09SDavid van Moolenbroek }
1842*00b67f09SDavid van Moolenbroek if (result != ISC_R_NOMORE)
1843*00b67f09SDavid van Moolenbroek goto cleanup_iterator;
1844*00b67f09SDavid van Moolenbroek
1845*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
1846*00b67f09SDavid van Moolenbroek
1847*00b67f09SDavid van Moolenbroek cleanup_iterator:
1848*00b67f09SDavid van Moolenbroek dns_rdatasetiter_destroy(&rdsiter);
1849*00b67f09SDavid van Moolenbroek
1850*00b67f09SDavid van Moolenbroek cleanup_node:
1851*00b67f09SDavid van Moolenbroek dns_db_detachnode(db, &node);
1852*00b67f09SDavid van Moolenbroek
1853*00b67f09SDavid van Moolenbroek return (result);
1854*00b67f09SDavid van Moolenbroek }
1855*00b67f09SDavid van Moolenbroek
1856*00b67f09SDavid van Moolenbroek /*
1857*00b67f09SDavid van Moolenbroek * Comparison function for use by dns_diff_subtract when sorting
1858*00b67f09SDavid van Moolenbroek * the diffs to be subtracted. The sort keys are the rdata type
1859*00b67f09SDavid van Moolenbroek * and the rdata itself. The owner name is ignored, because
1860*00b67f09SDavid van Moolenbroek * it is known to be the same for all tuples.
1861*00b67f09SDavid van Moolenbroek */
1862*00b67f09SDavid van Moolenbroek static int
rdata_order(const void * av,const void * bv)1863*00b67f09SDavid van Moolenbroek rdata_order(const void *av, const void *bv) {
1864*00b67f09SDavid van Moolenbroek dns_difftuple_t const * const *ap = av;
1865*00b67f09SDavid van Moolenbroek dns_difftuple_t const * const *bp = bv;
1866*00b67f09SDavid van Moolenbroek dns_difftuple_t const *a = *ap;
1867*00b67f09SDavid van Moolenbroek dns_difftuple_t const *b = *bp;
1868*00b67f09SDavid van Moolenbroek int r;
1869*00b67f09SDavid van Moolenbroek r = (b->rdata.type - a->rdata.type);
1870*00b67f09SDavid van Moolenbroek if (r != 0)
1871*00b67f09SDavid van Moolenbroek return (r);
1872*00b67f09SDavid van Moolenbroek r = dns_rdata_compare(&a->rdata, &b->rdata);
1873*00b67f09SDavid van Moolenbroek return (r);
1874*00b67f09SDavid van Moolenbroek }
1875*00b67f09SDavid van Moolenbroek
1876*00b67f09SDavid van Moolenbroek static isc_result_t
dns_diff_subtract(dns_diff_t diff[2],dns_diff_t * r)1877*00b67f09SDavid van Moolenbroek dns_diff_subtract(dns_diff_t diff[2], dns_diff_t *r) {
1878*00b67f09SDavid van Moolenbroek isc_result_t result;
1879*00b67f09SDavid van Moolenbroek dns_difftuple_t *p[2];
1880*00b67f09SDavid van Moolenbroek int i, t;
1881*00b67f09SDavid van Moolenbroek isc_boolean_t append;
1882*00b67f09SDavid van Moolenbroek
1883*00b67f09SDavid van Moolenbroek CHECK(dns_diff_sort(&diff[0], rdata_order));
1884*00b67f09SDavid van Moolenbroek CHECK(dns_diff_sort(&diff[1], rdata_order));
1885*00b67f09SDavid van Moolenbroek
1886*00b67f09SDavid van Moolenbroek for (;;) {
1887*00b67f09SDavid van Moolenbroek p[0] = ISC_LIST_HEAD(diff[0].tuples);
1888*00b67f09SDavid van Moolenbroek p[1] = ISC_LIST_HEAD(diff[1].tuples);
1889*00b67f09SDavid van Moolenbroek if (p[0] == NULL && p[1] == NULL)
1890*00b67f09SDavid van Moolenbroek break;
1891*00b67f09SDavid van Moolenbroek
1892*00b67f09SDavid van Moolenbroek for (i = 0; i < 2; i++)
1893*00b67f09SDavid van Moolenbroek if (p[!i] == NULL) {
1894*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(diff[i].tuples, p[i], link);
1895*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(r->tuples, p[i], link);
1896*00b67f09SDavid van Moolenbroek goto next;
1897*00b67f09SDavid van Moolenbroek }
1898*00b67f09SDavid van Moolenbroek t = rdata_order(&p[0], &p[1]);
1899*00b67f09SDavid van Moolenbroek if (t < 0) {
1900*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(diff[0].tuples, p[0], link);
1901*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(r->tuples, p[0], link);
1902*00b67f09SDavid van Moolenbroek goto next;
1903*00b67f09SDavid van Moolenbroek }
1904*00b67f09SDavid van Moolenbroek if (t > 0) {
1905*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(diff[1].tuples, p[1], link);
1906*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(r->tuples, p[1], link);
1907*00b67f09SDavid van Moolenbroek goto next;
1908*00b67f09SDavid van Moolenbroek }
1909*00b67f09SDavid van Moolenbroek INSIST(t == 0);
1910*00b67f09SDavid van Moolenbroek /*
1911*00b67f09SDavid van Moolenbroek * Identical RRs in both databases; skip them both
1912*00b67f09SDavid van Moolenbroek * if the ttl differs.
1913*00b67f09SDavid van Moolenbroek */
1914*00b67f09SDavid van Moolenbroek append = ISC_TF(p[0]->ttl != p[1]->ttl);
1915*00b67f09SDavid van Moolenbroek for (i = 0; i < 2; i++) {
1916*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(diff[i].tuples, p[i], link);
1917*00b67f09SDavid van Moolenbroek if (append) {
1918*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(r->tuples, p[i], link);
1919*00b67f09SDavid van Moolenbroek } else {
1920*00b67f09SDavid van Moolenbroek dns_difftuple_free(&p[i]);
1921*00b67f09SDavid van Moolenbroek }
1922*00b67f09SDavid van Moolenbroek }
1923*00b67f09SDavid van Moolenbroek next: ;
1924*00b67f09SDavid van Moolenbroek }
1925*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
1926*00b67f09SDavid van Moolenbroek failure:
1927*00b67f09SDavid van Moolenbroek return (result);
1928*00b67f09SDavid van Moolenbroek }
1929*00b67f09SDavid van Moolenbroek
1930*00b67f09SDavid van Moolenbroek static isc_result_t
diff_namespace(dns_db_t * dba,dns_dbversion_t * dbvera,dns_db_t * dbb,dns_dbversion_t * dbverb,unsigned int options,dns_diff_t * resultdiff)1931*00b67f09SDavid van Moolenbroek diff_namespace(dns_db_t *dba, dns_dbversion_t *dbvera,
1932*00b67f09SDavid van Moolenbroek dns_db_t *dbb, dns_dbversion_t *dbverb,
1933*00b67f09SDavid van Moolenbroek unsigned int options, dns_diff_t *resultdiff)
1934*00b67f09SDavid van Moolenbroek {
1935*00b67f09SDavid van Moolenbroek dns_db_t *db[2];
1936*00b67f09SDavid van Moolenbroek dns_dbversion_t *ver[2];
1937*00b67f09SDavid van Moolenbroek dns_dbiterator_t *dbit[2] = { NULL, NULL };
1938*00b67f09SDavid van Moolenbroek isc_boolean_t have[2] = { ISC_FALSE, ISC_FALSE };
1939*00b67f09SDavid van Moolenbroek dns_fixedname_t fixname[2];
1940*00b67f09SDavid van Moolenbroek isc_result_t result, itresult[2];
1941*00b67f09SDavid van Moolenbroek dns_diff_t diff[2];
1942*00b67f09SDavid van Moolenbroek int i, t;
1943*00b67f09SDavid van Moolenbroek
1944*00b67f09SDavid van Moolenbroek db[0] = dba, db[1] = dbb;
1945*00b67f09SDavid van Moolenbroek ver[0] = dbvera, ver[1] = dbverb;
1946*00b67f09SDavid van Moolenbroek
1947*00b67f09SDavid van Moolenbroek dns_diff_init(resultdiff->mctx, &diff[0]);
1948*00b67f09SDavid van Moolenbroek dns_diff_init(resultdiff->mctx, &diff[1]);
1949*00b67f09SDavid van Moolenbroek
1950*00b67f09SDavid van Moolenbroek dns_fixedname_init(&fixname[0]);
1951*00b67f09SDavid van Moolenbroek dns_fixedname_init(&fixname[1]);
1952*00b67f09SDavid van Moolenbroek
1953*00b67f09SDavid van Moolenbroek result = dns_db_createiterator(db[0], options, &dbit[0]);
1954*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
1955*00b67f09SDavid van Moolenbroek return (result);
1956*00b67f09SDavid van Moolenbroek result = dns_db_createiterator(db[1], options, &dbit[1]);
1957*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
1958*00b67f09SDavid van Moolenbroek goto cleanup_iterator;
1959*00b67f09SDavid van Moolenbroek
1960*00b67f09SDavid van Moolenbroek itresult[0] = dns_dbiterator_first(dbit[0]);
1961*00b67f09SDavid van Moolenbroek itresult[1] = dns_dbiterator_first(dbit[1]);
1962*00b67f09SDavid van Moolenbroek
1963*00b67f09SDavid van Moolenbroek for (;;) {
1964*00b67f09SDavid van Moolenbroek for (i = 0; i < 2; i++) {
1965*00b67f09SDavid van Moolenbroek if (! have[i] && itresult[i] == ISC_R_SUCCESS) {
1966*00b67f09SDavid van Moolenbroek CHECK(get_name_diff(db[i], ver[i], 0, dbit[i],
1967*00b67f09SDavid van Moolenbroek dns_fixedname_name(&fixname[i]),
1968*00b67f09SDavid van Moolenbroek i == 0 ?
1969*00b67f09SDavid van Moolenbroek DNS_DIFFOP_ADD :
1970*00b67f09SDavid van Moolenbroek DNS_DIFFOP_DEL,
1971*00b67f09SDavid van Moolenbroek &diff[i]));
1972*00b67f09SDavid van Moolenbroek itresult[i] = dns_dbiterator_next(dbit[i]);
1973*00b67f09SDavid van Moolenbroek have[i] = ISC_TRUE;
1974*00b67f09SDavid van Moolenbroek }
1975*00b67f09SDavid van Moolenbroek }
1976*00b67f09SDavid van Moolenbroek
1977*00b67f09SDavid van Moolenbroek if (! have[0] && ! have[1]) {
1978*00b67f09SDavid van Moolenbroek INSIST(ISC_LIST_EMPTY(diff[0].tuples));
1979*00b67f09SDavid van Moolenbroek INSIST(ISC_LIST_EMPTY(diff[1].tuples));
1980*00b67f09SDavid van Moolenbroek break;
1981*00b67f09SDavid van Moolenbroek }
1982*00b67f09SDavid van Moolenbroek
1983*00b67f09SDavid van Moolenbroek for (i = 0; i < 2; i++) {
1984*00b67f09SDavid van Moolenbroek if (! have[!i]) {
1985*00b67f09SDavid van Moolenbroek ISC_LIST_APPENDLIST(resultdiff->tuples,
1986*00b67f09SDavid van Moolenbroek diff[i].tuples, link);
1987*00b67f09SDavid van Moolenbroek INSIST(ISC_LIST_EMPTY(diff[i].tuples));
1988*00b67f09SDavid van Moolenbroek have[i] = ISC_FALSE;
1989*00b67f09SDavid van Moolenbroek goto next;
1990*00b67f09SDavid van Moolenbroek }
1991*00b67f09SDavid van Moolenbroek }
1992*00b67f09SDavid van Moolenbroek
1993*00b67f09SDavid van Moolenbroek t = dns_name_compare(dns_fixedname_name(&fixname[0]),
1994*00b67f09SDavid van Moolenbroek dns_fixedname_name(&fixname[1]));
1995*00b67f09SDavid van Moolenbroek if (t < 0) {
1996*00b67f09SDavid van Moolenbroek ISC_LIST_APPENDLIST(resultdiff->tuples,
1997*00b67f09SDavid van Moolenbroek diff[0].tuples, link);
1998*00b67f09SDavid van Moolenbroek INSIST(ISC_LIST_EMPTY(diff[0].tuples));
1999*00b67f09SDavid van Moolenbroek have[0] = ISC_FALSE;
2000*00b67f09SDavid van Moolenbroek continue;
2001*00b67f09SDavid van Moolenbroek }
2002*00b67f09SDavid van Moolenbroek if (t > 0) {
2003*00b67f09SDavid van Moolenbroek ISC_LIST_APPENDLIST(resultdiff->tuples,
2004*00b67f09SDavid van Moolenbroek diff[1].tuples, link);
2005*00b67f09SDavid van Moolenbroek INSIST(ISC_LIST_EMPTY(diff[1].tuples));
2006*00b67f09SDavid van Moolenbroek have[1] = ISC_FALSE;
2007*00b67f09SDavid van Moolenbroek continue;
2008*00b67f09SDavid van Moolenbroek }
2009*00b67f09SDavid van Moolenbroek INSIST(t == 0);
2010*00b67f09SDavid van Moolenbroek CHECK(dns_diff_subtract(diff, resultdiff));
2011*00b67f09SDavid van Moolenbroek INSIST(ISC_LIST_EMPTY(diff[0].tuples));
2012*00b67f09SDavid van Moolenbroek INSIST(ISC_LIST_EMPTY(diff[1].tuples));
2013*00b67f09SDavid van Moolenbroek have[0] = have[1] = ISC_FALSE;
2014*00b67f09SDavid van Moolenbroek next: ;
2015*00b67f09SDavid van Moolenbroek }
2016*00b67f09SDavid van Moolenbroek if (itresult[0] != ISC_R_NOMORE)
2017*00b67f09SDavid van Moolenbroek FAIL(itresult[0]);
2018*00b67f09SDavid van Moolenbroek if (itresult[1] != ISC_R_NOMORE)
2019*00b67f09SDavid van Moolenbroek FAIL(itresult[1]);
2020*00b67f09SDavid van Moolenbroek
2021*00b67f09SDavid van Moolenbroek INSIST(ISC_LIST_EMPTY(diff[0].tuples));
2022*00b67f09SDavid van Moolenbroek INSIST(ISC_LIST_EMPTY(diff[1].tuples));
2023*00b67f09SDavid van Moolenbroek
2024*00b67f09SDavid van Moolenbroek failure:
2025*00b67f09SDavid van Moolenbroek dns_dbiterator_destroy(&dbit[1]);
2026*00b67f09SDavid van Moolenbroek
2027*00b67f09SDavid van Moolenbroek cleanup_iterator:
2028*00b67f09SDavid van Moolenbroek dns_dbiterator_destroy(&dbit[0]);
2029*00b67f09SDavid van Moolenbroek dns_diff_clear(&diff[0]);
2030*00b67f09SDavid van Moolenbroek dns_diff_clear(&diff[1]);
2031*00b67f09SDavid van Moolenbroek return (result);
2032*00b67f09SDavid van Moolenbroek }
2033*00b67f09SDavid van Moolenbroek
2034*00b67f09SDavid van Moolenbroek /*
2035*00b67f09SDavid van Moolenbroek * Compare the databases 'dba' and 'dbb' and generate a journal
2036*00b67f09SDavid van Moolenbroek * entry containing the changes to make 'dba' from 'dbb' (note
2037*00b67f09SDavid van Moolenbroek * the order). This journal entry will consist of a single,
2038*00b67f09SDavid van Moolenbroek * possibly very large transaction.
2039*00b67f09SDavid van Moolenbroek */
2040*00b67f09SDavid van Moolenbroek isc_result_t
dns_db_diff(isc_mem_t * mctx,dns_db_t * dba,dns_dbversion_t * dbvera,dns_db_t * dbb,dns_dbversion_t * dbverb,const char * filename)2041*00b67f09SDavid van Moolenbroek dns_db_diff(isc_mem_t *mctx, dns_db_t *dba, dns_dbversion_t *dbvera,
2042*00b67f09SDavid van Moolenbroek dns_db_t *dbb, dns_dbversion_t *dbverb, const char *filename)
2043*00b67f09SDavid van Moolenbroek {
2044*00b67f09SDavid van Moolenbroek isc_result_t result;
2045*00b67f09SDavid van Moolenbroek dns_diff_t diff;
2046*00b67f09SDavid van Moolenbroek
2047*00b67f09SDavid van Moolenbroek dns_diff_init(mctx, &diff);
2048*00b67f09SDavid van Moolenbroek
2049*00b67f09SDavid van Moolenbroek result = dns_db_diffx(&diff, dba, dbvera, dbb, dbverb, filename);
2050*00b67f09SDavid van Moolenbroek
2051*00b67f09SDavid van Moolenbroek dns_diff_clear(&diff);
2052*00b67f09SDavid van Moolenbroek
2053*00b67f09SDavid van Moolenbroek return (result);
2054*00b67f09SDavid van Moolenbroek }
2055*00b67f09SDavid van Moolenbroek
2056*00b67f09SDavid van Moolenbroek isc_result_t
dns_db_diffx(dns_diff_t * diff,dns_db_t * dba,dns_dbversion_t * dbvera,dns_db_t * dbb,dns_dbversion_t * dbverb,const char * filename)2057*00b67f09SDavid van Moolenbroek dns_db_diffx(dns_diff_t *diff, dns_db_t *dba, dns_dbversion_t *dbvera,
2058*00b67f09SDavid van Moolenbroek dns_db_t *dbb, dns_dbversion_t *dbverb, const char *filename)
2059*00b67f09SDavid van Moolenbroek {
2060*00b67f09SDavid van Moolenbroek isc_result_t result;
2061*00b67f09SDavid van Moolenbroek dns_journal_t *journal = NULL;
2062*00b67f09SDavid van Moolenbroek
2063*00b67f09SDavid van Moolenbroek if (filename != NULL) {
2064*00b67f09SDavid van Moolenbroek result = dns_journal_open(diff->mctx, filename,
2065*00b67f09SDavid van Moolenbroek DNS_JOURNAL_CREATE, &journal);
2066*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
2067*00b67f09SDavid van Moolenbroek return (result);
2068*00b67f09SDavid van Moolenbroek }
2069*00b67f09SDavid van Moolenbroek
2070*00b67f09SDavid van Moolenbroek CHECK(diff_namespace(dba, dbvera, dbb, dbverb, DNS_DB_NONSEC3, diff));
2071*00b67f09SDavid van Moolenbroek CHECK(diff_namespace(dba, dbvera, dbb, dbverb, DNS_DB_NSEC3ONLY, diff));
2072*00b67f09SDavid van Moolenbroek
2073*00b67f09SDavid van Moolenbroek if (journal != NULL) {
2074*00b67f09SDavid van Moolenbroek if (ISC_LIST_EMPTY(diff->tuples))
2075*00b67f09SDavid van Moolenbroek isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no changes");
2076*00b67f09SDavid van Moolenbroek else
2077*00b67f09SDavid van Moolenbroek CHECK(dns_journal_write_transaction(journal, diff));
2078*00b67f09SDavid van Moolenbroek }
2079*00b67f09SDavid van Moolenbroek
2080*00b67f09SDavid van Moolenbroek failure:
2081*00b67f09SDavid van Moolenbroek if (journal != NULL)
2082*00b67f09SDavid van Moolenbroek dns_journal_destroy(&journal);
2083*00b67f09SDavid van Moolenbroek return (result);
2084*00b67f09SDavid van Moolenbroek }
2085*00b67f09SDavid van Moolenbroek
2086*00b67f09SDavid van Moolenbroek isc_result_t
dns_journal_compact(isc_mem_t * mctx,char * filename,isc_uint32_t serial,isc_uint32_t target_size)2087*00b67f09SDavid van Moolenbroek dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
2088*00b67f09SDavid van Moolenbroek isc_uint32_t target_size)
2089*00b67f09SDavid van Moolenbroek {
2090*00b67f09SDavid van Moolenbroek unsigned int i;
2091*00b67f09SDavid van Moolenbroek journal_pos_t best_guess;
2092*00b67f09SDavid van Moolenbroek journal_pos_t current_pos;
2093*00b67f09SDavid van Moolenbroek dns_journal_t *j = NULL;
2094*00b67f09SDavid van Moolenbroek dns_journal_t *new = NULL;
2095*00b67f09SDavid van Moolenbroek journal_rawheader_t rawheader;
2096*00b67f09SDavid van Moolenbroek unsigned int copy_length;
2097*00b67f09SDavid van Moolenbroek size_t namelen;
2098*00b67f09SDavid van Moolenbroek char *buf = NULL;
2099*00b67f09SDavid van Moolenbroek unsigned int size = 0;
2100*00b67f09SDavid van Moolenbroek isc_result_t result;
2101*00b67f09SDavid van Moolenbroek unsigned int indexend;
2102*00b67f09SDavid van Moolenbroek char newname[1024];
2103*00b67f09SDavid van Moolenbroek char backup[1024];
2104*00b67f09SDavid van Moolenbroek isc_boolean_t is_backup = ISC_FALSE;
2105*00b67f09SDavid van Moolenbroek
2106*00b67f09SDavid van Moolenbroek namelen = strlen(filename);
2107*00b67f09SDavid van Moolenbroek if (namelen > 4U && strcmp(filename + namelen - 4, ".jnl") == 0)
2108*00b67f09SDavid van Moolenbroek namelen -= 4;
2109*00b67f09SDavid van Moolenbroek
2110*00b67f09SDavid van Moolenbroek result = isc_string_printf(newname, sizeof(newname), "%.*s.jnw",
2111*00b67f09SDavid van Moolenbroek (int)namelen, filename);
2112*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
2113*00b67f09SDavid van Moolenbroek return (result);
2114*00b67f09SDavid van Moolenbroek
2115*00b67f09SDavid van Moolenbroek result = isc_string_printf(backup, sizeof(backup), "%.*s.jbk",
2116*00b67f09SDavid van Moolenbroek (int)namelen, filename);
2117*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
2118*00b67f09SDavid van Moolenbroek return (result);
2119*00b67f09SDavid van Moolenbroek
2120*00b67f09SDavid van Moolenbroek result = journal_open(mctx, filename, ISC_FALSE, ISC_FALSE, &j);
2121*00b67f09SDavid van Moolenbroek if (result == ISC_R_NOTFOUND) {
2122*00b67f09SDavid van Moolenbroek is_backup = ISC_TRUE;
2123*00b67f09SDavid van Moolenbroek result = journal_open(mctx, backup, ISC_FALSE, ISC_FALSE, &j);
2124*00b67f09SDavid van Moolenbroek }
2125*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
2126*00b67f09SDavid van Moolenbroek return (result);
2127*00b67f09SDavid van Moolenbroek
2128*00b67f09SDavid van Moolenbroek if (JOURNAL_EMPTY(&j->header)) {
2129*00b67f09SDavid van Moolenbroek dns_journal_destroy(&j);
2130*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
2131*00b67f09SDavid van Moolenbroek }
2132*00b67f09SDavid van Moolenbroek
2133*00b67f09SDavid van Moolenbroek if (DNS_SERIAL_GT(j->header.begin.serial, serial) ||
2134*00b67f09SDavid van Moolenbroek DNS_SERIAL_GT(serial, j->header.end.serial)) {
2135*00b67f09SDavid van Moolenbroek dns_journal_destroy(&j);
2136*00b67f09SDavid van Moolenbroek return (ISC_R_RANGE);
2137*00b67f09SDavid van Moolenbroek }
2138*00b67f09SDavid van Moolenbroek
2139*00b67f09SDavid van Moolenbroek /*
2140*00b67f09SDavid van Moolenbroek * Cope with very small target sizes.
2141*00b67f09SDavid van Moolenbroek */
2142*00b67f09SDavid van Moolenbroek indexend = sizeof(journal_rawheader_t) +
2143*00b67f09SDavid van Moolenbroek j->header.index_size * sizeof(journal_rawpos_t);
2144*00b67f09SDavid van Moolenbroek if (target_size < indexend * 2)
2145*00b67f09SDavid van Moolenbroek target_size = target_size/2 + indexend;
2146*00b67f09SDavid van Moolenbroek
2147*00b67f09SDavid van Moolenbroek /*
2148*00b67f09SDavid van Moolenbroek * See if there is any work to do.
2149*00b67f09SDavid van Moolenbroek */
2150*00b67f09SDavid van Moolenbroek if ((isc_uint32_t) j->header.end.offset < target_size) {
2151*00b67f09SDavid van Moolenbroek dns_journal_destroy(&j);
2152*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
2153*00b67f09SDavid van Moolenbroek }
2154*00b67f09SDavid van Moolenbroek
2155*00b67f09SDavid van Moolenbroek CHECK(journal_open(mctx, newname, ISC_TRUE, ISC_TRUE, &new));
2156*00b67f09SDavid van Moolenbroek
2157*00b67f09SDavid van Moolenbroek /*
2158*00b67f09SDavid van Moolenbroek * Remove overhead so space test below can succeed.
2159*00b67f09SDavid van Moolenbroek */
2160*00b67f09SDavid van Moolenbroek if (target_size >= indexend)
2161*00b67f09SDavid van Moolenbroek target_size -= indexend;
2162*00b67f09SDavid van Moolenbroek
2163*00b67f09SDavid van Moolenbroek /*
2164*00b67f09SDavid van Moolenbroek * Find if we can create enough free space.
2165*00b67f09SDavid van Moolenbroek */
2166*00b67f09SDavid van Moolenbroek best_guess = j->header.begin;
2167*00b67f09SDavid van Moolenbroek for (i = 0; i < j->header.index_size; i++) {
2168*00b67f09SDavid van Moolenbroek if (POS_VALID(j->index[i]) &&
2169*00b67f09SDavid van Moolenbroek DNS_SERIAL_GE(serial, j->index[i].serial) &&
2170*00b67f09SDavid van Moolenbroek ((isc_uint32_t)(j->header.end.offset - j->index[i].offset)
2171*00b67f09SDavid van Moolenbroek >= target_size / 2) &&
2172*00b67f09SDavid van Moolenbroek j->index[i].offset > best_guess.offset)
2173*00b67f09SDavid van Moolenbroek best_guess = j->index[i];
2174*00b67f09SDavid van Moolenbroek }
2175*00b67f09SDavid van Moolenbroek
2176*00b67f09SDavid van Moolenbroek current_pos = best_guess;
2177*00b67f09SDavid van Moolenbroek while (current_pos.serial != serial) {
2178*00b67f09SDavid van Moolenbroek CHECK(journal_next(j, ¤t_pos));
2179*00b67f09SDavid van Moolenbroek if (current_pos.serial == j->header.end.serial)
2180*00b67f09SDavid van Moolenbroek break;
2181*00b67f09SDavid van Moolenbroek
2182*00b67f09SDavid van Moolenbroek if (DNS_SERIAL_GE(serial, current_pos.serial) &&
2183*00b67f09SDavid van Moolenbroek ((isc_uint32_t)(j->header.end.offset - current_pos.offset)
2184*00b67f09SDavid van Moolenbroek >= (target_size / 2)) &&
2185*00b67f09SDavid van Moolenbroek current_pos.offset > best_guess.offset)
2186*00b67f09SDavid van Moolenbroek best_guess = current_pos;
2187*00b67f09SDavid van Moolenbroek else
2188*00b67f09SDavid van Moolenbroek break;
2189*00b67f09SDavid van Moolenbroek }
2190*00b67f09SDavid van Moolenbroek
2191*00b67f09SDavid van Moolenbroek INSIST(best_guess.serial != j->header.end.serial);
2192*00b67f09SDavid van Moolenbroek if (best_guess.serial != serial)
2193*00b67f09SDavid van Moolenbroek CHECK(journal_next(j, &best_guess));
2194*00b67f09SDavid van Moolenbroek
2195*00b67f09SDavid van Moolenbroek /*
2196*00b67f09SDavid van Moolenbroek * We should now be roughly half target_size provided
2197*00b67f09SDavid van Moolenbroek * we did not reach 'serial'. If not we will just copy
2198*00b67f09SDavid van Moolenbroek * all uncommitted deltas regardless of the size.
2199*00b67f09SDavid van Moolenbroek */
2200*00b67f09SDavid van Moolenbroek copy_length = j->header.end.offset - best_guess.offset;
2201*00b67f09SDavid van Moolenbroek
2202*00b67f09SDavid van Moolenbroek if (copy_length != 0) {
2203*00b67f09SDavid van Moolenbroek /*
2204*00b67f09SDavid van Moolenbroek * Copy best_guess to end into space just freed.
2205*00b67f09SDavid van Moolenbroek */
2206*00b67f09SDavid van Moolenbroek size = 64*1024;
2207*00b67f09SDavid van Moolenbroek if (copy_length < size)
2208*00b67f09SDavid van Moolenbroek size = copy_length;
2209*00b67f09SDavid van Moolenbroek buf = isc_mem_get(mctx, size);
2210*00b67f09SDavid van Moolenbroek if (buf == NULL) {
2211*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
2212*00b67f09SDavid van Moolenbroek goto failure;
2213*00b67f09SDavid van Moolenbroek }
2214*00b67f09SDavid van Moolenbroek
2215*00b67f09SDavid van Moolenbroek CHECK(journal_seek(j, best_guess.offset));
2216*00b67f09SDavid van Moolenbroek CHECK(journal_seek(new, indexend));
2217*00b67f09SDavid van Moolenbroek for (i = 0; i < copy_length; i += size) {
2218*00b67f09SDavid van Moolenbroek unsigned int len = (copy_length - i) > size ? size :
2219*00b67f09SDavid van Moolenbroek (copy_length - i);
2220*00b67f09SDavid van Moolenbroek CHECK(journal_read(j, buf, len));
2221*00b67f09SDavid van Moolenbroek CHECK(journal_write(new, buf, len));
2222*00b67f09SDavid van Moolenbroek }
2223*00b67f09SDavid van Moolenbroek
2224*00b67f09SDavid van Moolenbroek CHECK(journal_fsync(new));
2225*00b67f09SDavid van Moolenbroek
2226*00b67f09SDavid van Moolenbroek /*
2227*00b67f09SDavid van Moolenbroek * Compute new header.
2228*00b67f09SDavid van Moolenbroek */
2229*00b67f09SDavid van Moolenbroek new->header.begin.serial = best_guess.serial;
2230*00b67f09SDavid van Moolenbroek new->header.begin.offset = indexend;
2231*00b67f09SDavid van Moolenbroek new->header.end.serial = j->header.end.serial;
2232*00b67f09SDavid van Moolenbroek new->header.end.offset = indexend + copy_length;
2233*00b67f09SDavid van Moolenbroek new->header.sourceserial = j->header.sourceserial;
2234*00b67f09SDavid van Moolenbroek new->header.serialset = j->header.serialset;
2235*00b67f09SDavid van Moolenbroek
2236*00b67f09SDavid van Moolenbroek /*
2237*00b67f09SDavid van Moolenbroek * Update the journal header.
2238*00b67f09SDavid van Moolenbroek */
2239*00b67f09SDavid van Moolenbroek journal_header_encode(&new->header, &rawheader);
2240*00b67f09SDavid van Moolenbroek CHECK(journal_seek(new, 0));
2241*00b67f09SDavid van Moolenbroek CHECK(journal_write(new, &rawheader, sizeof(rawheader)));
2242*00b67f09SDavid van Moolenbroek CHECK(journal_fsync(new));
2243*00b67f09SDavid van Moolenbroek
2244*00b67f09SDavid van Moolenbroek /*
2245*00b67f09SDavid van Moolenbroek * Build new index.
2246*00b67f09SDavid van Moolenbroek */
2247*00b67f09SDavid van Moolenbroek current_pos = new->header.begin;
2248*00b67f09SDavid van Moolenbroek while (current_pos.serial != new->header.end.serial) {
2249*00b67f09SDavid van Moolenbroek index_add(new, ¤t_pos);
2250*00b67f09SDavid van Moolenbroek CHECK(journal_next(new, ¤t_pos));
2251*00b67f09SDavid van Moolenbroek }
2252*00b67f09SDavid van Moolenbroek
2253*00b67f09SDavid van Moolenbroek /*
2254*00b67f09SDavid van Moolenbroek * Write index.
2255*00b67f09SDavid van Moolenbroek */
2256*00b67f09SDavid van Moolenbroek CHECK(index_to_disk(new));
2257*00b67f09SDavid van Moolenbroek CHECK(journal_fsync(new));
2258*00b67f09SDavid van Moolenbroek
2259*00b67f09SDavid van Moolenbroek indexend = new->header.end.offset;
2260*00b67f09SDavid van Moolenbroek POST(indexend);
2261*00b67f09SDavid van Moolenbroek }
2262*00b67f09SDavid van Moolenbroek
2263*00b67f09SDavid van Moolenbroek /*
2264*00b67f09SDavid van Moolenbroek * Close both journals before trying to rename files (this is
2265*00b67f09SDavid van Moolenbroek * necessary on WIN32).
2266*00b67f09SDavid van Moolenbroek */
2267*00b67f09SDavid van Moolenbroek dns_journal_destroy(&j);
2268*00b67f09SDavid van Moolenbroek dns_journal_destroy(&new);
2269*00b67f09SDavid van Moolenbroek
2270*00b67f09SDavid van Moolenbroek /*
2271*00b67f09SDavid van Moolenbroek * With a UFS file system this should just succeed and be atomic.
2272*00b67f09SDavid van Moolenbroek * Any IXFR outs will just continue and the old journal will be
2273*00b67f09SDavid van Moolenbroek * removed on final close.
2274*00b67f09SDavid van Moolenbroek *
2275*00b67f09SDavid van Moolenbroek * With MSDOS / NTFS we need to do a two stage rename, triggered
2276*00b67f09SDavid van Moolenbroek * by EEXIST. (If any IXFR's are running in other threads, however,
2277*00b67f09SDavid van Moolenbroek * this will fail, and the journal will not be compacted. But
2278*00b67f09SDavid van Moolenbroek * if so, hopefully they'll be finished by the next time we
2279*00b67f09SDavid van Moolenbroek * compact.)
2280*00b67f09SDavid van Moolenbroek */
2281*00b67f09SDavid van Moolenbroek if (rename(newname, filename) == -1) {
2282*00b67f09SDavid van Moolenbroek if (errno == EEXIST && !is_backup) {
2283*00b67f09SDavid van Moolenbroek result = isc_file_remove(backup);
2284*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS &&
2285*00b67f09SDavid van Moolenbroek result != ISC_R_FILENOTFOUND)
2286*00b67f09SDavid van Moolenbroek goto failure;
2287*00b67f09SDavid van Moolenbroek if (rename(filename, backup) == -1)
2288*00b67f09SDavid van Moolenbroek goto maperrno;
2289*00b67f09SDavid van Moolenbroek if (rename(newname, filename) == -1)
2290*00b67f09SDavid van Moolenbroek goto maperrno;
2291*00b67f09SDavid van Moolenbroek (void)isc_file_remove(backup);
2292*00b67f09SDavid van Moolenbroek } else {
2293*00b67f09SDavid van Moolenbroek maperrno:
2294*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
2295*00b67f09SDavid van Moolenbroek goto failure;
2296*00b67f09SDavid van Moolenbroek }
2297*00b67f09SDavid van Moolenbroek }
2298*00b67f09SDavid van Moolenbroek
2299*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
2300*00b67f09SDavid van Moolenbroek
2301*00b67f09SDavid van Moolenbroek failure:
2302*00b67f09SDavid van Moolenbroek (void)isc_file_remove(newname);
2303*00b67f09SDavid van Moolenbroek if (buf != NULL)
2304*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, buf, size);
2305*00b67f09SDavid van Moolenbroek if (j != NULL)
2306*00b67f09SDavid van Moolenbroek dns_journal_destroy(&j);
2307*00b67f09SDavid van Moolenbroek if (new != NULL)
2308*00b67f09SDavid van Moolenbroek dns_journal_destroy(&new);
2309*00b67f09SDavid van Moolenbroek return (result);
2310*00b67f09SDavid van Moolenbroek }
2311*00b67f09SDavid van Moolenbroek
2312*00b67f09SDavid van Moolenbroek static isc_result_t
index_to_disk(dns_journal_t * j)2313*00b67f09SDavid van Moolenbroek index_to_disk(dns_journal_t *j) {
2314*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
2315*00b67f09SDavid van Moolenbroek
2316*00b67f09SDavid van Moolenbroek if (j->header.index_size != 0) {
2317*00b67f09SDavid van Moolenbroek unsigned int i;
2318*00b67f09SDavid van Moolenbroek unsigned char *p;
2319*00b67f09SDavid van Moolenbroek unsigned int rawbytes;
2320*00b67f09SDavid van Moolenbroek
2321*00b67f09SDavid van Moolenbroek rawbytes = j->header.index_size * sizeof(journal_rawpos_t);
2322*00b67f09SDavid van Moolenbroek
2323*00b67f09SDavid van Moolenbroek p = j->rawindex;
2324*00b67f09SDavid van Moolenbroek for (i = 0; i < j->header.index_size; i++) {
2325*00b67f09SDavid van Moolenbroek encode_uint32(j->index[i].serial, p);
2326*00b67f09SDavid van Moolenbroek p += 4;
2327*00b67f09SDavid van Moolenbroek encode_uint32(j->index[i].offset, p);
2328*00b67f09SDavid van Moolenbroek p += 4;
2329*00b67f09SDavid van Moolenbroek }
2330*00b67f09SDavid van Moolenbroek INSIST(p == j->rawindex + rawbytes);
2331*00b67f09SDavid van Moolenbroek
2332*00b67f09SDavid van Moolenbroek CHECK(journal_seek(j, sizeof(journal_rawheader_t)));
2333*00b67f09SDavid van Moolenbroek CHECK(journal_write(j, j->rawindex, rawbytes));
2334*00b67f09SDavid van Moolenbroek }
2335*00b67f09SDavid van Moolenbroek failure:
2336*00b67f09SDavid van Moolenbroek return (result);
2337*00b67f09SDavid van Moolenbroek }
2338