summaryrefslogtreecommitdiffstats
path: root/src/knot/zone/catalog.h
blob: 003be205740cf4ea1c1f21df53aa60b785593df3 (plain)
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);