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_compat(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,
64 tdb_errorstr_compat(tdb));
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,
134 tdb_errorstr_compat(tdb));
137 talloc_free(tmp_ctx);
144 * Open sam.ldb.d/metadata.tdb.
146 static int partition_metadata_open(struct ldb_module *module, bool create)
148 struct ldb_context *ldb = ldb_module_get_ctx(module);
150 struct partition_private_data *data;
151 struct loadparm_context *lp_ctx;
152 const char *sam_name;
153 char *filename, *dirname;
156 data = talloc_get_type_abort(ldb_module_get_private(module),
157 struct partition_private_data);
158 if (!data || !data->metadata) {
159 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
160 "partition_metadata: metadata not initialized");
163 tmp_ctx = talloc_new(NULL);
164 if (tmp_ctx == NULL) {
165 return ldb_module_oom(module);
168 sam_name = (const char *)ldb_get_opaque(ldb, "ldb_url");
169 if (strncmp("tdb://", sam_name, 6) == 0) {
173 talloc_free(tmp_ctx);
174 return ldb_operr(ldb);
176 filename = talloc_asprintf(tmp_ctx, "%s.d/metadata.tdb", sam_name);
178 talloc_free(tmp_ctx);
184 open_flags |= O_CREAT;
186 /* While provisioning, sam.ldb.d directory may not exist,
187 * so create it. Ignore errors, if it already exists. */
188 dirname = talloc_asprintf(tmp_ctx, "%s.d", sam_name);
190 talloc_free(tmp_ctx);
194 mkdir(dirname, 0700);
195 talloc_free(dirname);
198 lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
199 struct loadparm_context);
201 data->metadata->db = tdb_wrap_open(data->metadata, filename, 10,
202 TDB_DEFAULT, open_flags, 0660,
204 if (data->metadata->db == NULL) {
205 talloc_free(tmp_ctx);
207 ldb_debug(ldb, LDB_DEBUG_ERROR,
208 "partition_metadata: Unable to create %s",
211 return LDB_ERR_OPERATIONS_ERROR;
214 talloc_free(tmp_ctx);
220 * Set the sequence number calculated from older logic (sum of primary sequence
221 * numbers for each partition) as LDB_METADATA_SEQ_NUM key.
223 static int partition_metadata_set_sequence_number(struct ldb_module *module)
225 struct partition_private_data *data;
226 struct ldb_result *res;
227 struct ldb_request *req;
228 struct ldb_seqnum_request *seq;
229 struct ldb_seqnum_result *seqr;
230 struct ldb_extended *ext;
235 data = talloc_get_type_abort(ldb_module_get_private(module),
236 struct partition_private_data);
237 if (!data || !data->metadata) {
238 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
239 "partition_metadata: metadata not initialized");
242 tmp_ctx = talloc_new(data->metadata);
243 if (tmp_ctx == NULL) {
244 return ldb_module_oom(module);
247 res = talloc_zero(tmp_ctx, struct ldb_result);
249 talloc_free(tmp_ctx);
250 return ldb_module_oom(module);
253 seq = talloc_zero(tmp_ctx, struct ldb_seqnum_request);
255 talloc_free(tmp_ctx);
256 return ldb_module_oom(module);
258 seq->type = LDB_SEQ_HIGHEST_SEQ;
260 /* Build an extended request, so it can be passed to each partition in
261 partition_sequence_number_from_partitions() */
262 ret = ldb_build_extended_req(&req,
263 ldb_module_get_ctx(module),
265 LDB_EXTENDED_SEQUENCE_NUMBER,
269 ldb_extended_default_callback,
271 LDB_REQ_SET_LOCATION(req);
272 if (ret != LDB_SUCCESS) {
273 talloc_free(tmp_ctx);
277 ret = partition_sequence_number_from_partitions(module, req, &ext);
278 if (ret != LDB_SUCCESS) {
279 talloc_free(tmp_ctx);
283 seqr = talloc_get_type_abort(ext->data, struct ldb_seqnum_result);
284 seq_number = seqr->seq_num;
286 talloc_free(tmp_ctx);
288 return partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, seq_number, true);
293 * Initialize metadata. Load metadata.tdb.
294 * If missing, create it and fill in sequence number
296 int partition_metadata_init(struct ldb_module *module)
298 struct partition_private_data *data;
301 data = talloc_get_type_abort(ldb_module_get_private(module),
302 struct partition_private_data);
304 data->metadata = talloc_zero(data, struct partition_metadata);
305 if (data->metadata == NULL) {
306 return ldb_module_oom(module);
309 ret = partition_metadata_open(module, false);
310 if (ret == LDB_SUCCESS) {
314 /* metadata.tdb does not exist, create it */
315 DEBUG(2, ("partition_metadata: Migrating partition metadata\n"));
316 ret = partition_metadata_open(module, true);
317 if (ret != LDB_SUCCESS) {
318 talloc_free(data->metadata);
319 data->metadata = NULL;
323 ret = partition_metadata_set_sequence_number(module);
324 if (ret != LDB_SUCCESS) {
325 talloc_free(data->metadata);
326 data->metadata = NULL;
335 * Read the sequence number, default to 0 if LDB_METADATA_SEQ_NUM key is missing
337 int partition_metadata_sequence_number(struct ldb_module *module, uint64_t *value)
339 return partition_metadata_get_uint64(module,
340 LDB_METADATA_SEQ_NUM,
347 * Increment the sequence number, returning the new sequence number
349 int partition_metadata_sequence_number_increment(struct ldb_module *module, uint64_t *value)
351 struct partition_private_data *data;
354 data = talloc_get_type_abort(ldb_module_get_private(module),
355 struct partition_private_data);
356 if (!data && !data->metadata) {
357 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
358 "partition_metadata: metadata not initialized");
361 if (data->metadata->in_transaction == 0) {
362 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
363 "partition_metadata: increment sequence number without transaction");
366 ret = partition_metadata_get_uint64(module, LDB_METADATA_SEQ_NUM, value, 0);
367 if (ret != LDB_SUCCESS) {
372 ret = partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, *value, false);
380 int partition_metadata_start_trans(struct ldb_module *module)
382 struct partition_private_data *data;
383 struct tdb_context *tdb;
385 data = talloc_get_type_abort(ldb_module_get_private(module),
386 struct partition_private_data);
387 if (!data && !data->metadata && !data->metadata->db) {
388 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
389 "partition_metadata: metadata not initialized");
391 tdb = data->metadata->db->tdb;
393 if (tdb_transaction_start(tdb) != 0) {
394 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
395 tdb_errorstr_compat(tdb));
398 data->metadata->in_transaction++;
405 * Transaction prepare commit
407 int partition_metadata_prepare_commit(struct ldb_module *module)
409 struct partition_private_data *data;
410 struct tdb_context *tdb;
412 data = talloc_get_type_abort(ldb_module_get_private(module),
413 struct partition_private_data);
414 if (!data && !data->metadata && !data->metadata->db) {
415 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
416 "partition_metadata: metadata not initialized");
418 tdb = data->metadata->db->tdb;
420 if (data->metadata->in_transaction == 0) {
421 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
422 "partition_metadata: not in transaction");
425 if (tdb_transaction_prepare_commit(tdb) != 0) {
426 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
427 tdb_errorstr_compat(tdb));
437 int partition_metadata_end_trans(struct ldb_module *module)
439 struct partition_private_data *data;
440 struct tdb_context *tdb;
442 data = talloc_get_type_abort(ldb_module_get_private(module),
443 struct partition_private_data);
444 if (!data && !data->metadata && !data->metadata->db) {
445 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
446 "partition_metadata: metadata not initialized");
448 tdb = data->metadata->db->tdb;
450 if (data->metadata->in_transaction == 0) {
451 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
452 "partition_metadata: not in transaction");
455 data->metadata->in_transaction--;
457 if (tdb_transaction_commit(tdb) != 0) {
458 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
459 tdb_errorstr_compat(tdb));
469 int partition_metadata_del_trans(struct ldb_module *module)
471 struct partition_private_data *data;
472 struct tdb_context *tdb;
474 data = talloc_get_type_abort(ldb_module_get_private(module),
475 struct partition_private_data);
476 if (!data && !data->metadata && !data->metadata->db) {
477 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
478 "partition_metadata: metadata not initialized");
480 tdb = data->metadata->db->tdb;
482 if (data->metadata->in_transaction == 0) {
483 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
484 "partition_metadata: not in transaction");
487 data->metadata->in_transaction--;
489 tdb_transaction_cancel(tdb);