1 | /*
|
---|
2 | Unix SMB/CIFS implementation.
|
---|
3 |
|
---|
4 | Database interface wrapper around tdb/ctdb
|
---|
5 |
|
---|
6 | Copyright (C) Volker Lendecke 2005-2007
|
---|
7 | Copyright (C) Stefan Metzmacher 2008
|
---|
8 |
|
---|
9 | This program is free software; you can redistribute it and/or modify
|
---|
10 | it under the terms of the GNU General Public License as published by
|
---|
11 | the Free Software Foundation; either version 3 of the License, or
|
---|
12 | (at your option) any later version.
|
---|
13 |
|
---|
14 | This program is distributed in the hope that it will be useful,
|
---|
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
17 | GNU General Public License for more details.
|
---|
18 |
|
---|
19 | You should have received a copy of the GNU General Public License
|
---|
20 | along with this program. If not, see <http://www.gnu.org/licenses/>.
|
---|
21 | */
|
---|
22 |
|
---|
23 | #include "includes.h"
|
---|
24 | #include "librpc/gen_ndr/ndr_messaging.h"
|
---|
25 |
|
---|
26 | struct db_tdb2_ctx {
|
---|
27 | struct db_context *db;
|
---|
28 | const char *name;
|
---|
29 | struct tdb_wrap *mtdb;
|
---|
30 | const char *mtdb_path;
|
---|
31 | bool master_transaction;
|
---|
32 | struct {
|
---|
33 | int hash_size;
|
---|
34 | int tdb_flags;
|
---|
35 | int open_flags;
|
---|
36 | mode_t mode;
|
---|
37 | } open;
|
---|
38 | struct tdb_wrap *ltdb;
|
---|
39 | const char *ltdb_path;
|
---|
40 | bool local_transaction;
|
---|
41 | int transaction;
|
---|
42 | bool out_of_sync;
|
---|
43 | uint32_t lseqnum;
|
---|
44 | uint32_t mseqnum;
|
---|
45 | #define DB_TDB2_MASTER_SEQNUM_KEYSTR "DB_TDB2_MASTER_SEQNUM_KEYSTR"
|
---|
46 | TDB_DATA mseqkey;
|
---|
47 | uint32_t max_buffer_size;
|
---|
48 | uint32_t current_buffer_size;
|
---|
49 | struct dbwrap_tdb2_changes changes;
|
---|
50 | };
|
---|
51 |
|
---|
52 |
|
---|
53 | static NTSTATUS db_tdb2_store(struct db_record *rec, TDB_DATA data, int flag);
|
---|
54 | static NTSTATUS db_tdb2_delete(struct db_record *rec);
|
---|
55 |
|
---|
56 | static void db_tdb2_queue_change(struct db_tdb2_ctx *db_ctx, const TDB_DATA key);
|
---|
57 | static void db_tdb2_send_notify(struct db_tdb2_ctx *db_ctx);
|
---|
58 |
|
---|
59 | static struct db_context *db_open_tdb2_ex(TALLOC_CTX *mem_ctx,
|
---|
60 | const char *name,
|
---|
61 | int hash_size, int tdb_flags,
|
---|
62 | int open_flags, mode_t mode,
|
---|
63 | const struct dbwrap_tdb2_changes *chgs);
|
---|
64 |
|
---|
65 | static int db_tdb2_sync_from_master(struct db_tdb2_ctx *db_ctx,
|
---|
66 | const struct dbwrap_tdb2_changes *changes);
|
---|
67 |
|
---|
68 | static int db_tdb2_open_master(struct db_tdb2_ctx *db_ctx, bool transaction,
|
---|
69 | const struct dbwrap_tdb2_changes *changes);
|
---|
70 | static int db_tdb2_commit_local(struct db_tdb2_ctx *db_ctx, uint32_t mseqnum);
|
---|
71 | static int db_tdb2_close_master(struct db_tdb2_ctx *db_ctx);
|
---|
72 | static int db_tdb2_transaction_cancel(struct db_context *db);
|
---|
73 |
|
---|
74 | static void db_tdb2_receive_changes(struct messaging_context *msg,
|
---|
75 | void *private_data,
|
---|
76 | uint32_t msg_type,
|
---|
77 | struct server_id server_id,
|
---|
78 | DATA_BLOB *data);
|
---|
79 |
|
---|
80 | static struct messaging_context *global_tdb2_msg_ctx;
|
---|
81 | static bool global_tdb2_msg_ctx_initialized;
|
---|
82 |
|
---|
83 | void db_tdb2_setup_messaging(struct messaging_context *msg_ctx, bool server)
|
---|
84 | {
|
---|
85 | global_tdb2_msg_ctx = msg_ctx;
|
---|
86 |
|
---|
87 | global_tdb2_msg_ctx_initialized = true;
|
---|
88 |
|
---|
89 | if (!server) {
|
---|
90 | return;
|
---|
91 | }
|
---|
92 |
|
---|
93 | if (!lp_parm_bool(-1, "dbwrap", "use_tdb2", false)) {
|
---|
94 | return;
|
---|
95 | }
|
---|
96 |
|
---|
97 | messaging_register(msg_ctx, NULL, MSG_DBWRAP_TDB2_CHANGES,
|
---|
98 | db_tdb2_receive_changes);
|
---|
99 | }
|
---|
100 |
|
---|
101 | static struct messaging_context *db_tdb2_get_global_messaging_context(void)
|
---|
102 | {
|
---|
103 | struct messaging_context *msg_ctx;
|
---|
104 |
|
---|
105 | if (global_tdb2_msg_ctx_initialized) {
|
---|
106 | return global_tdb2_msg_ctx;
|
---|
107 | }
|
---|
108 |
|
---|
109 | msg_ctx = messaging_init(NULL, procid_self(),
|
---|
110 | event_context_init(NULL));
|
---|
111 |
|
---|
112 | db_tdb2_setup_messaging(msg_ctx, false);
|
---|
113 |
|
---|
114 | return global_tdb2_msg_ctx;
|
---|
115 | }
|
---|
116 |
|
---|
117 | struct tdb_fetch_locked_state {
|
---|
118 | TALLOC_CTX *mem_ctx;
|
---|
119 | struct db_record *result;
|
---|
120 | };
|
---|
121 |
|
---|
122 | static int db_tdb2_fetchlock_parse(TDB_DATA key, TDB_DATA data,
|
---|
123 | void *private_data)
|
---|
124 | {
|
---|
125 | struct tdb_fetch_locked_state *state =
|
---|
126 | (struct tdb_fetch_locked_state *)private_data;
|
---|
127 |
|
---|
128 | state->result = (struct db_record *)talloc_size(
|
---|
129 | state->mem_ctx,
|
---|
130 | sizeof(struct db_record) + key.dsize + data.dsize);
|
---|
131 |
|
---|
132 | if (state->result == NULL) {
|
---|
133 | return 0;
|
---|
134 | }
|
---|
135 |
|
---|
136 | state->result->key.dsize = key.dsize;
|
---|
137 | state->result->key.dptr = ((uint8 *)state->result)
|
---|
138 | + sizeof(struct db_record);
|
---|
139 | memcpy(state->result->key.dptr, key.dptr, key.dsize);
|
---|
140 |
|
---|
141 | state->result->value.dsize = data.dsize;
|
---|
142 |
|
---|
143 | if (data.dsize > 0) {
|
---|
144 | state->result->value.dptr = state->result->key.dptr+key.dsize;
|
---|
145 | memcpy(state->result->value.dptr, data.dptr, data.dsize);
|
---|
146 | }
|
---|
147 | else {
|
---|
148 | state->result->value.dptr = NULL;
|
---|
149 | }
|
---|
150 |
|
---|
151 | return 0;
|
---|
152 | }
|
---|
153 |
|
---|
154 | static struct db_record *db_tdb2_fetch_locked(struct db_context *db,
|
---|
155 | TALLOC_CTX *mem_ctx, TDB_DATA key)
|
---|
156 | {
|
---|
157 | struct db_tdb2_ctx *ctx = talloc_get_type_abort(db->private_data,
|
---|
158 | struct db_tdb2_ctx);
|
---|
159 | struct tdb_fetch_locked_state state;
|
---|
160 |
|
---|
161 | /* Do not accidently allocate/deallocate w/o need when debug level is lower than needed */
|
---|
162 | if(DEBUGLEVEL >= 10) {
|
---|
163 | char *keystr = hex_encode(NULL, (unsigned char*)key.dptr, key.dsize);
|
---|
164 | DEBUG(10, (DEBUGLEVEL > 10
|
---|
165 | ? "Locking key %s\n" : "Locking key %.20s\n",
|
---|
166 | keystr));
|
---|
167 | TALLOC_FREE(keystr);
|
---|
168 | }
|
---|
169 |
|
---|
170 | /*
|
---|
171 | * we only support modifications within a
|
---|
172 | * started transaction.
|
---|
173 | */
|
---|
174 | if (ctx->transaction == 0) {
|
---|
175 | DEBUG(0, ("db_tdb2_fetch_locked[%s]: no transaction started\n",
|
---|
176 | ctx->name));
|
---|
177 | smb_panic("no transaction");
|
---|
178 | return NULL;
|
---|
179 | }
|
---|
180 |
|
---|
181 | state.mem_ctx = mem_ctx;
|
---|
182 | state.result = NULL;
|
---|
183 |
|
---|
184 | tdb_parse_record(ctx->mtdb->tdb, key, db_tdb2_fetchlock_parse, &state);
|
---|
185 |
|
---|
186 | if (state.result == NULL) {
|
---|
187 | db_tdb2_fetchlock_parse(key, tdb_null, &state);
|
---|
188 | }
|
---|
189 |
|
---|
190 | if (state.result == NULL) {
|
---|
191 | return NULL;
|
---|
192 | }
|
---|
193 |
|
---|
194 | state.result->private_data = talloc_reference(state.result, ctx);
|
---|
195 | state.result->store = db_tdb2_store;
|
---|
196 | state.result->delete_rec = db_tdb2_delete;
|
---|
197 |
|
---|
198 | DEBUG(10, ("Allocated locked data 0x%p\n", state.result));
|
---|
199 |
|
---|
200 | return state.result;
|
---|
201 | }
|
---|
202 |
|
---|
203 | struct tdb_fetch_state {
|
---|
204 | TALLOC_CTX *mem_ctx;
|
---|
205 | int result;
|
---|
206 | TDB_DATA data;
|
---|
207 | };
|
---|
208 |
|
---|
209 | static int db_tdb2_fetch_parse(TDB_DATA key, TDB_DATA data,
|
---|
210 | void *private_data)
|
---|
211 | {
|
---|
212 | struct tdb_fetch_state *state =
|
---|
213 | (struct tdb_fetch_state *)private_data;
|
---|
214 |
|
---|
215 | state->data.dptr = (uint8 *)talloc_memdup(state->mem_ctx, data.dptr,
|
---|
216 | data.dsize);
|
---|
217 | if (state->data.dptr == NULL) {
|
---|
218 | state->result = -1;
|
---|
219 | return 0;
|
---|
220 | }
|
---|
221 |
|
---|
222 | state->data.dsize = data.dsize;
|
---|
223 | return 0;
|
---|
224 | }
|
---|
225 |
|
---|
226 | static void db_tdb2_resync_before_read(struct db_tdb2_ctx *db_ctx, TDB_DATA *kbuf)
|
---|
227 | {
|
---|
228 | if (db_ctx->mtdb) {
|
---|
229 | return;
|
---|
230 | }
|
---|
231 |
|
---|
232 | if (!db_ctx->out_of_sync) {
|
---|
233 | return;
|
---|
234 | }
|
---|
235 |
|
---|
236 | /*
|
---|
237 | * this function operates on the local copy,
|
---|
238 | * so hide the DB_TDB2_MASTER_SEQNUM_KEYSTR from the caller.
|
---|
239 | */
|
---|
240 | if (kbuf && (db_ctx->mseqkey.dsize == kbuf->dsize) &&
|
---|
241 | (memcmp(db_ctx->mseqkey.dptr, kbuf->dptr, kbuf->dsize) == 0)) {
|
---|
242 | return;
|
---|
243 | }
|
---|
244 |
|
---|
245 | DEBUG(0,("resync_before_read[%s/%s]\n",
|
---|
246 | db_ctx->mtdb_path, db_ctx->ltdb_path));
|
---|
247 |
|
---|
248 | db_tdb2_open_master(db_ctx, false, NULL);
|
---|
249 | db_tdb2_close_master(db_ctx);
|
---|
250 | }
|
---|
251 |
|
---|
252 | static int db_tdb2_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
|
---|
253 | TDB_DATA key, TDB_DATA *pdata)
|
---|
254 | {
|
---|
255 | struct db_tdb2_ctx *ctx = talloc_get_type_abort(
|
---|
256 | db->private_data, struct db_tdb2_ctx);
|
---|
257 |
|
---|
258 | struct tdb_fetch_state state;
|
---|
259 |
|
---|
260 | db_tdb2_resync_before_read(ctx, &key);
|
---|
261 |
|
---|
262 | if (ctx->out_of_sync) {
|
---|
263 | DEBUG(0,("out of sync[%s] failing fetch\n",
|
---|
264 | ctx->ltdb_path));
|
---|
265 | errno = EIO;
|
---|
266 | return -1;
|
---|
267 | }
|
---|
268 |
|
---|
269 | state.mem_ctx = mem_ctx;
|
---|
270 | state.result = 0;
|
---|
271 | state.data = tdb_null;
|
---|
272 |
|
---|
273 | tdb_parse_record(ctx->ltdb->tdb, key, db_tdb2_fetch_parse, &state);
|
---|
274 |
|
---|
275 | if (state.result == -1) {
|
---|
276 | return -1;
|
---|
277 | }
|
---|
278 |
|
---|
279 | *pdata = state.data;
|
---|
280 | return 0;
|
---|
281 | }
|
---|
282 |
|
---|
283 | static NTSTATUS db_tdb2_store(struct db_record *rec, TDB_DATA data, int flag)
|
---|
284 | {
|
---|
285 | struct db_tdb2_ctx *ctx = talloc_get_type_abort(rec->private_data,
|
---|
286 | struct db_tdb2_ctx);
|
---|
287 | int ret;
|
---|
288 |
|
---|
289 | /*
|
---|
290 | * This has a bug: We need to replace rec->value for correct
|
---|
291 | * operation, but right now brlock and locking don't use the value
|
---|
292 | * anymore after it was stored.
|
---|
293 | */
|
---|
294 |
|
---|
295 | /* first store it to the master copy */
|
---|
296 | ret = tdb_store(ctx->mtdb->tdb, rec->key, data, flag);
|
---|
297 | if (ret != 0) {
|
---|
298 | return NT_STATUS_UNSUCCESSFUL;
|
---|
299 | }
|
---|
300 |
|
---|
301 | /* then store it to the local copy */
|
---|
302 | ret = tdb_store(ctx->ltdb->tdb, rec->key, data, flag);
|
---|
303 | if (ret != 0) {
|
---|
304 | /* try to restore the old value in the master copy */
|
---|
305 | if (rec->value.dptr) {
|
---|
306 | tdb_store(ctx->mtdb->tdb, rec->key,
|
---|
307 | rec->value, TDB_REPLACE);
|
---|
308 | } else {
|
---|
309 | tdb_delete(ctx->mtdb->tdb, rec->key);
|
---|
310 | }
|
---|
311 | return NT_STATUS_INTERNAL_DB_CORRUPTION;
|
---|
312 | }
|
---|
313 |
|
---|
314 | db_tdb2_queue_change(ctx, rec->key);
|
---|
315 |
|
---|
316 | return NT_STATUS_OK;
|
---|
317 | }
|
---|
318 |
|
---|
319 | static NTSTATUS db_tdb2_delete(struct db_record *rec)
|
---|
320 | {
|
---|
321 | struct db_tdb2_ctx *ctx = talloc_get_type_abort(rec->private_data,
|
---|
322 | struct db_tdb2_ctx);
|
---|
323 | int ret;
|
---|
324 |
|
---|
325 | ret = tdb_delete(ctx->mtdb->tdb, rec->key);
|
---|
326 | if (ret != 0) {
|
---|
327 | if (tdb_error(ctx->mtdb->tdb) == TDB_ERR_NOEXIST) {
|
---|
328 | return NT_STATUS_NOT_FOUND;
|
---|
329 | }
|
---|
330 |
|
---|
331 | return NT_STATUS_UNSUCCESSFUL;
|
---|
332 | }
|
---|
333 |
|
---|
334 | ret = tdb_delete(ctx->ltdb->tdb, rec->key);
|
---|
335 | if (ret != 0) {
|
---|
336 | /* try to restore the value in the master copy */
|
---|
337 | tdb_store(ctx->mtdb->tdb, rec->key,
|
---|
338 | rec->value, TDB_REPLACE);
|
---|
339 | return NT_STATUS_INTERNAL_DB_CORRUPTION;
|
---|
340 | }
|
---|
341 |
|
---|
342 | db_tdb2_queue_change(ctx, rec->key);
|
---|
343 |
|
---|
344 | return NT_STATUS_OK;
|
---|
345 | }
|
---|
346 |
|
---|
347 | struct db_tdb2_traverse_ctx {
|
---|
348 | struct db_tdb2_ctx *db_ctx;
|
---|
349 | int (*f)(struct db_record *rec, void *private_data);
|
---|
350 | void *private_data;
|
---|
351 | };
|
---|
352 |
|
---|
353 | static int db_tdb2_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
|
---|
354 | void *private_data)
|
---|
355 | {
|
---|
356 | struct db_tdb2_traverse_ctx *ctx =
|
---|
357 | (struct db_tdb2_traverse_ctx *)private_data;
|
---|
358 | struct db_record rec;
|
---|
359 |
|
---|
360 | /* this function operates on the master copy */
|
---|
361 |
|
---|
362 | rec.key = kbuf;
|
---|
363 | rec.value = dbuf;
|
---|
364 | rec.store = db_tdb2_store;
|
---|
365 | rec.delete_rec = db_tdb2_delete;
|
---|
366 | rec.private_data = ctx->db_ctx;
|
---|
367 |
|
---|
368 | return ctx->f(&rec, ctx->private_data);
|
---|
369 | }
|
---|
370 |
|
---|
371 | static int db_tdb2_traverse(struct db_context *db,
|
---|
372 | int (*f)(struct db_record *rec, void *private_data),
|
---|
373 | void *private_data)
|
---|
374 | {
|
---|
375 | struct db_tdb2_ctx *db_ctx =
|
---|
376 | talloc_get_type_abort(db->private_data, struct db_tdb2_ctx);
|
---|
377 | struct db_tdb2_traverse_ctx ctx;
|
---|
378 |
|
---|
379 | /*
|
---|
380 | * we only support modifications within a
|
---|
381 | * started transaction.
|
---|
382 | */
|
---|
383 | if (db_ctx->transaction == 0) {
|
---|
384 | DEBUG(0, ("db_tdb2_traverse[%s]: no transaction started\n",
|
---|
385 | db_ctx->name));
|
---|
386 | smb_panic("no transaction");
|
---|
387 | return -1;
|
---|
388 | }
|
---|
389 |
|
---|
390 | /* here we traverse the master copy */
|
---|
391 | ctx.db_ctx = db_ctx;
|
---|
392 | ctx.f = f;
|
---|
393 | ctx.private_data = private_data;
|
---|
394 | return tdb_traverse(db_ctx->mtdb->tdb, db_tdb2_traverse_func, &ctx);
|
---|
395 | }
|
---|
396 |
|
---|
397 | static NTSTATUS db_tdb2_store_deny(struct db_record *rec, TDB_DATA data, int flag)
|
---|
398 | {
|
---|
399 | return NT_STATUS_MEDIA_WRITE_PROTECTED;
|
---|
400 | }
|
---|
401 |
|
---|
402 | static NTSTATUS db_tdb2_delete_deny(struct db_record *rec)
|
---|
403 | {
|
---|
404 | return NT_STATUS_MEDIA_WRITE_PROTECTED;
|
---|
405 | }
|
---|
406 |
|
---|
407 | static int db_tdb2_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
|
---|
408 | void *private_data)
|
---|
409 | {
|
---|
410 | struct db_tdb2_traverse_ctx *ctx =
|
---|
411 | (struct db_tdb2_traverse_ctx *)private_data;
|
---|
412 | struct db_record rec;
|
---|
413 |
|
---|
414 | /*
|
---|
415 | * this function operates on the local copy,
|
---|
416 | * so hide the DB_TDB2_MASTER_SEQNUM_KEYSTR from the caller.
|
---|
417 | */
|
---|
418 | if ((ctx->db_ctx->mseqkey.dsize == kbuf.dsize) &&
|
---|
419 | (memcmp(ctx->db_ctx->mseqkey.dptr, kbuf.dptr, kbuf.dsize) == 0)) {
|
---|
420 | return 0;
|
---|
421 | }
|
---|
422 |
|
---|
423 | rec.key = kbuf;
|
---|
424 | rec.value = dbuf;
|
---|
425 | rec.store = db_tdb2_store_deny;
|
---|
426 | rec.delete_rec = db_tdb2_delete_deny;
|
---|
427 | rec.private_data = ctx->db_ctx;
|
---|
428 |
|
---|
429 | return ctx->f(&rec, ctx->private_data);
|
---|
430 | }
|
---|
431 |
|
---|
432 | static int db_tdb2_traverse_read(struct db_context *db,
|
---|
433 | int (*f)(struct db_record *rec, void *private_data),
|
---|
434 | void *private_data)
|
---|
435 | {
|
---|
436 | struct db_tdb2_ctx *db_ctx =
|
---|
437 | talloc_get_type_abort(db->private_data, struct db_tdb2_ctx);
|
---|
438 | struct db_tdb2_traverse_ctx ctx;
|
---|
439 | int ret;
|
---|
440 |
|
---|
441 | db_tdb2_resync_before_read(db_ctx, NULL);
|
---|
442 |
|
---|
443 | if (db_ctx->out_of_sync) {
|
---|
444 | DEBUG(0,("out of sync[%s] failing traverse_read\n",
|
---|
445 | db_ctx->ltdb_path));
|
---|
446 | errno = EIO;
|
---|
447 | return -1;
|
---|
448 | }
|
---|
449 |
|
---|
450 | /* here we traverse the local copy */
|
---|
451 | ctx.db_ctx = db_ctx;
|
---|
452 | ctx.f = f;
|
---|
453 | ctx.private_data = private_data;
|
---|
454 | ret = tdb_traverse_read(db_ctx->ltdb->tdb, db_tdb2_traverse_read_func, &ctx);
|
---|
455 | if (ret > 0) {
|
---|
456 | /* we have filtered one entry */
|
---|
457 | ret--;
|
---|
458 | }
|
---|
459 |
|
---|
460 | return ret;
|
---|
461 | }
|
---|
462 |
|
---|
463 | static int db_tdb2_get_seqnum(struct db_context *db)
|
---|
464 |
|
---|
465 | {
|
---|
466 | struct db_tdb2_ctx *db_ctx =
|
---|
467 | talloc_get_type_abort(db->private_data, struct db_tdb2_ctx);
|
---|
468 | uint32_t nlseq;
|
---|
469 | uint32_t nmseq;
|
---|
470 | bool ok;
|
---|
471 |
|
---|
472 | nlseq = tdb_get_seqnum(db_ctx->ltdb->tdb);
|
---|
473 |
|
---|
474 | if (nlseq == db_ctx->lseqnum) {
|
---|
475 | return db_ctx->mseqnum;
|
---|
476 | }
|
---|
477 |
|
---|
478 | ok = tdb_fetch_uint32_byblob(db_ctx->ltdb->tdb,
|
---|
479 | db_ctx->mseqkey,
|
---|
480 | &nmseq);
|
---|
481 | if (!ok) {
|
---|
482 | /* TODO: what should we do here? */
|
---|
483 | return db_ctx->mseqnum;
|
---|
484 | }
|
---|
485 |
|
---|
486 | db_ctx->lseqnum = nlseq;
|
---|
487 | db_ctx->mseqnum = nmseq;
|
---|
488 |
|
---|
489 | return db_ctx->mseqnum;
|
---|
490 | }
|
---|
491 |
|
---|
492 | static int db_tdb2_transaction_start(struct db_context *db)
|
---|
493 | {
|
---|
494 | struct db_tdb2_ctx *db_ctx =
|
---|
495 | talloc_get_type_abort(db->private_data, struct db_tdb2_ctx);
|
---|
496 | int ret;
|
---|
497 |
|
---|
498 | if (db_ctx->transaction) {
|
---|
499 | db_ctx->transaction++;
|
---|
500 | return 0;
|
---|
501 | }
|
---|
502 |
|
---|
503 | /* we need to open the master tdb in order to */
|
---|
504 | ret = db_tdb2_open_master(db_ctx, true, NULL);
|
---|
505 | if (ret != 0) {
|
---|
506 | return ret;
|
---|
507 | }
|
---|
508 |
|
---|
509 | ret = tdb_transaction_start(db_ctx->ltdb->tdb);
|
---|
510 | if (ret != 0) {
|
---|
511 | db_tdb2_close_master(db_ctx);
|
---|
512 | return ret;
|
---|
513 | }
|
---|
514 |
|
---|
515 | db_ctx->local_transaction = true;
|
---|
516 | db_ctx->transaction = 1;
|
---|
517 |
|
---|
518 | return 0;
|
---|
519 | }
|
---|
520 |
|
---|
521 | static void db_tdb2_queue_change(struct db_tdb2_ctx *db_ctx, const TDB_DATA key)
|
---|
522 | {
|
---|
523 | size_t size_needed = 4 + key.dsize;
|
---|
524 | size_t size_new = db_ctx->current_buffer_size + size_needed;
|
---|
525 | uint32_t i;
|
---|
526 | DATA_BLOB *keys;
|
---|
527 |
|
---|
528 | db_ctx->changes.num_changes++;
|
---|
529 |
|
---|
530 | if (db_ctx->changes.num_changes > 1 &&
|
---|
531 | db_ctx->changes.keys == NULL) {
|
---|
532 | /*
|
---|
533 | * this means we already overflowed
|
---|
534 | */
|
---|
535 | return;
|
---|
536 | }
|
---|
537 |
|
---|
538 | if (db_ctx->changes.num_changes == 1) {
|
---|
539 | db_ctx->changes.old_seqnum = db_ctx->mseqnum;
|
---|
540 | }
|
---|
541 |
|
---|
542 | for (i=0; i < db_ctx->changes.num_keys; i++) {
|
---|
543 | int ret;
|
---|
544 |
|
---|
545 | if (key.dsize != db_ctx->changes.keys[i].length) {
|
---|
546 | continue;
|
---|
547 | }
|
---|
548 | ret = memcmp(key.dptr, db_ctx->changes.keys[i].data, key.dsize);
|
---|
549 | if (ret != 0) {
|
---|
550 | continue;
|
---|
551 | }
|
---|
552 |
|
---|
553 | /*
|
---|
554 | * the key is already in the list
|
---|
555 | * so we're done
|
---|
556 | */
|
---|
557 | return;
|
---|
558 | }
|
---|
559 |
|
---|
560 | if (db_ctx->max_buffer_size < size_new) {
|
---|
561 | goto overflow;
|
---|
562 | }
|
---|
563 |
|
---|
564 | keys = TALLOC_REALLOC_ARRAY(db_ctx, db_ctx->changes.keys,
|
---|
565 | DATA_BLOB,
|
---|
566 | db_ctx->changes.num_keys + 1);
|
---|
567 | if (!keys) {
|
---|
568 | goto overflow;
|
---|
569 | }
|
---|
570 | db_ctx->changes.keys = keys;
|
---|
571 |
|
---|
572 | keys[db_ctx->changes.num_keys].data = (uint8_t *)talloc_memdup(keys,
|
---|
573 | key.dptr,
|
---|
574 | key.dsize);
|
---|
575 | if (!keys[db_ctx->changes.num_keys].data) {
|
---|
576 | goto overflow;
|
---|
577 | }
|
---|
578 | keys[db_ctx->changes.num_keys].length = key.dsize;
|
---|
579 | db_ctx->changes.num_keys++;
|
---|
580 | db_ctx->current_buffer_size = size_new;
|
---|
581 |
|
---|
582 | return;
|
---|
583 |
|
---|
584 | overflow:
|
---|
585 | /*
|
---|
586 | * on overflow discard the buffer and let
|
---|
587 | * the others reload the whole tdb
|
---|
588 | */
|
---|
589 | db_ctx->current_buffer_size = 0;
|
---|
590 | db_ctx->changes.num_keys = 0;
|
---|
591 | TALLOC_FREE(db_ctx->changes.keys);
|
---|
592 | return;
|
---|
593 | }
|
---|
594 |
|
---|
595 | static void db_tdb2_send_notify(struct db_tdb2_ctx *db_ctx)
|
---|
596 | {
|
---|
597 | enum ndr_err_code ndr_err;
|
---|
598 | bool ok;
|
---|
599 | DATA_BLOB blob;
|
---|
600 | struct messaging_context *msg_ctx;
|
---|
601 | int num_msgs = 0;
|
---|
602 | struct server_id self = procid_self();
|
---|
603 |
|
---|
604 | msg_ctx = db_tdb2_get_global_messaging_context();
|
---|
605 |
|
---|
606 | db_ctx->changes.name = db_ctx->name;
|
---|
607 |
|
---|
608 | DEBUG(10,("%s[%s] size[%u/%u] changes[%u] keys[%u] seqnum[%u=>%u]\n",
|
---|
609 | __FUNCTION__,
|
---|
610 | db_ctx->changes.name,
|
---|
611 | db_ctx->current_buffer_size,
|
---|
612 | db_ctx->max_buffer_size,
|
---|
613 | db_ctx->changes.num_changes,
|
---|
614 | db_ctx->changes.num_keys,
|
---|
615 | db_ctx->changes.old_seqnum,
|
---|
616 | db_ctx->changes.new_seqnum));
|
---|
617 |
|
---|
618 | if (db_ctx->changes.num_changes == 0) {
|
---|
619 | DEBUG(10,("db_tdb2_send_notify[%s]: no changes\n",
|
---|
620 | db_ctx->changes.name));
|
---|
621 | goto done;
|
---|
622 | }
|
---|
623 |
|
---|
624 | if (!msg_ctx) {
|
---|
625 | DEBUG(1,("db_tdb2_send_notify[%s]: skipped (no msg ctx)\n",
|
---|
626 | db_ctx->changes.name));
|
---|
627 | goto done;
|
---|
628 | }
|
---|
629 |
|
---|
630 | ndr_err = ndr_push_struct_blob(
|
---|
631 | &blob, talloc_tos(), &db_ctx->changes,
|
---|
632 | (ndr_push_flags_fn_t)ndr_push_dbwrap_tdb2_changes);
|
---|
633 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
---|
634 | DEBUG(0,("db_tdb2_send_notify[%s]: failed to push changes: %s\n",
|
---|
635 | db_ctx->changes.name,
|
---|
636 | nt_errstr(ndr_map_error2ntstatus(ndr_err))));
|
---|
637 | goto done;
|
---|
638 | }
|
---|
639 |
|
---|
640 | ok = message_send_all(msg_ctx, MSG_DBWRAP_TDB2_CHANGES,
|
---|
641 | blob.data, blob.length, &num_msgs);
|
---|
642 | if (!ok) {
|
---|
643 | DEBUG(0,("db_tdb2_send_notify[%s]: failed to send changes\n",
|
---|
644 | db_ctx->changes.name));
|
---|
645 | goto done;
|
---|
646 | }
|
---|
647 |
|
---|
648 | DEBUG(10,("db_tdb2_send_notify[%s]: pid %s send %u messages\n",
|
---|
649 | db_ctx->name, procid_str_static(&self), num_msgs));
|
---|
650 |
|
---|
651 | done:
|
---|
652 | TALLOC_FREE(db_ctx->changes.keys);
|
---|
653 | ZERO_STRUCT(db_ctx->changes);
|
---|
654 |
|
---|
655 | return;
|
---|
656 | }
|
---|
657 |
|
---|
658 | static void db_tdb2_receive_changes(struct messaging_context *msg,
|
---|
659 | void *private_data,
|
---|
660 | uint32_t msg_type,
|
---|
661 | struct server_id server_id,
|
---|
662 | DATA_BLOB *data)
|
---|
663 | {
|
---|
664 | enum ndr_err_code ndr_err;
|
---|
665 | struct dbwrap_tdb2_changes changes;
|
---|
666 | struct db_context *db;
|
---|
667 | struct server_id self;
|
---|
668 |
|
---|
669 | if (procid_is_me(&server_id)) {
|
---|
670 | DEBUG(0,("db_tdb2_receive_changes: ignore selfpacket\n"));
|
---|
671 | return;
|
---|
672 | }
|
---|
673 |
|
---|
674 | self = procid_self();
|
---|
675 |
|
---|
676 | DEBUG(10,("db_tdb2_receive_changes: from %s to %s\n",
|
---|
677 | procid_str(debug_ctx(), &server_id),
|
---|
678 | procid_str(debug_ctx(), &self)));
|
---|
679 |
|
---|
680 | ndr_err = ndr_pull_struct_blob_all(
|
---|
681 | data, talloc_tos(), &changes,
|
---|
682 | (ndr_pull_flags_fn_t)ndr_pull_dbwrap_tdb2_changes);
|
---|
683 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
---|
684 | DEBUG(0,("db_tdb2_receive_changes: failed to pull changes: %s\n",
|
---|
685 | nt_errstr(ndr_map_error2ntstatus(ndr_err))));
|
---|
686 | goto done;
|
---|
687 | }
|
---|
688 |
|
---|
689 | if(DEBUGLEVEL >= 10) {
|
---|
690 | NDR_PRINT_DEBUG(dbwrap_tdb2_changes, &changes);
|
---|
691 | }
|
---|
692 |
|
---|
693 | /* open the db, this will sync it */
|
---|
694 | db = db_open_tdb2_ex(talloc_tos(), changes.name, 0,
|
---|
695 | 0, O_RDWR, 0600, &changes);
|
---|
696 | TALLOC_FREE(db);
|
---|
697 | done:
|
---|
698 | return;
|
---|
699 | }
|
---|
700 |
|
---|
701 | static int db_tdb2_transaction_commit(struct db_context *db)
|
---|
702 | {
|
---|
703 | struct db_tdb2_ctx *db_ctx =
|
---|
704 | talloc_get_type_abort(db->private_data, struct db_tdb2_ctx);
|
---|
705 | int ret;
|
---|
706 | uint32_t mseqnum;
|
---|
707 |
|
---|
708 | if (db_ctx->transaction == 0) {
|
---|
709 | return -1;
|
---|
710 | } else if (db_ctx->transaction > 1) {
|
---|
711 | db_ctx->transaction--;
|
---|
712 | return 0;
|
---|
713 | }
|
---|
714 |
|
---|
715 | mseqnum = tdb_get_seqnum(db_ctx->mtdb->tdb);
|
---|
716 | db_ctx->changes.new_seqnum = mseqnum;
|
---|
717 |
|
---|
718 | /* first commit to the master copy */
|
---|
719 | ret = tdb_transaction_commit(db_ctx->mtdb->tdb);
|
---|
720 | db_ctx->master_transaction = false;
|
---|
721 | if (ret != 0) {
|
---|
722 | int saved_errno = errno;
|
---|
723 | db_tdb2_transaction_cancel(db);
|
---|
724 | errno = saved_errno;
|
---|
725 | return ret;
|
---|
726 | }
|
---|
727 |
|
---|
728 | /*
|
---|
729 | * Note: as we've already commited the changes to the master copy
|
---|
730 | * so we ignore errors in the following functions
|
---|
731 | */
|
---|
732 | ret = db_tdb2_commit_local(db_ctx, mseqnum);
|
---|
733 | if (ret == 0) {
|
---|
734 | db_ctx->out_of_sync = false;
|
---|
735 | } else {
|
---|
736 | db_ctx->out_of_sync = true;
|
---|
737 | }
|
---|
738 |
|
---|
739 | db_ctx->transaction = 0;
|
---|
740 |
|
---|
741 | db_tdb2_close_master(db_ctx);
|
---|
742 |
|
---|
743 | db_tdb2_send_notify(db_ctx);
|
---|
744 |
|
---|
745 | return 0;
|
---|
746 | }
|
---|
747 |
|
---|
748 | static int db_tdb2_transaction_cancel(struct db_context *db)
|
---|
749 | {
|
---|
750 | struct db_tdb2_ctx *db_ctx =
|
---|
751 | talloc_get_type_abort(db->private_data, struct db_tdb2_ctx);
|
---|
752 | int saved_errno;
|
---|
753 | int ret;
|
---|
754 |
|
---|
755 | if (db_ctx->transaction == 0) {
|
---|
756 | return -1;
|
---|
757 | }
|
---|
758 | if (db_ctx->transaction > 1) {
|
---|
759 | db_ctx->transaction--;
|
---|
760 | return 0;
|
---|
761 | }
|
---|
762 |
|
---|
763 | /* cancel the transaction and close the master copy */
|
---|
764 | ret = db_tdb2_close_master(db_ctx);
|
---|
765 | saved_errno = errno;
|
---|
766 |
|
---|
767 | /* now cancel on the local copy and ignore any error */
|
---|
768 | tdb_transaction_cancel(db_ctx->ltdb->tdb);
|
---|
769 | db_ctx->local_transaction = false;
|
---|
770 |
|
---|
771 | db_ctx->transaction = 0;
|
---|
772 |
|
---|
773 | errno = saved_errno;
|
---|
774 | return ret;
|
---|
775 | }
|
---|
776 |
|
---|
777 | static int db_tdb2_open_master(struct db_tdb2_ctx *db_ctx, bool transaction,
|
---|
778 | const struct dbwrap_tdb2_changes *changes)
|
---|
779 | {
|
---|
780 | int ret;
|
---|
781 |
|
---|
782 | db_ctx->mtdb = tdb_wrap_open(db_ctx,
|
---|
783 | db_ctx->mtdb_path,
|
---|
784 | db_ctx->open.hash_size,
|
---|
785 | db_ctx->open.tdb_flags|TDB_NOMMAP|TDB_SEQNUM,
|
---|
786 | db_ctx->open.open_flags,
|
---|
787 | db_ctx->open.mode);
|
---|
788 | if (db_ctx->mtdb == NULL) {
|
---|
789 | DEBUG(0, ("Could not open master tdb[%s]: %s\n",
|
---|
790 | db_ctx->mtdb_path,
|
---|
791 | strerror(errno)));
|
---|
792 | return -1;
|
---|
793 | }
|
---|
794 | DEBUG(10,("open_master[%s]\n", db_ctx->mtdb_path));
|
---|
795 |
|
---|
796 | if (!db_ctx->ltdb) {
|
---|
797 | struct stat st;
|
---|
798 |
|
---|
799 | if (fstat(tdb_fd(db_ctx->mtdb->tdb), &st) == 0) {
|
---|
800 | db_ctx->open.mode = st.st_mode;
|
---|
801 | }
|
---|
802 |
|
---|
803 | /* make sure the local one uses the same hash size as the master one */
|
---|
804 | db_ctx->open.hash_size = tdb_hash_size(db_ctx->mtdb->tdb);
|
---|
805 |
|
---|
806 | db_ctx->ltdb = tdb_wrap_open(db_ctx,
|
---|
807 | db_ctx->ltdb_path,
|
---|
808 | db_ctx->open.hash_size,
|
---|
809 | db_ctx->open.tdb_flags|TDB_SEQNUM,
|
---|
810 | db_ctx->open.open_flags|O_CREAT,
|
---|
811 | db_ctx->open.mode);
|
---|
812 | if (db_ctx->ltdb == NULL) {
|
---|
813 | DEBUG(0, ("Could not open local tdb[%s]: %s\n",
|
---|
814 | db_ctx->ltdb_path,
|
---|
815 | strerror(errno)));
|
---|
816 | TALLOC_FREE(db_ctx->mtdb);
|
---|
817 | return -1;
|
---|
818 | }
|
---|
819 | DEBUG(10,("open_local[%s]\n", db_ctx->ltdb_path));
|
---|
820 | }
|
---|
821 |
|
---|
822 | if (transaction) {
|
---|
823 | ret = tdb_transaction_start(db_ctx->mtdb->tdb);
|
---|
824 | if (ret != 0) {
|
---|
825 | DEBUG(0,("open failed to start transaction[%s]\n",
|
---|
826 | db_ctx->mtdb_path));
|
---|
827 | db_tdb2_close_master(db_ctx);
|
---|
828 | return ret;
|
---|
829 | }
|
---|
830 | db_ctx->master_transaction = true;
|
---|
831 | }
|
---|
832 |
|
---|
833 | ret = db_tdb2_sync_from_master(db_ctx, changes);
|
---|
834 | if (ret != 0) {
|
---|
835 | DEBUG(0,("open failed to sync from master[%s]\n",
|
---|
836 | db_ctx->ltdb_path));
|
---|
837 | db_tdb2_close_master(db_ctx);
|
---|
838 | return ret;
|
---|
839 | }
|
---|
840 |
|
---|
841 | return 0;
|
---|
842 | }
|
---|
843 |
|
---|
844 | static int db_tdb2_commit_local(struct db_tdb2_ctx *db_ctx, uint32_t mseqnum)
|
---|
845 | {
|
---|
846 | bool ok;
|
---|
847 | int ret;
|
---|
848 |
|
---|
849 | /* first fetch the master seqnum */
|
---|
850 | db_ctx->mseqnum = mseqnum;
|
---|
851 |
|
---|
852 | /* now we try to store the master seqnum in the local tdb */
|
---|
853 | ok = tdb_store_uint32_byblob(db_ctx->ltdb->tdb,
|
---|
854 | db_ctx->mseqkey,
|
---|
855 | db_ctx->mseqnum);
|
---|
856 | if (!ok) {
|
---|
857 | tdb_transaction_cancel(db_ctx->ltdb->tdb);
|
---|
858 | db_ctx->local_transaction = false;
|
---|
859 | DEBUG(0,("local failed[%s] store mseq[%u]\n",
|
---|
860 | db_ctx->ltdb_path, db_ctx->mseqnum));
|
---|
861 | return -1;
|
---|
862 | }
|
---|
863 |
|
---|
864 | /* now commit all changes to the local tdb */
|
---|
865 | ret = tdb_transaction_commit(db_ctx->ltdb->tdb);
|
---|
866 | db_ctx->local_transaction = false;
|
---|
867 | if (ret != 0) {
|
---|
868 | DEBUG(0,("local failed[%s] commit mseq[%u]\n",
|
---|
869 | db_ctx->ltdb_path, db_ctx->mseqnum));
|
---|
870 | return ret;
|
---|
871 | }
|
---|
872 |
|
---|
873 | /*
|
---|
874 | * and update the cached local seqnum this is needed to
|
---|
875 | * let us cache the master seqnum.
|
---|
876 | */
|
---|
877 | db_ctx->lseqnum = tdb_get_seqnum(db_ctx->ltdb->tdb);
|
---|
878 | DEBUG(10,("local updated[%s] mseq[%u]\n",
|
---|
879 | db_ctx->ltdb_path, db_ctx->mseqnum));
|
---|
880 |
|
---|
881 | return 0;
|
---|
882 | }
|
---|
883 |
|
---|
884 | static int db_tdb2_close_master(struct db_tdb2_ctx *db_ctx)
|
---|
885 | {
|
---|
886 | if (db_ctx->master_transaction) {
|
---|
887 | tdb_transaction_cancel(db_ctx->mtdb->tdb);
|
---|
888 | }
|
---|
889 | db_ctx->master_transaction = false;
|
---|
890 | /* now we can close the master handle */
|
---|
891 | TALLOC_FREE(db_ctx->mtdb);
|
---|
892 |
|
---|
893 | DEBUG(10,("close_master[%s] ok\n", db_ctx->mtdb_path));
|
---|
894 | return 0;
|
---|
895 | }
|
---|
896 |
|
---|
897 | static int db_tdb2_traverse_sync_all_func(TDB_CONTEXT *tdb,
|
---|
898 | TDB_DATA kbuf, TDB_DATA dbuf,
|
---|
899 | void *private_data)
|
---|
900 | {
|
---|
901 | struct db_tdb2_traverse_ctx *ctx =
|
---|
902 | (struct db_tdb2_traverse_ctx *)private_data;
|
---|
903 | uint32_t *seqnum = (uint32_t *)ctx->private_data;
|
---|
904 | int ret;
|
---|
905 |
|
---|
906 | DEBUG(10,("sync_entry[%s]\n", ctx->db_ctx->mtdb_path));
|
---|
907 |
|
---|
908 | /* Do not accidently allocate/deallocate w/o need when debug level is lower than needed */
|
---|
909 | if(DEBUGLEVEL >= 10) {
|
---|
910 | char *keystr = hex_encode(NULL, (unsigned char*)kbuf.dptr, kbuf.dsize);
|
---|
911 | DEBUG(10, (DEBUGLEVEL > 10
|
---|
912 | ? "Locking key %s\n" : "Locking key %.20s\n",
|
---|
913 | keystr));
|
---|
914 | TALLOC_FREE(keystr);
|
---|
915 | }
|
---|
916 |
|
---|
917 | ret = tdb_store(ctx->db_ctx->ltdb->tdb, kbuf, dbuf, TDB_INSERT);
|
---|
918 | if (ret != 0) {
|
---|
919 | DEBUG(0,("sync_entry[%s] %d: %s\n",
|
---|
920 | ctx->db_ctx->ltdb_path, ret,
|
---|
921 | tdb_errorstr(ctx->db_ctx->ltdb->tdb)));
|
---|
922 | return ret;
|
---|
923 | }
|
---|
924 |
|
---|
925 | *seqnum = tdb_get_seqnum(ctx->db_ctx->mtdb->tdb);
|
---|
926 |
|
---|
927 | return 0;
|
---|
928 | }
|
---|
929 |
|
---|
930 | static int db_tdb2_sync_all(struct db_tdb2_ctx *db_ctx, uint32_t *seqnum)
|
---|
931 | {
|
---|
932 | struct db_tdb2_traverse_ctx ctx;
|
---|
933 | int ret;
|
---|
934 |
|
---|
935 | ret = tdb_wipe_all(db_ctx->ltdb->tdb);
|
---|
936 | if (ret != 0) {
|
---|
937 | DEBUG(0,("tdb_wipe_all[%s] failed %d: %s\n",
|
---|
938 | db_ctx->ltdb_path, ret,
|
---|
939 | tdb_errorstr(db_ctx->ltdb->tdb)));
|
---|
940 | return ret;
|
---|
941 | }
|
---|
942 |
|
---|
943 | ctx.db_ctx = db_ctx;
|
---|
944 | ctx.f = NULL;
|
---|
945 | ctx.private_data = seqnum;
|
---|
946 | ret = tdb_traverse_read(db_ctx->mtdb->tdb,
|
---|
947 | db_tdb2_traverse_sync_all_func,
|
---|
948 | &ctx);
|
---|
949 | DEBUG(10,("db_tdb2_sync_all[%s] count[%d]\n",
|
---|
950 | db_ctx->mtdb_path, ret));
|
---|
951 | if (ret < 0) {
|
---|
952 | return ret;
|
---|
953 | }
|
---|
954 |
|
---|
955 | return 0;
|
---|
956 | }
|
---|
957 |
|
---|
958 | static int db_tdb2_sync_changes(struct db_tdb2_ctx *db_ctx,
|
---|
959 | const struct dbwrap_tdb2_changes *changes,
|
---|
960 | uint32_t *seqnum)
|
---|
961 | {
|
---|
962 | uint32_t cseqnum;
|
---|
963 | uint32_t mseqnum;
|
---|
964 | uint32_t i;
|
---|
965 | int ret;
|
---|
966 | bool need_full_sync = false;
|
---|
967 |
|
---|
968 | DEBUG(10,("db_tdb2_sync_changes[%s] changes[%u]\n",
|
---|
969 | changes->name, changes->num_changes));
|
---|
970 | if(DEBUGLEVEL >= 10) {
|
---|
971 | NDR_PRINT_DEBUG(dbwrap_tdb2_changes, discard_const(changes));
|
---|
972 | }
|
---|
973 |
|
---|
974 | /* for the master tdb for reading */
|
---|
975 | ret = tdb_lockall_read(db_ctx->mtdb->tdb);
|
---|
976 | if (ret != 0) {
|
---|
977 | DEBUG(0,("tdb_lockall_read[%s] %d\n", db_ctx->mtdb_path, ret));
|
---|
978 | return ret;
|
---|
979 | }
|
---|
980 |
|
---|
981 | /* first fetch seqnum we know about */
|
---|
982 | cseqnum = db_tdb2_get_seqnum(db_ctx->db);
|
---|
983 |
|
---|
984 | /* then fetch the master seqnum */
|
---|
985 | mseqnum = tdb_get_seqnum(db_ctx->mtdb->tdb);
|
---|
986 |
|
---|
987 | if (cseqnum == mseqnum) {
|
---|
988 | DEBUG(10,("db_tdb2_sync_changes[%s] uptodate[%u]\n",
|
---|
989 | db_ctx->mtdb_path, mseqnum));
|
---|
990 | /* we hit a race before and now noticed we're uptodate */
|
---|
991 | goto done;
|
---|
992 | }
|
---|
993 |
|
---|
994 | /* now see if the changes describe what we need */
|
---|
995 | if (changes->old_seqnum != cseqnum) {
|
---|
996 | need_full_sync = true;
|
---|
997 | }
|
---|
998 |
|
---|
999 | if (changes->new_seqnum != mseqnum) {
|
---|
1000 | need_full_sync = true;
|
---|
1001 | }
|
---|
1002 |
|
---|
1003 | /* this was the overflow case */
|
---|
1004 | if (changes->num_keys == 0) {
|
---|
1005 | need_full_sync = true;
|
---|
1006 | }
|
---|
1007 |
|
---|
1008 | if (need_full_sync) {
|
---|
1009 | tdb_unlockall_read(db_ctx->mtdb->tdb);
|
---|
1010 | DEBUG(0,("fallback to full sync[%s] seq[%u=>%u] keys[%u]\n",
|
---|
1011 | db_ctx->ltdb_path, cseqnum, mseqnum,
|
---|
1012 | changes->num_keys));
|
---|
1013 | return db_tdb2_sync_all(db_ctx, &mseqnum);
|
---|
1014 | }
|
---|
1015 |
|
---|
1016 | for (i=0; i < changes->num_keys; i++) {
|
---|
1017 | const char *op = NULL;
|
---|
1018 | bool del = false;
|
---|
1019 | TDB_DATA key;
|
---|
1020 | TDB_DATA val;
|
---|
1021 |
|
---|
1022 | key.dsize = changes->keys[i].length;
|
---|
1023 | key.dptr = changes->keys[i].data;
|
---|
1024 |
|
---|
1025 | val = tdb_fetch(db_ctx->mtdb->tdb, key);
|
---|
1026 | ret = tdb_error(db_ctx->mtdb->tdb);
|
---|
1027 | if (ret == TDB_ERR_NOEXIST) {
|
---|
1028 | del = true;
|
---|
1029 | } else if (ret != 0) {
|
---|
1030 | DEBUG(0,("sync_changes[%s] failure %d\n",
|
---|
1031 | db_ctx->mtdb_path, ret));
|
---|
1032 | goto failed;
|
---|
1033 | }
|
---|
1034 |
|
---|
1035 | if (del) {
|
---|
1036 | op = "delete";
|
---|
1037 | ret = tdb_delete(db_ctx->ltdb->tdb, key);
|
---|
1038 | DEBUG(10,("sync_changes[%s] delete key[%u] %d\n",
|
---|
1039 | db_ctx->mtdb_path, i, ret));
|
---|
1040 | } else {
|
---|
1041 | op = "store";
|
---|
1042 | ret = tdb_store(db_ctx->ltdb->tdb, key,
|
---|
1043 | val, TDB_REPLACE);
|
---|
1044 | DEBUG(10,("sync_changes[%s] store key[%u] %d\n",
|
---|
1045 | db_ctx->mtdb_path, i, ret));
|
---|
1046 | }
|
---|
1047 | SAFE_FREE(val.dptr);
|
---|
1048 | if (ret != 0) {
|
---|
1049 | DEBUG(0,("sync_changes[%s] %s key[%u] failed %d\n",
|
---|
1050 | db_ctx->mtdb_path, op, i, ret));
|
---|
1051 | goto failed;
|
---|
1052 | }
|
---|
1053 | }
|
---|
1054 |
|
---|
1055 | done:
|
---|
1056 | tdb_unlockall_read(db_ctx->mtdb->tdb);
|
---|
1057 |
|
---|
1058 | *seqnum = mseqnum;
|
---|
1059 | return 0;
|
---|
1060 | failed:
|
---|
1061 | tdb_unlockall_read(db_ctx->mtdb->tdb);
|
---|
1062 | return ret;
|
---|
1063 | }
|
---|
1064 |
|
---|
1065 | static int db_tdb2_sync_from_master(struct db_tdb2_ctx *db_ctx,
|
---|
1066 | const struct dbwrap_tdb2_changes *changes)
|
---|
1067 | {
|
---|
1068 | int ret;
|
---|
1069 | uint32_t cseqnum;
|
---|
1070 | uint32_t mseqnum;
|
---|
1071 | bool force = false;
|
---|
1072 |
|
---|
1073 | /* first fetch seqnum we know about */
|
---|
1074 | cseqnum = db_tdb2_get_seqnum(db_ctx->db);
|
---|
1075 |
|
---|
1076 | /* then fetch the master seqnum */
|
---|
1077 | mseqnum = tdb_get_seqnum(db_ctx->mtdb->tdb);
|
---|
1078 |
|
---|
1079 | if (db_ctx->lseqnum == 0) {
|
---|
1080 | force = true;
|
---|
1081 | }
|
---|
1082 |
|
---|
1083 | if (!force && cseqnum == mseqnum) {
|
---|
1084 | DEBUG(10,("uptodate[%s] mseq[%u]\n",
|
---|
1085 | db_ctx->ltdb_path, mseqnum));
|
---|
1086 | /* the local copy is uptodate, close the master db */
|
---|
1087 | return 0;
|
---|
1088 | }
|
---|
1089 | DEBUG(10,("not uptodate[%s] seq[%u=>%u]\n",
|
---|
1090 | db_ctx->ltdb_path, cseqnum, mseqnum));
|
---|
1091 |
|
---|
1092 | ret = tdb_transaction_start(db_ctx->ltdb->tdb);
|
---|
1093 | if (ret != 0) {
|
---|
1094 | DEBUG(0,("failed to start transaction[%s] %d: %s\n",
|
---|
1095 | db_ctx->ltdb_path, ret,
|
---|
1096 | tdb_errorstr(db_ctx->ltdb->tdb)));
|
---|
1097 | db_ctx->out_of_sync = true;
|
---|
1098 | return ret;
|
---|
1099 | }
|
---|
1100 | db_ctx->local_transaction = true;
|
---|
1101 |
|
---|
1102 | if (changes && !force) {
|
---|
1103 | ret = db_tdb2_sync_changes(db_ctx, changes, &mseqnum);
|
---|
1104 | if (ret != 0) {
|
---|
1105 | db_ctx->out_of_sync = true;
|
---|
1106 | tdb_transaction_cancel(db_ctx->ltdb->tdb);
|
---|
1107 | db_ctx->local_transaction = false;
|
---|
1108 | return ret;
|
---|
1109 | }
|
---|
1110 | } else {
|
---|
1111 | ret = db_tdb2_sync_all(db_ctx, &mseqnum);
|
---|
1112 | if (ret != 0) {
|
---|
1113 | db_ctx->out_of_sync = true;
|
---|
1114 | tdb_transaction_cancel(db_ctx->ltdb->tdb);
|
---|
1115 | db_ctx->local_transaction = false;
|
---|
1116 | return ret;
|
---|
1117 | }
|
---|
1118 | }
|
---|
1119 |
|
---|
1120 | ret = db_tdb2_commit_local(db_ctx, mseqnum);
|
---|
1121 | if (ret != 0) {
|
---|
1122 | db_ctx->out_of_sync = true;
|
---|
1123 | return ret;
|
---|
1124 | }
|
---|
1125 |
|
---|
1126 | db_ctx->out_of_sync = false;
|
---|
1127 |
|
---|
1128 | return 0;
|
---|
1129 | }
|
---|
1130 |
|
---|
1131 | static int db_tdb2_ctx_destructor(struct db_tdb2_ctx *db_tdb2)
|
---|
1132 | {
|
---|
1133 | db_tdb2_close_master(db_tdb2);
|
---|
1134 | if (db_tdb2->local_transaction) {
|
---|
1135 | tdb_transaction_cancel(db_tdb2->ltdb->tdb);
|
---|
1136 | }
|
---|
1137 | db_tdb2->local_transaction = false;
|
---|
1138 | TALLOC_FREE(db_tdb2->ltdb);
|
---|
1139 | return 0;
|
---|
1140 | }
|
---|
1141 |
|
---|
1142 | static struct db_context *db_open_tdb2_ex(TALLOC_CTX *mem_ctx,
|
---|
1143 | const char *name,
|
---|
1144 | int hash_size, int tdb_flags,
|
---|
1145 | int open_flags, mode_t mode,
|
---|
1146 | const struct dbwrap_tdb2_changes *chgs)
|
---|
1147 | {
|
---|
1148 | struct db_context *result = NULL;
|
---|
1149 | struct db_tdb2_ctx *db_tdb2;
|
---|
1150 | int ret;
|
---|
1151 | const char *md;
|
---|
1152 | const char *ld;
|
---|
1153 | const char *bn;
|
---|
1154 |
|
---|
1155 | bn = strrchr_m(name, '/');
|
---|
1156 | if (bn) {
|
---|
1157 | bn++;
|
---|
1158 | DEBUG(3,("db_open_tdb2: use basename[%s] of abspath[%s]:\n",
|
---|
1159 | bn, name));
|
---|
1160 | } else {
|
---|
1161 | bn = name;
|
---|
1162 | }
|
---|
1163 |
|
---|
1164 | md = lp_parm_const_string(-1, "dbwrap_tdb2", "master directory", NULL);
|
---|
1165 | if (!md) {
|
---|
1166 | DEBUG(0,("'dbwrap_tdb2:master directory' empty\n"));
|
---|
1167 | goto fail;
|
---|
1168 | }
|
---|
1169 |
|
---|
1170 | ld = lp_parm_const_string(-1, "dbwrap_tdb2", "local directory", NULL);
|
---|
1171 | if (!ld) {
|
---|
1172 | DEBUG(0,("'dbwrap_tdb2:local directory' empty\n"));
|
---|
1173 | goto fail;
|
---|
1174 | }
|
---|
1175 |
|
---|
1176 | result = TALLOC_ZERO_P(mem_ctx, struct db_context);
|
---|
1177 | if (result == NULL) {
|
---|
1178 | DEBUG(0, ("talloc failed\n"));
|
---|
1179 | goto fail;
|
---|
1180 | }
|
---|
1181 |
|
---|
1182 | result->private_data = db_tdb2 = TALLOC_ZERO_P(result, struct db_tdb2_ctx);
|
---|
1183 | if (db_tdb2 == NULL) {
|
---|
1184 | DEBUG(0, ("talloc failed\n"));
|
---|
1185 | goto fail;
|
---|
1186 | }
|
---|
1187 |
|
---|
1188 | db_tdb2->db = result;
|
---|
1189 |
|
---|
1190 | db_tdb2->open.hash_size = hash_size;
|
---|
1191 | db_tdb2->open.tdb_flags = tdb_flags;
|
---|
1192 | db_tdb2->open.open_flags= open_flags;
|
---|
1193 | db_tdb2->open.mode = mode;
|
---|
1194 |
|
---|
1195 | db_tdb2->max_buffer_size = lp_parm_ulong(-1, "dbwrap_tdb2",
|
---|
1196 | "notify buffer size", 512);
|
---|
1197 |
|
---|
1198 | db_tdb2->name = talloc_strdup(db_tdb2, bn);
|
---|
1199 | if (db_tdb2->name == NULL) {
|
---|
1200 | DEBUG(0, ("talloc_strdup failed\n"));
|
---|
1201 | goto fail;
|
---|
1202 | }
|
---|
1203 |
|
---|
1204 | db_tdb2->mtdb_path = talloc_asprintf(db_tdb2, "%s/%s",
|
---|
1205 | md, bn);
|
---|
1206 | if (db_tdb2->mtdb_path == NULL) {
|
---|
1207 | DEBUG(0, ("talloc_asprintf failed\n"));
|
---|
1208 | goto fail;
|
---|
1209 | }
|
---|
1210 |
|
---|
1211 | db_tdb2->ltdb_path = talloc_asprintf(db_tdb2, "%s/%s.tdb2",
|
---|
1212 | ld, bn);
|
---|
1213 | if (db_tdb2->ltdb_path == NULL) {
|
---|
1214 | DEBUG(0, ("talloc_asprintf failed\n"));
|
---|
1215 | goto fail;
|
---|
1216 | }
|
---|
1217 |
|
---|
1218 | db_tdb2->mseqkey = string_term_tdb_data(DB_TDB2_MASTER_SEQNUM_KEYSTR);
|
---|
1219 |
|
---|
1220 | /*
|
---|
1221 | * this implicit opens the local one if as it's not yet open
|
---|
1222 | * it syncs the local copy.
|
---|
1223 | */
|
---|
1224 | ret = db_tdb2_open_master(db_tdb2, false, chgs);
|
---|
1225 | if (ret != 0) {
|
---|
1226 | goto fail;
|
---|
1227 | }
|
---|
1228 |
|
---|
1229 | ret = db_tdb2_close_master(db_tdb2);
|
---|
1230 | if (ret != 0) {
|
---|
1231 | goto fail;
|
---|
1232 | }
|
---|
1233 |
|
---|
1234 | DEBUG(10,("db_open_tdb2[%s] opened with mseq[%u]\n",
|
---|
1235 | db_tdb2->name, db_tdb2->mseqnum));
|
---|
1236 |
|
---|
1237 | result->fetch_locked = db_tdb2_fetch_locked;
|
---|
1238 | result->fetch = db_tdb2_fetch;
|
---|
1239 | result->traverse = db_tdb2_traverse;
|
---|
1240 | result->traverse_read = db_tdb2_traverse_read;
|
---|
1241 | result->get_seqnum = db_tdb2_get_seqnum;
|
---|
1242 | result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
|
---|
1243 | result->transaction_start = db_tdb2_transaction_start;
|
---|
1244 | result->transaction_commit = db_tdb2_transaction_commit;
|
---|
1245 | result->transaction_cancel = db_tdb2_transaction_cancel;
|
---|
1246 |
|
---|
1247 | talloc_set_destructor(db_tdb2, db_tdb2_ctx_destructor);
|
---|
1248 |
|
---|
1249 | return result;
|
---|
1250 |
|
---|
1251 | fail:
|
---|
1252 | if (result != NULL) {
|
---|
1253 | TALLOC_FREE(result);
|
---|
1254 | }
|
---|
1255 | return NULL;
|
---|
1256 | }
|
---|
1257 |
|
---|
1258 | struct db_context *db_open_tdb2(TALLOC_CTX *mem_ctx,
|
---|
1259 | const char *name,
|
---|
1260 | int hash_size, int tdb_flags,
|
---|
1261 | int open_flags, mode_t mode)
|
---|
1262 | {
|
---|
1263 | return db_open_tdb2_ex(mem_ctx, name, hash_size,
|
---|
1264 | tdb_flags, open_flags, mode, NULL);
|
---|
1265 | }
|
---|