4 Copyright (C) Andrew Tridgell 2007
5 Copyright (C) Ronnie Sahlberg 2007
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library 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 GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "lib/tdb/include/tdb.h"
25 #include "lib/events/events.h"
26 #include "lib/util/dlinklist.h"
27 #include "system/network.h"
28 #include "system/filesys.h"
29 #include "../include/ctdb.h"
30 #include "../include/ctdb_private.h"
33 queue a packet for sending from client to daemon
35 static int ctdb_client_queue_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
37 return ctdb_queue_send(ctdb->daemon.queue, (uint8_t *)hdr, hdr->length);
42 handle a connect wait reply packet
44 static void ctdb_reply_connect_wait(struct ctdb_context *ctdb,
45 struct ctdb_req_header *hdr)
47 struct ctdb_reply_connect_wait *r = (struct ctdb_reply_connect_wait *)hdr;
49 ctdb->num_connected = r->num_connected;
53 state of a in-progress ctdb call in client
55 struct ctdb_client_call_state {
56 enum call_state state;
58 struct ctdb_db_context *ctdb_db;
59 struct ctdb_call call;
63 called when a CTDB_REPLY_CALL packet comes in in the client
65 This packet comes in response to a CTDB_REQ_CALL request packet. It
66 contains any reply data from the call
68 static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
70 struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr;
71 struct ctdb_client_call_state *state;
73 state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_call_state);
75 DEBUG(0,(__location__ " reqid %d not found\n", hdr->reqid));
79 if (hdr->reqid != state->reqid) {
80 /* we found a record but it was the wrong one */
81 DEBUG(0, ("Dropped orphaned reply with reqid:%d\n",hdr->reqid));
85 state->call.reply_data.dptr = c->data;
86 state->call.reply_data.dsize = c->datalen;
87 state->call.status = c->status;
89 talloc_steal(state, c);
91 state->state = CTDB_CALL_DONE;
94 static void ctdb_client_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
97 this is called in the client, when data comes in from the daemon
99 static void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args)
101 struct ctdb_context *ctdb = talloc_get_type(args, struct ctdb_context);
102 struct ctdb_req_header *hdr = (struct ctdb_req_header *)data;
105 /* place the packet as a child of a tmp_ctx. We then use
106 talloc_free() below to free it. If any of the calls want
107 to keep it, then they will steal it somewhere else, and the
108 talloc_free() will be a no-op */
109 tmp_ctx = talloc_new(ctdb);
110 talloc_steal(tmp_ctx, hdr);
113 DEBUG(2,("Daemon has exited - shutting down client\n"));
117 if (cnt < sizeof(*hdr)) {
118 DEBUG(0,("Bad packet length %d in client\n", cnt));
121 if (cnt != hdr->length) {
122 ctdb_set_error(ctdb, "Bad header length %d expected %d in client\n",
127 if (hdr->ctdb_magic != CTDB_MAGIC) {
128 ctdb_set_error(ctdb, "Non CTDB packet rejected in client\n");
132 if (hdr->ctdb_version != CTDB_VERSION) {
133 ctdb_set_error(ctdb, "Bad CTDB version 0x%x rejected in client\n", hdr->ctdb_version);
137 switch (hdr->operation) {
138 case CTDB_REPLY_CALL:
139 ctdb_client_reply_call(ctdb, hdr);
142 case CTDB_REQ_MESSAGE:
143 ctdb_request_message(ctdb, hdr);
146 case CTDB_REPLY_CONNECT_WAIT:
147 ctdb_reply_connect_wait(ctdb, hdr);
150 case CTDB_REPLY_CONTROL:
151 ctdb_client_reply_control(ctdb, hdr);
155 DEBUG(0,("bogus operation code:%d\n",hdr->operation));
159 talloc_free(tmp_ctx);
163 connect to a unix domain socket
165 int ctdb_socket_connect(struct ctdb_context *ctdb)
167 struct sockaddr_un addr;
169 memset(&addr, 0, sizeof(addr));
170 addr.sun_family = AF_UNIX;
171 strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path));
173 ctdb->daemon.sd = socket(AF_UNIX, SOCK_STREAM, 0);
174 if (ctdb->daemon.sd == -1) {
178 if (connect(ctdb->daemon.sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
179 close(ctdb->daemon.sd);
180 ctdb->daemon.sd = -1;
184 ctdb->daemon.queue = ctdb_queue_setup(ctdb, ctdb, ctdb->daemon.sd,
186 ctdb_client_read_cb, ctdb);
191 struct ctdb_record_handle {
192 struct ctdb_db_context *ctdb_db;
195 struct ctdb_ltdb_header header;
200 make a recv call to the local ctdb daemon - called from client context
202 This is called when the program wants to wait for a ctdb_call to complete and get the
203 results. This call will block unless the call has already completed.
205 int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call)
207 while (state->state < CTDB_CALL_DONE) {
208 event_loop_once(state->ctdb_db->ctdb->ev);
210 if (state->state != CTDB_CALL_DONE) {
211 DEBUG(0,(__location__ " ctdb_call_recv failed\n"));
216 if (state->call.reply_data.dsize) {
217 call->reply_data.dptr = talloc_memdup(state->ctdb_db,
218 state->call.reply_data.dptr,
219 state->call.reply_data.dsize);
220 call->reply_data.dsize = state->call.reply_data.dsize;
222 call->reply_data.dptr = NULL;
223 call->reply_data.dsize = 0;
225 call->status = state->call.status;
235 destroy a ctdb_call in client
237 static int ctdb_client_call_destructor(struct ctdb_client_call_state *state)
239 ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid);
244 construct an event driven local ctdb_call
246 this is used so that locally processed ctdb_call requests are processed
247 in an event driven manner
249 static struct ctdb_client_call_state *ctdb_client_call_local_send(struct ctdb_db_context *ctdb_db,
250 struct ctdb_call *call,
251 struct ctdb_ltdb_header *header,
254 struct ctdb_client_call_state *state;
255 struct ctdb_context *ctdb = ctdb_db->ctdb;
258 state = talloc_zero(ctdb_db, struct ctdb_client_call_state);
259 CTDB_NO_MEMORY_NULL(ctdb, state);
261 talloc_steal(state, data->dptr);
263 state->state = CTDB_CALL_DONE;
265 state->ctdb_db = ctdb_db;
267 ret = ctdb_call_local(ctdb_db, &state->call, header, data, ctdb->vnn);
268 talloc_steal(state, state->call.reply_data.dptr);
274 make a ctdb call to the local daemon - async send. Called from client context.
276 This constructs a ctdb_call request and queues it for processing.
277 This call never blocks.
279 struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db,
280 struct ctdb_call *call)
282 struct ctdb_client_call_state *state;
283 struct ctdb_context *ctdb = ctdb_db->ctdb;
284 struct ctdb_ltdb_header header;
288 struct ctdb_req_call *c;
290 /* if the domain socket is not yet open, open it */
291 if (ctdb->daemon.sd==-1) {
292 ctdb_socket_connect(ctdb);
295 ret = ctdb_ltdb_lock(ctdb_db, call->key);
297 DEBUG(0,(__location__ " Failed to get chainlock\n"));
301 ret = ctdb_ltdb_fetch(ctdb_db, call->key, &header, ctdb_db, &data);
303 ctdb_ltdb_unlock(ctdb_db, call->key);
304 DEBUG(0,(__location__ " Failed to fetch record\n"));
308 if (header.dmaster == ctdb->vnn && !(ctdb->flags & CTDB_FLAG_SELF_CONNECT)) {
309 state = ctdb_client_call_local_send(ctdb_db, call, &header, &data);
310 talloc_free(data.dptr);
311 ctdb_ltdb_unlock(ctdb_db, call->key);
315 ctdb_ltdb_unlock(ctdb_db, call->key);
316 talloc_free(data.dptr);
318 state = talloc_zero(ctdb_db, struct ctdb_client_call_state);
320 DEBUG(0, (__location__ " failed to allocate state\n"));
324 len = offsetof(struct ctdb_req_call, data) + call->key.dsize + call->call_data.dsize;
325 c = ctdbd_allocate_pkt(state, len);
327 DEBUG(0, (__location__ " failed to allocate packet\n"));
330 talloc_set_name_const(c, "ctdb client req_call packet");
331 memset(c, 0, offsetof(struct ctdb_req_call, data));
334 c->hdr.ctdb_magic = CTDB_MAGIC;
335 c->hdr.ctdb_version = CTDB_VERSION;
336 c->hdr.operation = CTDB_REQ_CALL;
337 /* this limits us to 16k outstanding messages - not unreasonable */
338 c->hdr.reqid = ctdb_reqid_new(ctdb, state);
339 c->flags = call->flags;
340 c->db_id = ctdb_db->db_id;
341 c->callid = call->call_id;
342 c->keylen = call->key.dsize;
343 c->calldatalen = call->call_data.dsize;
344 memcpy(&c->data[0], call->key.dptr, call->key.dsize);
345 memcpy(&c->data[call->key.dsize],
346 call->call_data.dptr, call->call_data.dsize);
348 state->call.call_data.dptr = &c->data[call->key.dsize];
349 state->call.key.dptr = &c->data[0];
351 state->state = CTDB_CALL_WAIT;
352 state->ctdb_db = ctdb_db;
353 state->reqid = c->hdr.reqid;
355 talloc_set_destructor(state, ctdb_client_call_destructor);
357 ctdb_client_queue_pkt(ctdb, &c->hdr);
364 full ctdb_call. Equivalent to a ctdb_call_send() followed by a ctdb_call_recv()
366 int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call)
368 struct ctdb_client_call_state *state;
370 state = ctdb_call_send(ctdb_db, call);
371 return ctdb_call_recv(state, call);
376 tell the daemon what messaging srvid we will use, and register the message
377 handler function in the client
379 int ctdb_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
380 ctdb_message_fn_t handler,
384 struct ctdb_req_register c;
387 /* if the domain socket is not yet open, open it */
388 if (ctdb->daemon.sd==-1) {
389 ctdb_socket_connect(ctdb);
394 c.hdr.length = sizeof(c);
395 c.hdr.ctdb_magic = CTDB_MAGIC;
396 c.hdr.ctdb_version = CTDB_VERSION;
397 c.hdr.operation = CTDB_REQ_REGISTER;
400 res = ctdb_client_queue_pkt(ctdb, &c.hdr);
405 /* also need to register the handler with our ctdb structure */
406 return ctdb_register_message_handler(ctdb, ctdb, srvid, handler, private_data);
411 send a message - from client context
413 int ctdb_send_message(struct ctdb_context *ctdb, uint32_t vnn,
414 uint64_t srvid, TDB_DATA data)
416 struct ctdb_req_message *r;
419 len = offsetof(struct ctdb_req_message, data) + data.dsize;
420 r = ctdbd_allocate_pkt(ctdb, len);
421 CTDB_NO_MEMORY(ctdb, r);
422 talloc_set_name_const(r, "req_message packet");
425 r->hdr.ctdb_magic = CTDB_MAGIC;
426 r->hdr.ctdb_version = CTDB_VERSION;
427 r->hdr.operation = CTDB_REQ_MESSAGE;
428 r->hdr.destnode = vnn;
429 r->hdr.srcnode = ctdb->vnn;
432 r->datalen = data.dsize;
433 memcpy(&r->data[0], data.dptr, data.dsize);
435 res = ctdb_client_queue_pkt(ctdb, &r->hdr);
445 wait for all nodes to be connected - from client
447 void ctdb_connect_wait(struct ctdb_context *ctdb)
449 struct ctdb_req_connect_wait r;
454 r.hdr.length = sizeof(r);
455 r.hdr.ctdb_magic = CTDB_MAGIC;
456 r.hdr.ctdb_version = CTDB_VERSION;
457 r.hdr.operation = CTDB_REQ_CONNECT_WAIT;
459 DEBUG(3,("ctdb_connect_wait: sending to ctdbd\n"));
461 /* if the domain socket is not yet open, open it */
462 if (ctdb->daemon.sd==-1) {
463 ctdb_socket_connect(ctdb);
466 res = ctdb_queue_send(ctdb->daemon.queue, (uint8_t *)&r.hdr, r.hdr.length);
468 DEBUG(0,(__location__ " Failed to queue a connect wait request\n"));
472 DEBUG(3,("ctdb_connect_wait: waiting\n"));
474 /* now we can go into the normal wait routine, as the reply packet
475 will update the ctdb->num_connected variable */
476 ctdb_daemon_connect_wait(ctdb);
478 /* get other config variables */
479 ctdb_get_config(ctdb);
483 cancel a ctdb_fetch_lock operation, releasing the lock
485 static int fetch_lock_destructor(struct ctdb_record_handle *h)
487 ctdb_ltdb_unlock(h->ctdb_db, h->key);
492 force the migration of a record to this node
494 static int ctdb_client_force_migration(struct ctdb_db_context *ctdb_db, TDB_DATA key)
496 struct ctdb_call call;
498 call.call_id = CTDB_NULL_FUNC;
500 call.flags = CTDB_IMMEDIATE_MIGRATION;
501 return ctdb_call(ctdb_db, &call);
505 get a lock on a record, and return the records data. Blocks until it gets the lock
507 struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx,
508 TDB_DATA key, TDB_DATA *data)
511 struct ctdb_record_handle *h;
514 procedure is as follows:
516 1) get the chain lock.
517 2) check if we are dmaster
518 3) if we are the dmaster then return handle
519 4) if not dmaster then ask ctdb daemon to make us dmaster, and wait for
521 5) when we get the reply, goto (1)
524 h = talloc_zero(mem_ctx, struct ctdb_record_handle);
529 h->ctdb_db = ctdb_db;
531 h->key.dptr = talloc_memdup(h, key.dptr, key.dsize);
532 if (h->key.dptr == NULL) {
538 DEBUG(3,("ctdb_fetch_lock: key=%*.*s\n", key.dsize, key.dsize,
539 (const char *)key.dptr));
542 /* step 1 - get the chain lock */
543 ret = ctdb_ltdb_lock(ctdb_db, key);
545 DEBUG(0, (__location__ " failed to lock ltdb record\n"));
550 DEBUG(4,("ctdb_fetch_lock: got chain lock\n"));
552 talloc_set_destructor(h, fetch_lock_destructor);
554 ret = ctdb_ltdb_fetch(ctdb_db, key, &h->header, h, data);
556 ctdb_ltdb_unlock(ctdb_db, key);
561 /* when torturing, ensure we test the remote path */
562 if ((ctdb_db->ctdb->flags & CTDB_FLAG_TORTURE) &&
564 h->header.dmaster = (uint32_t)-1;
568 DEBUG(4,("ctdb_fetch_lock: done local fetch\n"));
570 if (h->header.dmaster != ctdb_db->ctdb->vnn) {
571 ctdb_ltdb_unlock(ctdb_db, key);
572 ret = ctdb_client_force_migration(ctdb_db, key);
574 DEBUG(4,("ctdb_fetch_lock: force_migration failed\n"));
581 DEBUG(4,("ctdb_fetch_lock: we are dmaster - done\n"));
586 store some data to the record that was locked with ctdb_fetch_lock()
588 int ctdb_record_store(struct ctdb_record_handle *h, TDB_DATA data)
590 return ctdb_ltdb_store(h->ctdb_db, h->key, &h->header, data);
594 wait until we're the only node left.
595 this function never returns
597 void ctdb_shutdown(struct ctdb_context *ctdb)
599 struct ctdb_req_shutdown r;
602 /* if the domain socket is not yet open, open it */
603 if (ctdb->daemon.sd==-1) {
604 ctdb_socket_connect(ctdb);
607 len = sizeof(struct ctdb_req_shutdown);
610 r.hdr.ctdb_magic = CTDB_MAGIC;
611 r.hdr.ctdb_version = CTDB_VERSION;
612 r.hdr.operation = CTDB_REQ_SHUTDOWN;
615 ctdb_client_queue_pkt(ctdb, &(r.hdr));
617 /* this event loop will terminate once we receive the reply */
619 event_loop_once(ctdb->ev);
624 struct ctdb_client_control_state {
628 enum call_state state;
632 called when a CTDB_REPLY_CONTROL packet comes in in the client
634 This packet comes in response to a CTDB_REQ_CONTROL request packet. It
635 contains any reply data from the control
637 static void ctdb_client_reply_control(struct ctdb_context *ctdb,
638 struct ctdb_req_header *hdr)
640 struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr;
641 struct ctdb_client_control_state *state;
643 state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_control_state);
645 DEBUG(0,(__location__ " reqid %d not found\n", hdr->reqid));
649 if (hdr->reqid != state->reqid) {
650 /* we found a record but it was the wrong one */
651 DEBUG(0, ("Dropped orphaned reply control with reqid:%d\n",hdr->reqid));
655 state->outdata.dptr = c->data;
656 state->outdata.dsize = c->datalen;
657 state->status = c->status;
659 talloc_steal(state, c);
661 state->state = CTDB_CALL_DONE;
666 send a ctdb control message
668 int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid,
669 uint32_t opcode, TDB_DATA data,
670 TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status)
672 struct ctdb_client_control_state *state;
673 struct ctdb_req_control *c;
677 /* if the domain socket is not yet open, open it */
678 if (ctdb->daemon.sd==-1) {
679 ctdb_socket_connect(ctdb);
682 state = talloc_zero(ctdb, struct ctdb_client_control_state);
683 CTDB_NO_MEMORY(ctdb, state);
685 state->reqid = ctdb_reqid_new(ctdb, state);
686 state->state = CTDB_CALL_WAIT;
688 len = offsetof(struct ctdb_req_control, data) + data.dsize;
689 c = ctdbd_allocate_pkt(state, len);
693 c->hdr.ctdb_magic = CTDB_MAGIC;
694 c->hdr.ctdb_version = CTDB_VERSION;
695 c->hdr.operation = CTDB_REQ_CONTROL;
696 c->hdr.reqid = state->reqid;
697 c->hdr.destnode = destnode;
698 c->hdr.srcnode = ctdb->vnn;
699 c->hdr.reqid = state->reqid;
702 c->datalen = data.dsize;
704 memcpy(&c->data[0], data.dptr, data.dsize);
707 ret = ctdb_client_queue_pkt(ctdb, &(c->hdr));
713 /* semi-async operation */
714 while (state->state == CTDB_CALL_WAIT) {
715 event_loop_once(ctdb->ev);
719 *outdata = state->outdata;
720 outdata->dptr = talloc_memdup(mem_ctx, outdata->dptr, outdata->dsize);
723 *status = state->status;
733 a process exists call. Returns 0 if process exists, -1 otherwise
735 int ctdb_process_exists(struct ctdb_context *ctdb, uint32_t destnode, pid_t pid)
741 data.dptr = (uint8_t*)&pid;
742 data.dsize = sizeof(pid);
744 ret = ctdb_control(ctdb, destnode, 0,
745 CTDB_CONTROL_PROCESS_EXISTS, data,
746 NULL, NULL, &status);
748 DEBUG(0,(__location__ " ctdb_control for process_exists failed\n"));
758 int ctdb_status(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_status *status)
765 ret = ctdb_control(ctdb, destnode, 0,
766 CTDB_CONTROL_STATUS, data,
768 if (ret != 0 || res != 0) {
769 DEBUG(0,(__location__ " ctdb_control for status failed\n"));
773 if (data.dsize != sizeof(struct ctdb_status)) {
774 DEBUG(0,(__location__ " Wrong status size %u - expected %u\n",
775 data.dsize, sizeof(struct ctdb_status)));
779 *status = *(struct ctdb_status *)data.dptr;
780 talloc_free(data.dptr);
786 get vnn map from a remote node
788 int ctdb_getvnnmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_vnn_map *vnnmap)
791 TDB_DATA data, outdata;
795 ret = ctdb_control(ctdb, destnode, 0,
796 CTDB_CONTROL_GETVNNMAP, data,
797 ctdb, &outdata, &res);
798 if (ret != 0 || res != 0) {
799 DEBUG(0,(__location__ " ctdb_control for getvnnmap failed\n"));
803 vnnmap->generation = ((uint32_t *)outdata.dptr)[0];
804 vnnmap->size = ((uint32_t *)outdata.dptr)[1];
806 talloc_free(vnnmap->map);
809 vnnmap->map = talloc_array(vnnmap, uint32_t, vnnmap->size);
810 for (i=0;i<vnnmap->size;i++) {
811 vnnmap->map[i] = ((uint32_t *)outdata.dptr)[i+2];
819 set vnn map on a node
821 int ctdb_setvnnmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_vnn_map *vnnmap)
824 TDB_DATA *data, outdata;
827 data = talloc_zero(ctdb, TDB_DATA);
828 data->dsize = (vnnmap->size+2)*sizeof(uint32_t);
829 data->dptr = (unsigned char *)talloc_array(data, uint32_t, vnnmap->size+2);
831 ((uint32_t *)&data->dptr[0])[0] = vnnmap->generation;
832 ((uint32_t *)&data->dptr[0])[1] = vnnmap->size;
833 for (i=0;i<vnnmap->size;i++) {
834 ((uint32_t *)&data->dptr[0])[i+2] = vnnmap->map[i];
837 ret = ctdb_control(ctdb, destnode, 0,
838 CTDB_CONTROL_SETVNNMAP, *data,
839 ctdb, &outdata, &res);
840 if (ret != 0 || res != 0) {
841 DEBUG(0,(__location__ " ctdb_control for setvnnmap failed\n"));
852 int ctdb_ping(struct ctdb_context *ctdb, uint32_t destnode)
859 ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_PING, data, NULL, NULL, &res);
860 if (ret != 0 || res != 0) {
869 int ctdb_get_config(struct ctdb_context *ctdb)
874 struct ctdb_context c;
877 ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_CONFIG, data,
879 if (ret != 0 || res != 0) {
882 if (data.dsize != sizeof(c)) {
883 DEBUG(0,("Bad config size %u - expected %u\n", data.dsize, sizeof(c)));
887 c = *(struct ctdb_context *)data.dptr;
888 talloc_free(data.dptr);
890 ctdb->num_nodes = c.num_nodes;
891 ctdb->num_connected = c.num_connected;
893 ctdb->max_lacount = c.max_lacount;
899 find the real path to a ltdb
901 int ctdb_getdbpath(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx,
908 data.dptr = (uint8_t *)&ctdb_db->db_id;
909 data.dsize = sizeof(ctdb_db->db_id);
911 ret = ctdb_control(ctdb_db->ctdb, CTDB_CURRENT_NODE, 0,
912 CTDB_CONTROL_GETDBPATH, data,
913 ctdb_db, &data, &res);
914 if (ret != 0 || res != 0) {
918 (*path) = talloc_strndup(mem_ctx, (const char *)data.dptr, data.dsize);
919 if ((*path) == NULL) {
923 talloc_free(data.dptr);
929 get debug level on a node
931 int ctdb_get_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, uint32_t *level)
938 ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DEBUG, data,
940 if (ret != 0 || res != 0) {
943 if (data.dsize != sizeof(uint32_t)) {
944 DEBUG(0,("Bad control reply size in ctdb_get_debuglevel (got %u)\n",
948 *level = *(uint32_t *)data.dptr;
949 talloc_free(data.dptr);
954 set debug level on a node
956 int ctdb_set_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, uint32_t level)
962 data.dptr = (uint8_t *)&level;
963 data.dsize = sizeof(level);
965 ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_DEBUG, data,
967 if (ret != 0 || res != 0) {