1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 #pragma once
36 
37 #define ZDB_JOURNAL_CODE 1
38 #define JOURNAL_CJF 1
39 
40 #include <dnscore/output_stream.h>
41 #include <dnscore/serial.h>
42 #include <dnscore/logger.h>
43 #include <dnsdb/journal.h>
44 #include <dnsdb/zdb-zone-path-provider.h>
45 
46 #ifdef CJF_HEADER_SIZE
47 #error "CJF_HEADER_SIZE already defined"
48 #endif
49 
50 #include <dnscore/file-pool.h>
51 
52 /*
53  *  MAGIC 'JCS' 0
54  *  offset to next (0 until the section is closed and followed by a new one)
55  *  list of last-serial + file_offset
56  */
57 
58 #define CJF_IDXT_MAGIC MAGIC4('I','D','X','T')
59 
60 #define JOURNAL_CFJ_FLAGS_OTHER_ENDIAN  0x8000  // journal endian is different
61 #define JOURNAL_CFJ_FLAGS_MY_ENDIAN     0x0080  // journal endian is the same
62 #define JOURNAL_CFJ_FLAGS_NOT_EMPTY     0x0001  // journal contains pages
63 #define JOURNAL_CFJ_FLAGS_DIRTY         0x0002  // journal needs flushing
64 #define JOURNAL_CFJ_FLAGS_UNINITIALISED 0x0004
65 
66 
67 struct cjf_header // Cyclic Journal File
68 {
69     u32 magic_plus_version;
70     u32 serial_begin;
71     u32 serial_end;
72     u32 first_index_offset; // PAGE
73     u32 table_index_offset; // IDXT
74     //
75     u32 last_soa_offset;    // record
76     u32 last_page_offset_next; // the byte after the last PAGE on the chain ends
77     u16 flags;
78     u8 __end_of_struct__;
79 };
80 
81 typedef struct cjf_header cjf_header;
82 
83 #define CJF_HEADER_REAL_SIZE offsetof(cjf_header,__end_of_struct__)
84 /*
85 #if CJF_HEADER_SIZE != CJF_HEADER_REAL_SIZE
86 #error "CJF_HEADER_SIZE != CJF_HEADER_REAL_SIZE"
87 #endif
88 */
89 
90 /*
91  * PAGE
92  *
93  * Serial Number Stream Offset
94  *
95  * The table of serials streams (IXFR) and their offset
96  * The value stored is of the serial ending the IXFR
97  */
98 
99 #define CJF_CJF0_MAGIC MAGIC4('C','J','F', 0x20) // ver 2.0
100 
101 #define CJF_HEADER_SIZE 30
102 
103 #ifndef MODULE_MSG_HANDLE
104 extern logger_handle* g_database_logger;
105 #define MODULE_MSG_HANDLE g_database_logger
106 #endif
107 
108 struct jnl_page
109 {
110     u32 file_offset;    // position in the file
111     u32 count;          // number of updates
112     u32 size;           // size is fixed to CJF_SECTION_INDEX_SLOT_COUNT
113     u32 serial_start;   // first serial in this section. Could probably be lost if not for debugging
114     u32 serial_end;     // last serial in this section
115     u32 records_limit;    // starts at file_offset (position of the PAGE in the file) + CJF_SECTION_INDEX_SLOT_COUNT * 8 (4KB)
116     u32 file_offset_limit;   // if the section is about to break this limit, something has to be done. ie:
117                         // _ resynchronise serials in the file
118                         // _ write the zone to disk
119 };
120 
121 typedef struct jnl_page jnl_page;
122 
123 struct journal_cjf;
124 
125 struct journal_cjf_idxt_tbl_header
126 {
127     u32 magic;
128     u16 size;
129 };
130 
131 typedef struct journal_cjf_idxt_tbl_header journal_cjf_idxt_tbl_header;
132 
133 #define JCJFITI_TAG 0x495449464a434a
134 
135 struct journal_cjf_idxt_tbl_item
136 {
137     u32 last_serial;
138     u32 file_offset;
139 };
140 
141 typedef struct journal_cjf_idxt_tbl_item journal_cjf_idxt_tbl_item;
142 
143 struct journal_cjf_idxt
144 {
145     s16 count;
146     s16 first;
147     s16 size;
148     bool dirty;
149     bool marked;
150     journal_cjf_idxt_tbl_item *entries;
151 };
152 
153 typedef struct journal_cjf_idxt journal_cjf_idxt;
154 
155 struct journal_cjf
156 {
157     /* common points with journal base */
158     volatile struct journal_vtbl *vtbl;
159     volatile list_dl_node_s mru_node;
160     volatile int rc;
161     volatile unsigned int _forget:1,_mru:1;
162 
163     /* ******************************* */
164 
165     journal_cjf_idxt              idxt;
166     jnl_page                 last_page; // current page
167 
168     u32                   serial_begin;
169     u32                     serial_end;
170 
171     u32              first_page_offset;
172     u32         page_table_file_offset;
173 
174     u32                last_soa_offset;
175     u32              file_maximum_size;
176 
177     file_pool_file_t              file;
178 
179     shared_group_mutex_t           mtx;
180 
181     u16                          flags;
182     u8                         *origin; // to not rely on zone
183     char            *journal_file_name;
184 };
185 
186 typedef struct journal_cjf journal_cjf;
187 
188 void log_debug_jnl(journal_cjf *jnl, const char *prefix);
189 void journal_cjf_header_flush(journal_cjf *jnl);
190 void journal_cjf_remove_first_page(journal_cjf *jnl);
191 
journal_cjf_get_last_page_offset_limit(journal_cjf * jnl)192 static inline u32 journal_cjf_get_last_page_offset_limit(journal_cjf *jnl)
193 {
194     return jnl->last_page.file_offset_limit;
195 }
196 
journal_cjf_get_last_page_first_available_byte_offset(journal_cjf * jnl)197 static inline u32 journal_cjf_get_last_page_first_available_byte_offset(journal_cjf *jnl)
198 {
199     return jnl->last_page.records_limit;
200 }
201 
journal_cjf_get_last_page_has_room_left(journal_cjf * jnl)202 static inline u32 journal_cjf_get_last_page_has_room_left(journal_cjf *jnl)
203 {
204     return jnl->last_page.file_offset_limit >= jnl->last_page.records_limit;
205 }
206 
journal_cjf_get_last_page_available_space_left(journal_cjf * jnl)207 static inline s64 journal_cjf_get_last_page_available_space_left(journal_cjf *jnl)
208 {
209     s64 to = (s64)jnl->last_page.file_offset_limit;
210     s64 from = (s64)jnl->last_page.records_limit;
211     s64 ret = MAX(to - from, 0);
212     return ret;
213 }
214 
journal_cjf_maximum_size(journal_cjf * jnl)215 static inline u32 journal_cjf_maximum_size(journal_cjf *jnl)
216 {
217     return jnl->file_maximum_size;
218 }
219 
journal_cjf_has_flag(journal_cjf * jnl,u16 bits)220 static inline bool journal_cjf_has_flag(journal_cjf *jnl, u16 bits)
221 {
222     return (jnl->flags & bits) == bits;
223 }
224 
journal_cjf_set_flag(journal_cjf * jnl,u16 bits)225 static inline void journal_cjf_set_flag(journal_cjf *jnl, u16 bits)
226 {
227     jnl->flags |= bits;
228 }
229 
journal_cjf_clear_flag(journal_cjf * jnl,u16 bits)230 static inline void journal_cjf_clear_flag(journal_cjf *jnl, u16 bits)
231 {
232     jnl->flags &= ~bits;
233 }
234 
journal_cjf_set_dirty(journal_cjf * jnl)235 static inline void journal_cjf_set_dirty(journal_cjf *jnl)
236 {
237     journal_cjf_set_flag(jnl, JOURNAL_CFJ_FLAGS_DIRTY);
238 }
239 
journal_cjf_is_dirty(journal_cjf * jnl)240 static inline bool journal_cjf_is_dirty(journal_cjf *jnl)
241 {
242     bool ret = journal_cjf_has_flag(jnl, JOURNAL_CFJ_FLAGS_DIRTY);
243     return ret;
244 }
245 
journal_cjf_clear_dirty(journal_cjf * jnl)246 static inline void journal_cjf_clear_dirty(journal_cjf *jnl)
247 {
248     journal_cjf_clear_flag(jnl, JOURNAL_CFJ_FLAGS_DIRTY);
249 }
250 
journal_cjf_set_empty(journal_cjf * jnl)251 static inline void journal_cjf_set_empty(journal_cjf *jnl)
252 {
253     journal_cjf_clear_flag(jnl, JOURNAL_CFJ_FLAGS_NOT_EMPTY);
254 }
255 
journal_cjf_clear_empty(journal_cjf * jnl)256 static inline void journal_cjf_clear_empty(journal_cjf *jnl)
257 {
258     journal_cjf_set_flag(jnl, JOURNAL_CFJ_FLAGS_NOT_EMPTY);
259 }
260 
journal_cjf_isempty(journal_cjf * jnl)261 static inline bool journal_cjf_isempty(journal_cjf *jnl)
262 {
263     bool ret = !journal_cjf_has_flag(jnl, JOURNAL_CFJ_FLAGS_NOT_EMPTY);
264     return ret;
265 }
266 
journal_cjf_is_my_endian(journal_cjf * jnl)267 static inline bool journal_cjf_is_my_endian(journal_cjf *jnl)
268 {
269     bool ret = journal_cjf_has_flag(jnl, JOURNAL_CFJ_FLAGS_MY_ENDIAN);
270     return ret;
271 }
272