4 Copyright (C) Andrew Tridgell 2007
5 Copyright (C) Ronnie Sahlberg 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "lib/events/events.h"
23 #include "system/filesys.h"
24 #include "system/wait.h"
26 #include "lib/tdb/include/tdb.h"
27 #include "include/ctdb_protocol.h"
28 #include "include/ctdb_private.h"
30 struct ctdb_persistent_state {
31 struct ctdb_context *ctdb;
32 struct ctdb_req_control *c;
36 uint32_t num_failed, num_sent;
40 1) all nodes fail, and all nodes reply
41 2) some nodes fail, all nodes reply
47 called when a node has acknowledged a ctdb_control_update_record call
49 static void ctdb_persistent_callback(struct ctdb_context *ctdb,
50 int32_t status, TDB_DATA data,
54 struct ctdb_persistent_state *state = talloc_get_type(private_data,
55 struct ctdb_persistent_state);
58 DEBUG(DEBUG_ERR,("ctdb_persistent_callback failed with status %d (%s)\n",
60 state->status = status;
61 state->errormsg = errormsg;
65 if (state->num_pending == 0) {
66 enum ctdb_trans2_commit_error etype;
67 if (state->num_failed == state->num_sent) {
68 etype = CTDB_TRANS2_COMMIT_ALLFAIL;
69 } else if (state->num_failed != 0) {
70 etype = CTDB_TRANS2_COMMIT_SOMEFAIL;
72 etype = CTDB_TRANS2_COMMIT_SUCCESS;
74 ctdb_request_control_reply(state->ctdb, state->c, NULL, etype, state->errormsg);
80 called if persistent store times out
82 static void ctdb_persistent_store_timeout(struct event_context *ev, struct timed_event *te,
83 struct timeval t, void *private_data)
85 struct ctdb_persistent_state *state = talloc_get_type(private_data, struct ctdb_persistent_state);
87 ctdb_request_control_reply(state->ctdb, state->c, NULL, CTDB_TRANS2_COMMIT_TIMEOUT,
88 "timeout in ctdb_persistent_state");
94 store a set of persistent records - called from a ctdb client when it has updated
95 some records in a persistent database. The client will have the record
96 locked for the duration of this call. The client is the dmaster when
99 int32_t ctdb_control_trans2_commit(struct ctdb_context *ctdb,
100 struct ctdb_req_control *c,
101 TDB_DATA recdata, bool *async_reply)
103 struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
104 struct ctdb_persistent_state *state;
106 struct ctdb_marshall_buffer *m = (struct ctdb_marshall_buffer *)recdata.dptr;
107 struct ctdb_db_context *ctdb_db;
109 ctdb_db = find_ctdb_db(ctdb, m->db_id);
110 if (ctdb_db == NULL) {
111 DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans2_commit: "
112 "Unknown database db_id[0x%08x]\n", m->db_id));
116 if (client == NULL) {
117 DEBUG(DEBUG_ERR,(__location__ " can not match persistent_store to a client. Returning error\n"));
121 if (ctdb_db->unhealthy_reason) {
122 DEBUG(DEBUG_ERR,("db(%s) unhealty in ctdb_control_trans2_commit: %s\n",
123 ctdb_db->db_name, ctdb_db->unhealthy_reason));
127 /* handling num_persistent_updates is a bit strange -
129 1) very old clients, which never called CTDB_CONTROL_START_PERSISTENT_UPDATE
130 They don't expect num_persistent_updates to be used at all
132 2) less old clients, which uses CTDB_CONTROL_START_PERSISTENT_UPDATE, and expected
133 this commit to then decrement it
135 3) new clients which use TRANS2 commit functions, and
136 expect this function to increment the counter, and
137 then have it decremented in ctdb_control_trans2_error
138 or ctdb_control_trans2_finished
141 case CTDB_CONTROL_PERSISTENT_STORE:
142 if (ctdb_db->transaction_active) {
143 DEBUG(DEBUG_ERR, (__location__ " trans2_commit: a "
144 "transaction is active on database "
145 "db_id[0x%08x] - refusing persistent "
146 " store for client id[0x%08x]\n",
147 ctdb_db->db_id, client->client_id));
150 if (client->num_persistent_updates > 0) {
151 client->num_persistent_updates--;
154 case CTDB_CONTROL_TRANS2_COMMIT:
155 if (ctdb_db->transaction_active) {
156 DEBUG(DEBUG_ERR,(__location__ " trans2_commit: there is"
157 " already a transaction commit "
158 "active on db_id[0x%08x] - forbidding "
159 "client_id[0x%08x] to commit\n",
160 ctdb_db->db_id, client->client_id));
163 if (client->db_id != 0) {
164 DEBUG(DEBUG_ERR,(__location__ " ERROR: trans2_commit: "
165 "client-db_id[0x%08x] != 0 "
166 "(client_id[0x%08x])\n",
167 client->db_id, client->client_id));
170 client->num_persistent_updates++;
171 ctdb_db->transaction_active = true;
172 client->db_id = m->db_id;
173 DEBUG(DEBUG_DEBUG, (__location__ " client id[0x%08x] started to"
174 " commit transaction on db id[0x%08x]\n",
175 client->client_id, client->db_id));
177 case CTDB_CONTROL_TRANS2_COMMIT_RETRY:
178 /* already updated from the first commit */
179 if (client->db_id != m->db_id) {
180 DEBUG(DEBUG_ERR,(__location__ " ERROR: trans2_commit "
181 "retry: client-db_id[0x%08x] != "
182 "db_id[0x%08x] (client_id[0x%08x])\n",
184 m->db_id, client->client_id));
187 DEBUG(DEBUG_DEBUG, (__location__ " client id[0x%08x] started "
188 "transaction commit retry on "
190 client->client_id, client->db_id));
194 if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
195 DEBUG(DEBUG_INFO,("rejecting ctdb_control_trans2_commit when recovery active\n"));
199 state = talloc_zero(ctdb, struct ctdb_persistent_state);
200 CTDB_NO_MEMORY(ctdb, state);
205 for (i=0;i<ctdb->vnn_map->size;i++) {
206 struct ctdb_node *node = ctdb->nodes[ctdb->vnn_map->map[i]];
209 /* only send to active nodes */
210 if (node->flags & NODE_FLAGS_INACTIVE) {
214 /* don't send to ourselves */
215 if (node->pnn == ctdb->pnn) {
219 ret = ctdb_daemon_send_control(ctdb, node->pnn, 0, CTDB_CONTROL_UPDATE_RECORD,
220 c->client_id, 0, recdata,
221 ctdb_persistent_callback, state);
223 DEBUG(DEBUG_ERR,("Unable to send CTDB_CONTROL_UPDATE_RECORD to pnn %u\n", node->pnn));
228 state->num_pending++;
232 if (state->num_pending == 0) {
237 /* we need to wait for the replies */
240 /* need to keep the control structure around */
241 talloc_steal(state, c);
243 /* but we won't wait forever */
244 event_add_timed(ctdb->ev, state,
245 timeval_current_ofs(ctdb->tunable.control_timeout, 0),
246 ctdb_persistent_store_timeout, state);
253 * Store a set of persistent records.
254 * This is used to roll out a transaction to all nodes.
256 int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb,
257 struct ctdb_req_control *c,
258 TDB_DATA recdata, bool *async_reply)
260 struct ctdb_client *client;
261 struct ctdb_persistent_state *state;
263 struct ctdb_marshall_buffer *m = (struct ctdb_marshall_buffer *)recdata.dptr;
264 struct ctdb_db_context *ctdb_db;
266 if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
267 DEBUG(DEBUG_INFO,("rejecting ctdb_control_trans3_commit when recovery active\n"));
271 ctdb_db = find_ctdb_db(ctdb, m->db_id);
272 if (ctdb_db == NULL) {
273 DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans3_commit: "
274 "Unknown database db_id[0x%08x]\n", m->db_id));
278 client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
279 if (client == NULL) {
280 DEBUG(DEBUG_ERR,(__location__ " can not match persistent_store "
281 "to a client. Returning error\n"));
285 state = talloc_zero(ctdb, struct ctdb_persistent_state);
286 CTDB_NO_MEMORY(ctdb, state);
291 for (i = 0; i < ctdb->vnn_map->size; i++) {
292 struct ctdb_node *node = ctdb->nodes[ctdb->vnn_map->map[i]];
295 /* only send to active nodes */
296 if (node->flags & NODE_FLAGS_INACTIVE) {
300 ret = ctdb_daemon_send_control(ctdb, node->pnn, 0,
301 CTDB_CONTROL_UPDATE_RECORD,
302 c->client_id, 0, recdata,
303 ctdb_persistent_callback,
306 DEBUG(DEBUG_ERR,("Unable to send "
307 "CTDB_CONTROL_UPDATE_RECORD "
308 "to pnn %u\n", node->pnn));
313 state->num_pending++;
317 if (state->num_pending == 0) {
322 /* we need to wait for the replies */
325 /* need to keep the control structure around */
326 talloc_steal(state, c);
328 /* but we won't wait forever */
329 event_add_timed(ctdb->ev, state,
330 timeval_current_ofs(ctdb->tunable.control_timeout, 0),
331 ctdb_persistent_store_timeout, state);
337 struct ctdb_persistent_write_state {
338 struct ctdb_db_context *ctdb_db;
339 struct ctdb_marshall_buffer *m;
340 struct ctdb_req_control *c;
345 called from a child process to write the data
347 static int ctdb_persistent_store(struct ctdb_persistent_write_state *state)
350 struct ctdb_rec_data *rec = NULL;
351 struct ctdb_marshall_buffer *m = state->m;
353 ret = tdb_transaction_start(state->ctdb_db->ltdb->tdb);
355 DEBUG(DEBUG_ERR,("Failed to start transaction for db_id 0x%08x in ctdb_persistent_store\n",
356 state->ctdb_db->db_id));
360 for (i=0;i<m->count;i++) {
361 struct ctdb_ltdb_header oldheader;
362 struct ctdb_ltdb_header header;
363 TDB_DATA key, data, olddata;
364 TALLOC_CTX *tmp_ctx = talloc_new(state);
366 rec = ctdb_marshall_loop_next(m, rec, NULL, &header, &key, &data);
369 DEBUG(DEBUG_ERR,("Failed to get next record %d for db_id 0x%08x in ctdb_persistent_store\n",
370 i, state->ctdb_db->db_id));
371 talloc_free(tmp_ctx);
375 /* fetch the old header and ensure the rsn is less than the new rsn */
376 ret = ctdb_ltdb_fetch(state->ctdb_db, key, &oldheader, tmp_ctx, &olddata);
378 DEBUG(DEBUG_ERR,("Failed to fetch old record for db_id 0x%08x in ctdb_persistent_store\n",
379 state->ctdb_db->db_id));
380 talloc_free(tmp_ctx);
384 if (oldheader.rsn >= header.rsn &&
385 (olddata.dsize != data.dsize ||
386 memcmp(olddata.dptr, data.dptr, data.dsize) != 0)) {
387 DEBUG(DEBUG_CRIT,("existing header for db_id 0x%08x has larger RSN %llu than new RSN %llu in ctdb_persistent_store\n",
388 state->ctdb_db->db_id,
389 (unsigned long long)oldheader.rsn, (unsigned long long)header.rsn));
390 talloc_free(tmp_ctx);
394 talloc_free(tmp_ctx);
396 ret = ctdb_ltdb_store(state->ctdb_db, key, &header, data);
398 DEBUG(DEBUG_CRIT,("Failed to store record for db_id 0x%08x in ctdb_persistent_store\n",
399 state->ctdb_db->db_id));
404 ret = tdb_transaction_commit(state->ctdb_db->ltdb->tdb);
406 DEBUG(DEBUG_ERR,("Failed to commit transaction for db_id 0x%08x in ctdb_persistent_store\n",
407 state->ctdb_db->db_id));
414 tdb_transaction_cancel(state->ctdb_db->ltdb->tdb);
420 called when we the child has completed the persistent write
423 static void ctdb_persistent_write_callback(int status, void *private_data)
425 struct ctdb_persistent_write_state *state = talloc_get_type(private_data,
426 struct ctdb_persistent_write_state);
429 ctdb_request_control_reply(state->ctdb_db->ctdb, state->c, NULL, status, NULL);
435 called if our lockwait child times out
437 static void ctdb_persistent_lock_timeout(struct event_context *ev, struct timed_event *te,
438 struct timeval t, void *private_data)
440 struct ctdb_persistent_write_state *state = talloc_get_type(private_data,
441 struct ctdb_persistent_write_state);
442 ctdb_request_control_reply(state->ctdb_db->ctdb, state->c, NULL, -1, "timeout in ctdb_persistent_lock");
446 struct childwrite_handle {
447 struct ctdb_context *ctdb;
448 struct ctdb_db_context *ctdb_db;
449 struct fd_event *fde;
453 void (*callback)(int, void *);
454 struct timeval start_time;
457 static int childwrite_destructor(struct childwrite_handle *h)
459 h->ctdb->statistics.pending_childwrite_calls--;
460 kill(h->child, SIGKILL);
464 /* called when the child process has finished writing the record to the
467 static void childwrite_handler(struct event_context *ev, struct fd_event *fde,
468 uint16_t flags, void *private_data)
470 struct childwrite_handle *h = talloc_get_type(private_data,
471 struct childwrite_handle);
472 void *p = h->private_data;
473 void (*callback)(int, void *) = h->callback;
474 pid_t child = h->child;
475 TALLOC_CTX *tmp_ctx = talloc_new(ev);
479 ctdb_latency(h->ctdb_db, "persistent", &h->ctdb->statistics.max_childwrite_latency, h->start_time);
480 h->ctdb->statistics.pending_childwrite_calls--;
482 /* the handle needs to go away when the context is gone - when
483 the handle goes away this implicitly closes the pipe, which
485 talloc_steal(tmp_ctx, h);
487 talloc_set_destructor(h, NULL);
489 ret = read(h->fd[0], &c, 1);
491 DEBUG(DEBUG_ERR, (__location__ " Read returned %d. Childwrite failed\n", ret));
497 kill(child, SIGKILL);
498 talloc_free(tmp_ctx);
501 /* this creates a child process which will take out a tdb transaction
502 and write the record to the database.
504 struct childwrite_handle *ctdb_childwrite(struct ctdb_db_context *ctdb_db,
505 void (*callback)(int, void *private_data),
506 struct ctdb_persistent_write_state *state)
508 struct childwrite_handle *result;
510 pid_t parent = getpid();
512 ctdb_db->ctdb->statistics.childwrite_calls++;
513 ctdb_db->ctdb->statistics.pending_childwrite_calls++;
515 if (!(result = talloc_zero(state, struct childwrite_handle))) {
516 ctdb_db->ctdb->statistics.pending_childwrite_calls--;
520 ret = pipe(result->fd);
524 ctdb_db->ctdb->statistics.pending_childwrite_calls--;
528 result->child = fork();
530 if (result->child == (pid_t)-1) {
531 close(result->fd[0]);
532 close(result->fd[1]);
534 ctdb_db->ctdb->statistics.pending_childwrite_calls--;
538 result->callback = callback;
539 result->private_data = state;
540 result->ctdb = ctdb_db->ctdb;
541 result->ctdb_db = ctdb_db;
543 if (result->child == 0) {
546 close(result->fd[0]);
547 ret = ctdb_persistent_store(state);
549 DEBUG(DEBUG_ERR, (__location__ " Failed to write persistent data\n"));
553 write(result->fd[1], &c, 1);
555 /* make sure we die when our parent dies */
556 while (kill(parent, 0) == 0 || errno != ESRCH) {
562 close(result->fd[1]);
563 set_close_on_exec(result->fd[0]);
565 talloc_set_destructor(result, childwrite_destructor);
567 DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d for ctdb_childwrite\n", result->fd[0]));
569 result->fde = event_add_fd(ctdb_db->ctdb->ev, result, result->fd[0],
570 EVENT_FD_READ|EVENT_FD_AUTOCLOSE, childwrite_handler,
572 if (result->fde == NULL) {
574 ctdb_db->ctdb->statistics.pending_childwrite_calls--;
578 result->start_time = timeval_current();
584 update a record on this node if the new record has a higher rsn than the
587 int32_t ctdb_control_update_record(struct ctdb_context *ctdb,
588 struct ctdb_req_control *c, TDB_DATA recdata,
591 struct ctdb_db_context *ctdb_db;
592 struct ctdb_persistent_write_state *state;
593 struct childwrite_handle *handle;
594 struct ctdb_marshall_buffer *m = (struct ctdb_marshall_buffer *)recdata.dptr;
596 if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
597 DEBUG(DEBUG_INFO,("rejecting ctdb_control_update_record when recovery active\n"));
601 ctdb_db = find_ctdb_db(ctdb, m->db_id);
602 if (ctdb_db == NULL) {
603 DEBUG(DEBUG_ERR,("Unknown database 0x%08x in ctdb_control_update_record\n", m->db_id));
607 if (ctdb_db->unhealthy_reason) {
608 DEBUG(DEBUG_ERR,("db(%s) unhealty in ctdb_control_update_record: %s\n",
609 ctdb_db->db_name, ctdb_db->unhealthy_reason));
613 state = talloc(ctdb, struct ctdb_persistent_write_state);
614 CTDB_NO_MEMORY(ctdb, state);
616 state->ctdb_db = ctdb_db;
620 /* create a child process to take out a transaction and
623 handle = ctdb_childwrite(ctdb_db, ctdb_persistent_write_callback, state);
624 if (handle == NULL) {
625 DEBUG(DEBUG_ERR,("Failed to setup childwrite handler in ctdb_control_update_record\n"));
630 /* we need to wait for the replies */
633 /* need to keep the control structure around */
634 talloc_steal(state, c);
636 /* but we won't wait forever */
637 event_add_timed(ctdb->ev, state, timeval_current_ofs(ctdb->tunable.control_timeout, 0),
638 ctdb_persistent_lock_timeout, state);
645 called when a client has finished a local commit in a transaction to
646 a persistent database
648 int32_t ctdb_control_trans2_finished(struct ctdb_context *ctdb,
649 struct ctdb_req_control *c)
651 struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
652 struct ctdb_db_context *ctdb_db;
654 ctdb_db = find_ctdb_db(ctdb, client->db_id);
655 if (ctdb_db == NULL) {
656 DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans2_finish "
657 "Unknown database 0x%08x\n", client->db_id));
660 if (!ctdb_db->transaction_active) {
661 DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans2_finish: "
662 "Database 0x%08x has no transaction commit "
663 "started\n", client->db_id));
667 ctdb_db->transaction_active = false;
670 if (client->num_persistent_updates == 0) {
671 DEBUG(DEBUG_ERR, (__location__ " ERROR: num_persistent_updates == 0\n"));
672 DEBUG(DEBUG_ERR,(__location__ " Forcing recovery\n"));
673 client->ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
676 client->num_persistent_updates--;
678 DEBUG(DEBUG_DEBUG, (__location__ " client id[0x%08x] finished "
679 "transaction commit db_id[0x%08x]\n",
680 client->client_id, ctdb_db->db_id));
686 called when a client gets an error committing its database
687 during a transaction commit
689 int32_t ctdb_control_trans2_error(struct ctdb_context *ctdb,
690 struct ctdb_req_control *c)
692 struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
693 struct ctdb_db_context *ctdb_db;
695 ctdb_db = find_ctdb_db(ctdb, client->db_id);
696 if (ctdb_db == NULL) {
697 DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans2_error: "
698 "Unknown database 0x%08x\n", client->db_id));
701 if (!ctdb_db->transaction_active) {
702 DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans2_error: "
703 "Database 0x%08x has no transaction commit "
704 "started\n", client->db_id));
708 ctdb_db->transaction_active = false;
711 if (client->num_persistent_updates == 0) {
712 DEBUG(DEBUG_ERR, (__location__ " ERROR: num_persistent_updates == 0\n"));
714 client->num_persistent_updates--;
717 DEBUG(DEBUG_ERR,(__location__ " An error occurred during transaction on"
718 " db_id[0x%08x] - forcing recovery\n",
720 client->ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
726 * Tell whether a transaction is active on this node on the give DB.
728 int32_t ctdb_control_trans2_active(struct ctdb_context *ctdb,
729 struct ctdb_req_control *c,
732 struct ctdb_db_context *ctdb_db;
733 struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
735 ctdb_db = find_ctdb_db(ctdb, db_id);
737 DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", db_id));
741 if (client->db_id == db_id) {
745 if (ctdb_db->transaction_active) {
753 backwards compatibility:
755 start a persistent store operation. passing both the key, header and
756 data to the daemon. If the client disconnects before it has issued
757 a persistent_update call to the daemon we trigger a full recovery
758 to ensure the databases are brought back in sync.
759 for now we ignore the recdata that the client has passed to us.
761 int32_t ctdb_control_start_persistent_update(struct ctdb_context *ctdb,
762 struct ctdb_req_control *c,
765 struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
767 if (client == NULL) {
768 DEBUG(DEBUG_ERR,(__location__ " can not match start_persistent_update to a client. Returning error\n"));
772 client->num_persistent_updates++;
778 backwards compatibility:
780 called to tell ctdbd that it is no longer doing a persistent update
782 int32_t ctdb_control_cancel_persistent_update(struct ctdb_context *ctdb,
783 struct ctdb_req_control *c,
786 struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
788 if (client == NULL) {
789 DEBUG(DEBUG_ERR,(__location__ " can not match cancel_persistent_update to a client. Returning error\n"));
793 if (client->num_persistent_updates > 0) {
794 client->num_persistent_updates--;
802 backwards compatibility:
804 single record varient of ctdb_control_trans2_commit for older clients
806 int32_t ctdb_control_persistent_store(struct ctdb_context *ctdb,
807 struct ctdb_req_control *c,
808 TDB_DATA recdata, bool *async_reply)
810 struct ctdb_marshall_buffer *m;
811 struct ctdb_rec_data *rec = (struct ctdb_rec_data *)recdata.dptr;
814 if (recdata.dsize != offsetof(struct ctdb_rec_data, data) +
815 rec->keylen + rec->datalen) {
816 DEBUG(DEBUG_ERR, (__location__ " Bad data size in recdata\n"));
820 key.dptr = &rec->data[0];
821 key.dsize = rec->keylen;
822 data.dptr = &rec->data[rec->keylen];
823 data.dsize = rec->datalen;
825 m = ctdb_marshall_add(c, NULL, rec->reqid, rec->reqid, key, NULL, data);
826 CTDB_NO_MEMORY(ctdb, m);
828 return ctdb_control_trans2_commit(ctdb, c, ctdb_marshall_finish(m), async_reply);
831 static int32_t ctdb_get_db_seqnum(struct ctdb_context *ctdb,
836 struct ctdb_db_context *ctdb_db;
837 const char *keyname = CTDB_DB_SEQNUM_KEY;
840 TALLOC_CTX *mem_ctx = talloc_new(ctdb);
842 ctdb_db = find_ctdb_db(ctdb, db_id);
844 DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", db_id));
849 key.dptr = (uint8_t *)discard_const(keyname);
850 key.dsize = strlen(keyname) + 1;
852 ret = (int32_t)ctdb_ltdb_fetch(ctdb_db, key, NULL, mem_ctx, &data);
857 if (data.dsize != sizeof(uint64_t)) {
862 *seqnum = *(uint64_t *)data.dptr;
865 talloc_free(mem_ctx);
870 * Get the sequence number of a persistent database.
872 int32_t ctdb_control_get_db_seqnum(struct ctdb_context *ctdb,
880 db_id = *(uint32_t *)indata.dptr;
881 ret = ctdb_get_db_seqnum(ctdb, db_id, &seqnum);
886 outdata->dsize = sizeof(uint64_t);
887 outdata->dptr = (uint8_t *)talloc_zero(outdata, uint64_t);
888 if (outdata->dptr == NULL) {
893 *(outdata->dptr) = seqnum;