1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
|
/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <pthread.h>
#include "libknot/libknot.h"
#include "contrib/qp-trie/trie.h"
#include "knot/journal/knot_lmdb.h"
typedef struct catalog {
knot_lmdb_db_t db;
knot_lmdb_txn_t *ro_txn; // persistent RO transaction
knot_lmdb_txn_t *rw_txn; // temporary RW transaction
// private
knot_lmdb_txn_t *old_ro_txn;
} catalog_t;
typedef enum {
MEMBER_NONE, // this member zone is not in any catalog
MEMBER_EXACT, // this member zone precisely matches lookup
MEMBER_ZONE, // this member zone is in different catalog
MEMBER_OWNER, // this member zone is in same catalog with diferent owner
MEMBER_ERROR, // find error code in cat->txn.ret
} catalog_find_res_t;
typedef struct {
trie_t *rem; // tree of catalog_upd_val_t, that gonna be removed from catalog
trie_t *add; // tree of catalog_upd_val_t, that gonna be added to catalog
pthread_mutex_t mutex; // lock for accessing this struct
} catalog_update_t;
typedef struct {
knot_dname_t *member; // name of catalog member zone
knot_dname_t *owner; // the owner of PTR record defining the member zone
knot_dname_t *catzone; // the catalog zone the PTR is in
bool just_reconf; // this addition is of an existing member zone, which however shall be reset (purged)
} catalog_upd_val_t;
extern const MDB_val catalog_iter_prefix;
/*!
* \brief Initialize catalog structure.
*
* \param cat Catalog structure.
* \param path Path to LMDB for catalog.
* \param mapsize Mapsize of the LMDB.
*/
void catalog_init(catalog_t *cat, const char *path, size_t mapsize);
/*!
* \brief Open the catalog LMDB, create it if not exists.
*
* \param cat Catlog to be opened.
*
* \return KNOT_E*
*/
int catalog_open(catalog_t *cat);
/*!
* \brief Start a temporary RW transaction in the catalog.
*
* \param cat Catalog in question.
*
* \return KNOT_E*
*/
int catalog_begin(catalog_t *cat);
/*!
* \brief End using the temporary RW txn, refresh the persistent RO txn.
*
* \param cat Catalog in question.
*
* \return KNOT_E*
*/
int catalog_commit(catalog_t *cat);
/*!
* \brief Free up old txns.
*
* \note This must be called after catalog_commit() with a delay of synchronnize_rcu().
*
* \param cat Catalog.
*/
void catalog_commit_cleanup(catalog_t *cat);
/*!
* \brief Close the catalog and de-init the structure.
*
* \param cat Catalog to be closed.
*
* \return KNOT_E*
*/
int catalog_deinit(catalog_t *cat);
/*!
* \brief Add a member zone to the catalog database.
*
* \param cat Catalog to be augmented.
* \param member Member zone name.
* \param owner Owner of the PTR record in catalog zone, respective to the member zone.
* \param catzone Name of the catalog zone whose it's the member.
*
* \return KNOT_E*
*/
int catalog_add(catalog_t *cat, const knot_dname_t *member,
const knot_dname_t *owner, const knot_dname_t *catzone);
inline static int catalog_add2(catalog_t *cat, const catalog_upd_val_t *val)
{
return catalog_add(cat, val->member, val->owner, val->catzone);
}
/*!
* \brief Delete a member zone from the catalog database.
*
* \param cat Catalog to be removed from.
* \param member Member zone to be removed.
*
* \return KNOT_E*
*/
int catalog_del(catalog_t *cat, const knot_dname_t *member);
inline static int catalog_del2(catalog_t *cat, const catalog_upd_val_t *val)
{
assert(!val->just_reconf); // just re-add in this case
return catalog_del(cat, val->member);
}
#define catalog_foreach(cat) knot_lmdb_foreach((cat)->ro_txn, (MDB_val *)&catalog_iter_prefix)
/*!
* \brief Deserialize a value in catalog database.
*
* \param cat Catalog with cat->txn->cur_val to be deserialized.
* \param member Output: member zone.
* \param owner Output: PTR owner.
* \param catzone Output: catalog zone.
*/
void catalog_curval(catalog_t *cat, const knot_dname_t **member,
const knot_dname_t **owner, const knot_dname_t **catzone);
/*!
* \brief Get the catalog zone for known member zone.
*
* \param cat Catalog database.
* \param member Member zone name.
* \param catzone Catalog zone holding the member zone.
*
* \return KNOT_E*
*/
int catalog_get_zone(catalog_t *cat, const knot_dname_t *member,
const knot_dname_t **catzone);
/*!
* \brief Get the catalog zone for known member zone.
*
* \note This function is safe for multithreaded operation over shared LMDB transaction.
*
* \param cat Catalog database.
* \param member Member zone name.
* \param catzone Catalog zone holding the member zone.
*
* \return KNOT_E*
*/
int catalog_get_zone_threadsafe(catalog_t *cat, const knot_dname_t *member,
knot_dname_storage_t catzone);
/*!
* \brief Find specific member record in catalog database.
*
* \param cat Catalog database.
* \param member Member zone to be searched for.
* \param owner Owner to be searched/verified.
* \param catzone Catalog zone to be searched/verified.
*
* \return see catalog_find_res_t
*/
catalog_find_res_t catalog_find(catalog_t *cat, const knot_dname_t *member,
const knot_dname_t *owner, const knot_dname_t *catzone);
/*!
* \brief Copy records from one catalog database to other.
*
* \param from Catalog DB to copy from.
* \param to Catalog db to copy to.
* \param zone_only Optional: copy only records for this catalog zone.
* \param read_rw_txn Use RW txn for read operations.
*
* \return KNOT_E*
*/
int catalog_copy(knot_lmdb_db_t *from, knot_lmdb_db_t *to,
const knot_dname_t *zone_only, bool read_rw_txn);
/*!
* \brief Initialize catalog update structure.
*
* \param u Catalog update to be initialized.
*
* \return KNOT_EOK, KNOT_ENOMEM
*/
int catalog_update_init(catalog_update_t *u);
/*!
* \brief Clear contents of catalog update structure.
*
* \param u Catalog update structure to be cleared.
*/
void catalog_update_clear(catalog_update_t *u);
/*!
* \brief Free catalog update structure.
*
* \param u Catalog update structure.
*/
void catalog_update_deinit(catalog_update_t *u);
/*!
* \brief Add a new record to catalog update structure.
*
* \param u Catalog update.
* \param member Member zone name to be added.
* \param owner Owner of respective PTR record.
* \param catzone Catalog zone holding the member.
* \param remove Add a removal of such record.
*
* \return KNOT_E*
*/
int catalog_update_add(catalog_update_t *u, const knot_dname_t *member,
const knot_dname_t *owner, const knot_dname_t *catzone,
bool remove);
/*!
* \brief Read catalog update record for given member zone.
*
* \param u Catalog update.
* \param member Member zone name.
* \param remove Search in remove section.
*
* \return Found update record for given member zone; or NULL.
*/
catalog_upd_val_t *catalog_update_get(catalog_update_t *u, const knot_dname_t *member, bool remove);
struct zone_contents;
/*!
* \brief Iterate over PTR records in given zone contents and add members to catalog update.
*
* \param u Catalog update to be updated.
* \param zone Zone contents to be searched for member PTR records.
* \param remove Add removals of found member zones.
* \param check_ver Do check catalog zone version record first.
* \param check Optional: existing catalog database to be checked for existence of such record (useful for removals).
*
* \return KNOT_E*
*/
int catalog_update_from_zone(catalog_update_t *u, struct zone_contents *zone,
bool remove, bool check_ver, catalog_t *check);
/*!
* \brief Add to catalog update removals of all member zones of a single catalog zone.
*
* \param u Catalog updat to be updated.
* \param cat Catalog database to be iterated.
* \param zone Name of catalog zone whose members gonna be removed.
*
* \return KNOT_E*
*/
int catalog_update_del_all(catalog_update_t *u, catalog_t *cat, const knot_dname_t *zone);
typedef trie_it_t catalog_it_t;
inline static catalog_it_t *catalog_it_begin(catalog_update_t *u, bool remove)
{
return trie_it_begin(remove ? u->rem : u->add);
}
inline static catalog_upd_val_t *catalog_it_val(catalog_it_t *it)
{
return *(catalog_upd_val_t **)trie_it_val(it);
}
inline static bool catalog_it_finished(catalog_it_t *it)
{
return it == NULL || trie_it_finished(it);
}
#define catalog_it_next trie_it_next
#define catalog_it_free trie_it_free
/*!
* \brief Print to stdout whole contents of catalog database (for human).
*
* \param cat Catalog database to be printed.
*/
void catalog_print(catalog_t *cat);
/*!
* \brief Print to stdout whole contents of catalog update (for human).
*
* \param u Catalog update to be printed.
*/
void catalog_update_print(catalog_update_t *u);
|