2 Partitions ldb module - management of metadata.tdb for sequence number
4 Copyright (C) Amitay Isaacs <amitay@samba.org> 2011
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "dsdb/samdb/ldb_modules/partition.h"
21 #include "system/filesys.h"
23 #define LDB_METADATA_SEQ_NUM "SEQ_NUM"
27 * Read a key with uint64 value
29 static int partition_metadata_get_uint64(struct ldb_module
*module
,
30 const char *key
, uint64_t *value
,
31 uint64_t default_value
)
33 struct partition_private_data
*data
;
34 struct tdb_context
*tdb
;
35 TDB_DATA tdb_key
, tdb_data
;
39 data
= talloc_get_type_abort(ldb_module_get_private(module
),
40 struct partition_private_data
);
42 if (!data
|| !data
->metadata
|| !data
->metadata
->db
) {
43 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
44 "partition_metadata: metadata tdb not initialized");
47 tmp_ctx
= talloc_new(NULL
);
48 if (tmp_ctx
== NULL
) {
49 return ldb_module_oom(module
);
52 tdb
= data
->metadata
->db
->tdb
;
54 tdb_key
.dptr
= (uint8_t *)discard_const_p(char, key
);
55 tdb_key
.dsize
= strlen(key
);
57 tdb_data
= tdb_fetch(tdb
, tdb_key
);
59 if (tdb_error(tdb
) == TDB_ERR_NOEXIST
) {
60 *value
= default_value
;
63 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
68 value_str
= talloc_strndup(tmp_ctx
, (char *)tdb_data
.dptr
, tdb_data
.dsize
);
69 if (value_str
== NULL
) {
70 SAFE_FREE(tdb_data
.dptr
);
72 return ldb_module_oom(module
);
75 *value
= strtoull(value_str
, NULL
, 10);
77 SAFE_FREE(tdb_data
.dptr
);
85 * Write a key with uin64 value
87 static int partition_metadata_set_uint64(struct ldb_module
*module
,
88 const char *key
, uint64_t value
,
91 struct partition_private_data
*data
;
92 struct tdb_context
*tdb
;
93 TDB_DATA tdb_key
, tdb_data
;
98 data
= talloc_get_type_abort(ldb_module_get_private(module
),
99 struct partition_private_data
);
101 if (!data
|| !data
->metadata
|| !data
->metadata
->db
) {
102 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
103 "partition_metadata: metadata tdb not initialized");
106 tmp_ctx
= talloc_new(NULL
);
107 if (tmp_ctx
== NULL
) {
108 return ldb_module_oom(module
);
111 tdb
= data
->metadata
->db
->tdb
;
113 value_str
= talloc_asprintf(tmp_ctx
, "%llu", (unsigned long long)value
);
114 if (value_str
== NULL
) {
115 talloc_free(tmp_ctx
);
116 return ldb_module_oom(module
);
119 tdb_key
.dptr
= (uint8_t *)discard_const_p(char, key
);
120 tdb_key
.dsize
= strlen(key
);
122 tdb_data
.dptr
= (uint8_t *)value_str
;
123 tdb_data
.dsize
= strlen(value_str
);
126 tdb_flag
= TDB_INSERT
;
128 tdb_flag
= TDB_MODIFY
;
131 if (tdb_store(tdb
, tdb_key
, tdb_data
, tdb_flag
) != 0) {
132 talloc_free(tmp_ctx
);
133 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
137 talloc_free(tmp_ctx
);
142 int partition_metadata_inc_schema_sequence(struct ldb_module
*module
)
144 struct partition_private_data
*data
;
148 data
= talloc_get_type_abort(ldb_module_get_private(module
),
149 struct partition_private_data
);
150 if (!data
|| !data
->metadata
) {
151 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
152 "partition_metadata: metadata not initialized");
155 if (data
->metadata
->in_transaction
== 0) {
156 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
157 "partition_metadata: increment sequence number without transaction");
159 ret
= partition_metadata_get_uint64(module
, DSDB_METADATA_SCHEMA_SEQ_NUM
, &value
, 0);
160 if (ret
!= LDB_SUCCESS
) {
165 ret
= partition_metadata_set_uint64(module
, DSDB_METADATA_SCHEMA_SEQ_NUM
, value
, false);
166 if (ret
== LDB_ERR_OPERATIONS_ERROR
) {
167 /* Modify failed, let's try the add */
168 ret
= partition_metadata_set_uint64(module
, DSDB_METADATA_SCHEMA_SEQ_NUM
, value
, true);
176 * Open sam.ldb.d/metadata.tdb.
178 static int partition_metadata_open(struct ldb_module
*module
, bool create
)
180 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
182 struct partition_private_data
*data
;
183 struct loadparm_context
*lp_ctx
;
184 const char *sam_name
;
185 char *filename
, *dirname
;
189 data
= talloc_get_type_abort(ldb_module_get_private(module
),
190 struct partition_private_data
);
191 if (!data
|| !data
->metadata
) {
192 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
193 "partition_metadata: metadata not initialized");
196 tmp_ctx
= talloc_new(NULL
);
197 if (tmp_ctx
== NULL
) {
198 return ldb_module_oom(module
);
201 sam_name
= (const char *)ldb_get_opaque(ldb
, "ldb_url");
202 if (strncmp("tdb://", sam_name
, 6) == 0) {
206 talloc_free(tmp_ctx
);
207 return ldb_operr(ldb
);
209 filename
= talloc_asprintf(tmp_ctx
, "%s.d/metadata.tdb", sam_name
);
211 talloc_free(tmp_ctx
);
217 open_flags
|= O_CREAT
;
219 /* While provisioning, sam.ldb.d directory may not exist,
220 * so create it. Ignore errors, if it already exists. */
221 dirname
= talloc_asprintf(tmp_ctx
, "%s.d", sam_name
);
223 talloc_free(tmp_ctx
);
227 mkdir(dirname
, 0700);
228 talloc_free(dirname
);
230 if (stat(filename
, &statbuf
) != 0) {
231 talloc_free(tmp_ctx
);
232 return LDB_ERR_OPERATIONS_ERROR
;
236 lp_ctx
= talloc_get_type_abort(ldb_get_opaque(ldb
, "loadparm"),
237 struct loadparm_context
);
239 data
->metadata
->db
= tdb_wrap_open(data
->metadata
, filename
, 10,
240 TDB_DEFAULT
, open_flags
, 0660,
242 if (data
->metadata
->db
== NULL
) {
243 talloc_free(tmp_ctx
);
245 ldb_debug(ldb
, LDB_DEBUG_ERROR
,
246 "partition_metadata: Unable to create %s",
249 return LDB_ERR_OPERATIONS_ERROR
;
252 talloc_free(tmp_ctx
);
258 * Set the sequence number calculated from older logic (sum of primary sequence
259 * numbers for each partition) as LDB_METADATA_SEQ_NUM key.
261 static int partition_metadata_set_sequence_number(struct ldb_module
*module
)
263 struct partition_private_data
*data
;
264 struct ldb_result
*res
;
265 struct ldb_request
*req
;
266 struct ldb_seqnum_request
*seq
;
267 struct ldb_seqnum_result
*seqr
;
268 struct ldb_extended
*ext
;
273 data
= talloc_get_type_abort(ldb_module_get_private(module
),
274 struct partition_private_data
);
275 if (!data
|| !data
->metadata
) {
276 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
277 "partition_metadata: metadata not initialized");
280 tmp_ctx
= talloc_new(data
->metadata
);
281 if (tmp_ctx
== NULL
) {
282 return ldb_module_oom(module
);
285 res
= talloc_zero(tmp_ctx
, struct ldb_result
);
287 talloc_free(tmp_ctx
);
288 return ldb_module_oom(module
);
291 seq
= talloc_zero(tmp_ctx
, struct ldb_seqnum_request
);
293 talloc_free(tmp_ctx
);
294 return ldb_module_oom(module
);
296 seq
->type
= LDB_SEQ_HIGHEST_SEQ
;
298 /* Build an extended request, so it can be passed to each partition in
299 partition_sequence_number_from_partitions() */
300 ret
= ldb_build_extended_req(&req
,
301 ldb_module_get_ctx(module
),
303 LDB_EXTENDED_SEQUENCE_NUMBER
,
307 ldb_extended_default_callback
,
309 LDB_REQ_SET_LOCATION(req
);
310 if (ret
!= LDB_SUCCESS
) {
311 talloc_free(tmp_ctx
);
315 ret
= partition_sequence_number_from_partitions(module
, req
, &ext
);
316 if (ret
!= LDB_SUCCESS
) {
317 talloc_free(tmp_ctx
);
321 seqr
= talloc_get_type_abort(ext
->data
, struct ldb_seqnum_result
);
322 seq_number
= seqr
->seq_num
;
324 talloc_free(tmp_ctx
);
326 return partition_metadata_set_uint64(module
, LDB_METADATA_SEQ_NUM
, seq_number
, true);
331 * Initialize metadata. Load metadata.tdb.
332 * If missing, create it and fill in sequence number
334 int partition_metadata_init(struct ldb_module
*module
)
336 struct partition_private_data
*data
;
339 data
= talloc_get_type_abort(ldb_module_get_private(module
),
340 struct partition_private_data
);
342 data
->metadata
= talloc_zero(data
, struct partition_metadata
);
343 if (data
->metadata
== NULL
) {
344 return ldb_module_oom(module
);
347 ret
= partition_metadata_open(module
, false);
348 if (ret
== LDB_SUCCESS
) {
352 /* metadata.tdb does not exist, create it */
353 DEBUG(2, ("partition_metadata: Migrating partition metadata\n"));
354 ret
= partition_metadata_open(module
, true);
355 if (ret
!= LDB_SUCCESS
) {
356 talloc_free(data
->metadata
);
357 data
->metadata
= NULL
;
361 ret
= partition_metadata_set_sequence_number(module
);
362 if (ret
!= LDB_SUCCESS
) {
363 talloc_free(data
->metadata
);
364 data
->metadata
= NULL
;
373 * Read the sequence number, default to 0 if LDB_METADATA_SEQ_NUM key is missing
375 int partition_metadata_sequence_number(struct ldb_module
*module
, uint64_t *value
)
377 return partition_metadata_get_uint64(module
,
378 LDB_METADATA_SEQ_NUM
,
385 * Increment the sequence number, returning the new sequence number
387 int partition_metadata_sequence_number_increment(struct ldb_module
*module
, uint64_t *value
)
389 struct partition_private_data
*data
;
392 data
= talloc_get_type_abort(ldb_module_get_private(module
),
393 struct partition_private_data
);
394 if (!data
|| !data
->metadata
) {
395 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
396 "partition_metadata: metadata not initialized");
399 if (data
->metadata
->in_transaction
== 0) {
400 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
401 "partition_metadata: increment sequence number without transaction");
404 ret
= partition_metadata_get_uint64(module
, LDB_METADATA_SEQ_NUM
, value
, 0);
405 if (ret
!= LDB_SUCCESS
) {
410 ret
= partition_metadata_set_uint64(module
, LDB_METADATA_SEQ_NUM
, *value
, false);
418 int partition_metadata_start_trans(struct ldb_module
*module
)
420 struct partition_private_data
*data
;
421 struct tdb_context
*tdb
;
423 data
= talloc_get_type_abort(ldb_module_get_private(module
),
424 struct partition_private_data
);
425 if (!data
|| !data
->metadata
|| !data
->metadata
->db
) {
426 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
427 "partition_metadata: metadata not initialized");
429 tdb
= data
->metadata
->db
->tdb
;
431 if (tdb_transaction_start(tdb
) != 0) {
432 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
436 data
->metadata
->in_transaction
++;
443 * Transaction prepare commit
445 int partition_metadata_prepare_commit(struct ldb_module
*module
)
447 struct partition_private_data
*data
;
448 struct tdb_context
*tdb
;
450 data
= talloc_get_type_abort(ldb_module_get_private(module
),
451 struct partition_private_data
);
452 if (!data
|| !data
->metadata
|| !data
->metadata
->db
) {
453 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
454 "partition_metadata: metadata not initialized");
456 tdb
= data
->metadata
->db
->tdb
;
458 if (data
->metadata
->in_transaction
== 0) {
459 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
460 "partition_metadata: not in transaction");
463 if (tdb_transaction_prepare_commit(tdb
) != 0) {
464 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
475 int partition_metadata_end_trans(struct ldb_module
*module
)
477 struct partition_private_data
*data
;
478 struct tdb_context
*tdb
;
480 data
= talloc_get_type_abort(ldb_module_get_private(module
),
481 struct partition_private_data
);
482 if (!data
|| !data
->metadata
|| !data
->metadata
->db
) {
483 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
484 "partition_metadata: metadata not initialized");
486 tdb
= data
->metadata
->db
->tdb
;
488 if (data
->metadata
->in_transaction
== 0) {
489 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
490 "partition_metadata: not in transaction");
493 data
->metadata
->in_transaction
--;
495 if (tdb_transaction_commit(tdb
) != 0) {
496 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
507 int partition_metadata_del_trans(struct ldb_module
*module
)
509 struct partition_private_data
*data
;
510 struct tdb_context
*tdb
;
512 data
= talloc_get_type_abort(ldb_module_get_private(module
),
513 struct partition_private_data
);
514 if (!data
|| !data
->metadata
|| !data
->metadata
->db
) {
515 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
516 "partition_metadata: metadata not initialized");
518 tdb
= data
->metadata
->db
->tdb
;
520 if (data
->metadata
->in_transaction
== 0) {
521 return ldb_module_error(module
, LDB_ERR_OPERATIONS_ERROR
,
522 "partition_metadata: not in transaction");
525 data
->metadata
->in_transaction
--;
527 tdb_transaction_cancel(tdb
);