along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "includes.h"
-#include "db_wrap.h"
-#include "lib/tdb/include/tdb.h"
-#include "lib/util/dlinklist.h"
-#include "lib/tevent/tevent.h"
+#include "replace.h"
#include "system/network.h"
#include "system/filesys.h"
#include "system/locale.h"
-#include <stdlib.h>
-#include "../include/ctdb_private.h"
+
+#include <talloc.h>
+/* Allow use of deprecated function tevent_loop_allow_nesting() */
+#define TEVENT_DEPRECATED
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/tdb_wrap/tdb_wrap.h"
#include "lib/util/dlinklist.h"
+#include "lib/util/time.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+#include "ctdb_client.h"
-pid_t ctdbd_pid;
+#include "common/reqid.h"
+#include "common/system.h"
+#include "common/common.h"
+#include "common/logging.h"
/*
allocate a packet for use in client<->daemon communication
hdr->length = length;
hdr->operation = operation;
hdr->ctdb_magic = CTDB_MAGIC;
- hdr->ctdb_version = CTDB_VERSION;
+ hdr->ctdb_version = CTDB_PROTOCOL;
hdr->srcnode = ctdb->pnn;
if (ctdb->vnn_map) {
hdr->generation = ctdb->vnn_map->generation;
*/
int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call,
struct ctdb_ltdb_header *header, TALLOC_CTX *mem_ctx,
- TDB_DATA *data, bool updatetdb, uint32_t caller)
+ TDB_DATA *data, bool updatetdb)
{
struct ctdb_call_info *c;
struct ctdb_registered_call *fn;
}
/* we need to force the record to be written out if this was a remote access */
- if (header->laccessor != caller) {
- header->lacount = 0;
- }
- header->laccessor = caller;
- header->lacount++;
-
- /* we need to force the record to be written out if this was a remote access,
- so that the lacount is updated */
- if (c->new_data == NULL && header->laccessor != ctdb->pnn) {
+ if (c->new_data == NULL) {
c->new_data = &c->record_data;
}
*/
static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
{
- struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr;
+ struct ctdb_reply_call_old *c = (struct ctdb_reply_call_old *)hdr;
struct ctdb_client_call_state *state;
- state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_call_state);
+ state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_client_call_state);
if (state == NULL) {
DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid));
return;
}
}
+void ctdb_request_message(struct ctdb_context *ctdb,
+ struct ctdb_req_header *hdr)
+{
+ struct ctdb_req_message_old *c = (struct ctdb_req_message_old *)hdr;
+ TDB_DATA data;
+
+ data.dsize = c->datalen;
+ data.dptr = talloc_memdup(c, &c->data[0], c->datalen);
+ if (data.dptr == NULL) {
+ DEBUG(DEBUG_ERR, (__location__ " Memory allocation failure\n"));
+ return;
+ }
+
+ srvid_dispatch(ctdb->srv, c->srvid, CTDB_SRVID_ALL, data);
+}
+
static void ctdb_client_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
/*
talloc_steal(tmp_ctx, hdr);
if (cnt == 0) {
- DEBUG(DEBUG_INFO,("Daemon has exited - shutting down client\n"));
- exit(0);
+ DEBUG(DEBUG_CRIT,("Daemon has exited - shutting down client\n"));
+ exit(1);
}
if (cnt < sizeof(*hdr)) {
goto done;
}
- if (hdr->ctdb_version != CTDB_VERSION) {
+ if (hdr->ctdb_version != CTDB_PROTOCOL) {
ctdb_set_error(ctdb, "Bad CTDB version 0x%x rejected in client\n", hdr->ctdb_version);
goto done;
}
}
/*
- connect with exponential backoff, thanks Stevens
+ connect to a unix domain socket
*/
-#define CONNECT_MAXSLEEP 64
-static int ctdb_connect_retry(struct ctdb_context *ctdb)
+int ctdb_socket_connect(struct ctdb_context *ctdb)
{
struct sockaddr_un addr;
- int secs;
- int ret = 0;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path));
+ strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path)-1);
- for (secs = 1; secs <= CONNECT_MAXSLEEP; secs *= 2) {
- ret = connect(ctdb->daemon.sd, (struct sockaddr *)&addr,
- sizeof(addr));
- if ((ret == 0) || (errno != EAGAIN)) {
- break;
- }
-
- if (secs <= (CONNECT_MAXSLEEP / 2)) {
- DEBUG(DEBUG_ERR,("connect failed: %s, retry in %d second(s)\n",
- strerror(errno), secs));
- sleep(secs);
- }
- }
-
- return ret;
-}
-
-/*
- connect to a unix domain socket
-*/
-int ctdb_socket_connect(struct ctdb_context *ctdb)
-{
ctdb->daemon.sd = socket(AF_UNIX, SOCK_STREAM, 0);
if (ctdb->daemon.sd == -1) {
DEBUG(DEBUG_ERR,(__location__ " Failed to open client socket. Errno:%s(%d)\n", strerror(errno), errno));
return -1;
}
- set_nonblocking(ctdb->daemon.sd);
- set_close_on_exec(ctdb->daemon.sd);
-
- if (ctdb_connect_retry(ctdb) == -1) {
- DEBUG(DEBUG_ERR,(__location__ " Failed to connect client socket to daemon. Errno:%s(%d)\n", strerror(errno), errno));
+ if (connect(ctdb->daemon.sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
close(ctdb->daemon.sd);
ctdb->daemon.sd = -1;
+ DEBUG(DEBUG_ERR,(__location__ " Failed to connect client socket to daemon. Errno:%s(%d)\n", strerror(errno), errno));
return -1;
}
+ set_nonblocking(ctdb->daemon.sd);
+ set_close_on_exec(ctdb->daemon.sd);
+
ctdb->daemon.queue = ctdb_queue_setup(ctdb, ctdb, ctdb->daemon.sd,
CTDB_DS_ALIGNMENT,
ctdb_client_read_cb, ctdb, "to-ctdbd");
}
while (state->state < CTDB_CALL_DONE) {
- event_loop_once(state->ctdb_db->ctdb->ev);
+ tevent_loop_once(state->ctdb_db->ctdb->ev);
}
if (state->state != CTDB_CALL_DONE) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_call_recv failed\n"));
*/
static int ctdb_client_call_destructor(struct ctdb_client_call_state *state)
{
- ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid);
+ reqid_remove(state->ctdb_db->ctdb->idr, state->reqid);
return 0;
}
*(state->call) = *call;
state->ctdb_db = ctdb_db;
- ret = ctdb_call_local(ctdb_db, state->call, header, state, data, true, ctdb->pnn);
+ ret = ctdb_call_local(ctdb_db, state->call, header, state, data, true);
if (ret != 0) {
DEBUG(DEBUG_DEBUG,("ctdb_call_local() failed, ignoring return code %d\n", ret));
}
TDB_DATA data;
int ret;
size_t len;
- struct ctdb_req_call *c;
+ struct ctdb_req_call_old *c;
/* if the domain socket is not yet open, open it */
if (ctdb->daemon.sd==-1) {
return NULL;
}
- len = offsetof(struct ctdb_req_call, data) + call->key.dsize + call->call_data.dsize;
- c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CALL, len, struct ctdb_req_call);
+ len = offsetof(struct ctdb_req_call_old, data) + call->key.dsize + call->call_data.dsize;
+ c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CALL, len, struct ctdb_req_call_old);
if (c == NULL) {
DEBUG(DEBUG_ERR, (__location__ " failed to allocate packet\n"));
return NULL;
}
- state->reqid = ctdb_reqid_new(ctdb, state);
+ state->reqid = reqid_new(ctdb->idr, state);
state->ctdb_db = ctdb_db;
talloc_set_destructor(state, ctdb_client_call_destructor);
tell the daemon what messaging srvid we will use, and register the message
handler function in the client
*/
-int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
- ctdb_msg_fn_t handler,
- void *private_data)
-
+int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
+ srvid_handler_fn handler,
+ void *private_data)
{
int res;
int32_t status;
-
- res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_REGISTER_SRVID, 0,
+
+ res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid,
+ CTDB_CONTROL_REGISTER_SRVID, 0,
tdb_null, NULL, NULL, &status, NULL, NULL);
if (res != 0 || status != 0) {
- DEBUG(DEBUG_ERR,("Failed to register srvid %llu\n", (unsigned long long)srvid));
+ DEBUG(DEBUG_ERR,
+ ("Failed to register srvid %llu\n",
+ (unsigned long long)srvid));
return -1;
}
/* also need to register the handler with our own ctdb structure */
- return ctdb_register_message_handler(ctdb, ctdb, srvid, handler, private_data);
+ return srvid_register(ctdb->srv, ctdb, srvid, handler, private_data);
}
/*
tell the daemon we no longer want a srvid
*/
-int ctdb_client_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data)
+int ctdb_client_remove_message_handler(struct ctdb_context *ctdb,
+ uint64_t srvid, void *private_data)
{
int res;
int32_t status;
-
- res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_DEREGISTER_SRVID, 0,
+
+ res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid,
+ CTDB_CONTROL_DEREGISTER_SRVID, 0,
tdb_null, NULL, NULL, &status, NULL, NULL);
if (res != 0 || status != 0) {
- DEBUG(DEBUG_ERR,("Failed to deregister srvid %llu\n", (unsigned long long)srvid));
+ DEBUG(DEBUG_ERR,
+ ("Failed to deregister srvid %llu\n",
+ (unsigned long long)srvid));
return -1;
}
/* also need to register the handler with our own ctdb structure */
- ctdb_deregister_message_handler(ctdb, srvid, private_data);
+ srvid_deregister(ctdb->srv, srvid, private_data);
return 0;
}
+/*
+ * check server ids
+ */
+int ctdb_client_check_message_handlers(struct ctdb_context *ctdb, uint64_t *ids, uint32_t num,
+ uint8_t *result)
+{
+ TDB_DATA indata, outdata;
+ int res;
+ int32_t status;
+ int i;
+
+ indata.dptr = (uint8_t *)ids;
+ indata.dsize = num * sizeof(*ids);
+
+ res = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_CHECK_SRVIDS, 0,
+ indata, ctdb, &outdata, &status, NULL, NULL);
+ if (res != 0 || status != 0) {
+ DEBUG(DEBUG_ERR, (__location__ " failed to check srvids\n"));
+ return -1;
+ }
+
+ if (outdata.dsize != num*sizeof(uint8_t)) {
+ DEBUG(DEBUG_ERR, (__location__ " expected %lu bytes, received %zi bytes\n",
+ (long unsigned int)num*sizeof(uint8_t),
+ outdata.dsize));
+ talloc_free(outdata.dptr);
+ return -1;
+ }
+
+ for (i=0; i<num; i++) {
+ result[i] = outdata.dptr[i];
+ }
+
+ talloc_free(outdata.dptr);
+ return 0;
+}
/*
send a message - from client context
int ctdb_client_send_message(struct ctdb_context *ctdb, uint32_t pnn,
uint64_t srvid, TDB_DATA data)
{
- struct ctdb_req_message *r;
+ struct ctdb_req_message_old *r;
int len, res;
- len = offsetof(struct ctdb_req_message, data) + data.dsize;
+ len = offsetof(struct ctdb_req_message_old, data) + data.dsize;
r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_MESSAGE,
- len, struct ctdb_req_message);
+ len, struct ctdb_req_message_old);
CTDB_NO_MEMORY(ctdb, r);
r->hdr.destnode = pnn;
memcpy(&r->data[0], data.dptr, data.dsize);
res = ctdb_client_queue_pkt(ctdb, &r->hdr);
- if (res != 0) {
- return res;
- }
-
talloc_free(r);
- return 0;
+ return res;
}
goto again;
}
+ /* if this is a request for read/write and we have delegations
+ we have to revoke all delegations first
+ */
+ if ((h->header.dmaster == ctdb_db->ctdb->pnn) &&
+ (h->header.flags & CTDB_REC_RO_HAVE_DELEGATIONS)) {
+ ctdb_ltdb_unlock(ctdb_db, key);
+ ret = ctdb_client_force_migration(ctdb_db, key);
+ if (ret != 0) {
+ DEBUG(DEBUG_DEBUG,("ctdb_fetch_readonly_lock: force_migration failed\n"));
+ talloc_free(h);
+ return NULL;
+ }
+ goto again;
+ }
+
DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: we are dmaster - done\n"));
return h;
}
called when a control completes or timesout to invoke the callback
function the user provided
*/
-static void invoke_control_callback(struct event_context *ev, struct timed_event *te,
- struct timeval t, void *private_data)
+static void invoke_control_callback(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t, void *private_data)
{
struct ctdb_client_control_state *state;
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
static void ctdb_client_reply_control(struct ctdb_context *ctdb,
struct ctdb_req_header *hdr)
{
- struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr;
+ struct ctdb_reply_control_old *c = (struct ctdb_reply_control_old *)hdr;
struct ctdb_client_control_state *state;
- state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_control_state);
+ state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_client_control_state);
if (state == NULL) {
DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid));
return;
c->errorlen);
}
- /* state->outdata now uses resources from c so we dont want c
+ /* state->outdata now uses resources from c so we don't want c
to just dissappear from under us while state is still alive
*/
talloc_steal(state, c);
and call the callback.
*/
if (state->async.fn) {
- event_add_timed(ctdb->ev, state, timeval_zero(), invoke_control_callback, state);
+ tevent_add_timer(ctdb->ev, state, timeval_zero(),
+ invoke_control_callback, state);
}
}
*/
static int ctdb_client_control_destructor(struct ctdb_client_control_state *state)
{
- ctdb_reqid_remove(state->ctdb, state->reqid);
+ reqid_remove(state->ctdb->idr, state->reqid);
return 0;
}
/* time out handler for ctdb_control */
-static void control_timeout_func(struct event_context *ev, struct timed_event *te,
- struct timeval t, void *private_data)
+static void control_timeout_func(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t, void *private_data)
{
struct ctdb_client_control_state *state = talloc_get_type(private_data, struct ctdb_client_control_state);
and call the callback.
*/
if (state->async.fn) {
- event_add_timed(state->ctdb->ev, state, timeval_zero(), invoke_control_callback, state);
+ tevent_add_timer(state->ctdb->ev, state, timeval_zero(),
+ invoke_control_callback, state);
}
}
{
struct ctdb_client_control_state *state;
size_t len;
- struct ctdb_req_control *c;
+ struct ctdb_req_control_old *c;
int ret;
if (errormsg) {
CTDB_NO_MEMORY_NULL(ctdb, state);
state->ctdb = ctdb;
- state->reqid = ctdb_reqid_new(ctdb, state);
+ state->reqid = reqid_new(ctdb->idr, state);
state->state = CTDB_CONTROL_WAIT;
state->errormsg = NULL;
talloc_set_destructor(state, ctdb_client_control_destructor);
- len = offsetof(struct ctdb_req_control, data) + data.dsize;
+ len = offsetof(struct ctdb_req_control_old, data) + data.dsize;
c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CONTROL,
- len, struct ctdb_req_control);
+ len, struct ctdb_req_control_old);
state->c = c;
CTDB_NO_MEMORY_NULL(ctdb, c);
c->hdr.reqid = state->reqid;
/* timeout */
if (timeout && !timeval_is_zero(timeout)) {
- event_add_timed(ctdb->ev, state, *timeout, control_timeout_func, state);
+ tevent_add_timer(ctdb->ev, state, *timeout,
+ control_timeout_func, state);
}
ret = ctdb_client_queue_pkt(ctdb, &(c->hdr));
completes.
*/
while (state->state == CTDB_CONTROL_WAIT) {
- event_loop_once(ctdb->ev);
+ tevent_loop_once(ctdb->ev);
}
if (state->state != CTDB_CONTROL_DONE) {
state->async.fn(state);
}
talloc_free(tmp_ctx);
- return -1;
+ return (status == 0 ? -1 : state->status);
}
if (outdata) {
state = ctdb_control_send(ctdb, destnode, srvid, opcode,
flags, data, mem_ctx,
timeout, errormsg);
+
+ /* FIXME: Error conditions in ctdb_control_send return NULL without
+ * setting errormsg. So, there is no way to distinguish between sucess
+ * and failure when CTDB_CTRL_FLAG_NOREPLY is set */
+ if (flags & CTDB_CTRL_FLAG_NOREPLY) {
+ if (status != NULL) {
+ *status = 0;
+ }
+ return 0;
+ }
+
return ctdb_control_recv(ctdb, state, mem_ctx, outdata, status,
errormsg);
}
return 0;
}
+/*
+ * get db statistics
+ */
+int ctdb_ctrl_dbstatistics(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid,
+ TALLOC_CTX *mem_ctx, struct ctdb_db_statistics_old **dbstat)
+{
+ int ret;
+ TDB_DATA indata, outdata;
+ int32_t res;
+ struct ctdb_db_statistics_old *wire, *s;
+ char *ptr;
+ int i;
+
+ indata.dptr = (uint8_t *)&dbid;
+ indata.dsize = sizeof(dbid);
+
+ ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DB_STATISTICS,
+ 0, indata, ctdb, &outdata, &res, NULL, NULL);
+ if (ret != 0 || res != 0) {
+ DEBUG(DEBUG_ERR,(__location__ " ctdb_control for dbstatistics failed\n"));
+ return -1;
+ }
+
+ if (outdata.dsize < offsetof(struct ctdb_db_statistics_old, hot_keys_wire)) {
+ DEBUG(DEBUG_ERR,(__location__ " Wrong dbstatistics size %zi - expected >= %lu\n",
+ outdata.dsize,
+ (long unsigned int)sizeof(struct ctdb_statistics)));
+ return -1;
+ }
+
+ s = talloc_zero(mem_ctx, struct ctdb_db_statistics_old);
+ if (s == NULL) {
+ talloc_free(outdata.dptr);
+ CTDB_NO_MEMORY(ctdb, s);
+ }
+
+ wire = (struct ctdb_db_statistics_old *)outdata.dptr;
+ memcpy(s, wire, offsetof(struct ctdb_db_statistics_old, hot_keys_wire));
+ ptr = &wire->hot_keys_wire[0];
+ for (i=0; i<wire->num_hot_keys; i++) {
+ s->hot_keys[i].key.dptr = talloc_size(mem_ctx, s->hot_keys[i].key.dsize);
+ if (s->hot_keys[i].key.dptr == NULL) {
+ talloc_free(outdata.dptr);
+ CTDB_NO_MEMORY(ctdb, s->hot_keys[i].key.dptr);
+ }
+
+ memcpy(s->hot_keys[i].key.dptr, ptr, s->hot_keys[i].key.dsize);
+ ptr += wire->hot_keys[i].key.dsize;
+ }
+
+ talloc_free(outdata.dptr);
+ *dbstat = s;
+ return 0;
+}
+
/*
shutdown a remote ctdb node
*/
get a list of databases off a remote node
*/
int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode,
- TALLOC_CTX *mem_ctx, struct ctdb_dbid_map **dbmap)
+ TALLOC_CTX *mem_ctx, struct ctdb_dbid_map_old **dbmap)
{
int ret;
TDB_DATA outdata;
return -1;
}
- *dbmap = (struct ctdb_dbid_map *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+ *dbmap = (struct ctdb_dbid_map_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
talloc_free(outdata.dptr);
return 0;
*/
int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb,
struct timeval timeout, uint32_t destnode,
- TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap)
+ TALLOC_CTX *mem_ctx, struct ctdb_node_map_old **nodemap)
{
int ret;
TDB_DATA outdata;
int32_t res;
- ret = ctdb_control(ctdb, destnode, 0,
- CTDB_CONTROL_GET_NODEMAP, 0, tdb_null,
+ ret = ctdb_control(ctdb, destnode, 0,
+ CTDB_CONTROL_GET_NODEMAP, 0, tdb_null,
mem_ctx, &outdata, &res, &timeout, NULL);
- if (ret == 0 && res == -1 && outdata.dsize == 0) {
- DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getnodes failed, falling back to ipv4-only control\n"));
- return ctdb_ctrl_getnodemapv4(ctdb, timeout, destnode, mem_ctx, nodemap);
- }
if (ret != 0 || res != 0 || outdata.dsize == 0) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getnodes failed ret:%d res:%d\n", ret, res));
return -1;
}
- *nodemap = (struct ctdb_node_map *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+ *nodemap = (struct ctdb_node_map_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
talloc_free(outdata.dptr);
-
return 0;
}
/*
- old style ipv4-only get a list of nodes (vnn and flags ) from a remote node
+ load nodes file on a remote node and return as a node map
*/
-int ctdb_ctrl_getnodemapv4(struct ctdb_context *ctdb,
- struct timeval timeout, uint32_t destnode,
- TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap)
+int ctdb_ctrl_getnodesfile(struct ctdb_context *ctdb,
+ struct timeval timeout, uint32_t destnode,
+ TALLOC_CTX *mem_ctx, struct ctdb_node_map_old **nodemap)
{
- int ret, i, len;
+ int ret;
TDB_DATA outdata;
- struct ctdb_node_mapv4 *nodemapv4;
int32_t res;
- ret = ctdb_control(ctdb, destnode, 0,
- CTDB_CONTROL_GET_NODEMAPv4, 0, tdb_null,
+ ret = ctdb_control(ctdb, destnode, 0,
+ CTDB_CONTROL_GET_NODES_FILE, 0, tdb_null,
mem_ctx, &outdata, &res, &timeout, NULL);
if (ret != 0 || res != 0 || outdata.dsize == 0) {
- DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getnodesv4 failed ret:%d res:%d\n", ret, res));
+ DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getnodes failed ret:%d res:%d\n", ret, res));
return -1;
}
- nodemapv4 = (struct ctdb_node_mapv4 *)outdata.dptr;
-
- len = offsetof(struct ctdb_node_map, nodes) + nodemapv4->num*sizeof(struct ctdb_node_and_flags);
- (*nodemap) = talloc_zero_size(mem_ctx, len);
- CTDB_NO_MEMORY(ctdb, (*nodemap));
-
- (*nodemap)->num = nodemapv4->num;
- for (i=0; i<nodemapv4->num; i++) {
- (*nodemap)->nodes[i].pnn = nodemapv4->nodes[i].pnn;
- (*nodemap)->nodes[i].flags = nodemapv4->nodes[i].flags;
- (*nodemap)->nodes[i].addr.ip = nodemapv4->nodes[i].sin;
- (*nodemap)->nodes[i].addr.sa.sa_family = AF_INET;
- }
-
+ *nodemap = (struct ctdb_node_map_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
talloc_free(outdata.dptr);
-
+
return 0;
}
uint32_t lmaster, TALLOC_CTX *mem_ctx, struct timeval timeout)
{
TDB_DATA indata;
- struct ctdb_control_pulldb *pull;
+ struct ctdb_pulldb *pull;
struct ctdb_client_control_state *state;
- pull = talloc(mem_ctx, struct ctdb_control_pulldb);
+ pull = talloc(mem_ctx, struct ctdb_pulldb);
CTDB_NO_MEMORY_NULL(ctdb, pull);
pull->db_id = dbid;
pull->lmaster = lmaster;
- indata.dsize = sizeof(struct ctdb_control_pulldb);
+ indata.dsize = sizeof(struct ctdb_pulldb);
indata.dptr = (unsigned char *)pull;
state = ctdb_control_send(ctdb, destnode, 0,
return res;
}
+int ctdb_ctrl_get_runstate(struct ctdb_context *ctdb,
+ struct timeval timeout,
+ uint32_t destnode,
+ uint32_t *runstate)
+{
+ TDB_DATA outdata;
+ int32_t res;
+ int ret;
+
+ ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_RUNSTATE, 0,
+ tdb_null, ctdb, &outdata, &res, &timeout, NULL);
+ if (ret != 0 || res != 0) {
+ DEBUG(DEBUG_ERR,("ctdb_control for get_runstate failed\n"));
+ return ret != 0 ? ret : res;
+ }
+
+ if (outdata.dsize != sizeof(uint32_t)) {
+ DEBUG(DEBUG_ERR,("Invalid return data in get_runstate\n"));
+ talloc_free(outdata.dptr);
+ return -1;
+ }
+
+ if (runstate != NULL) {
+ *runstate = *(uint32_t *)outdata.dptr;
+ }
+ talloc_free(outdata.dptr);
+
+ return 0;
+}
+
/*
find the real path to a ltdb
*/
return 0;
}
+/*
+ * get db sequence number
+ */
+int ctdb_ctrl_getdbseqnum(struct ctdb_context *ctdb, struct timeval timeout,
+ uint32_t destnode, uint32_t dbid, uint64_t *seqnum)
+{
+ int ret;
+ int32_t res;
+ TDB_DATA data, outdata;
+
+ data.dptr = (uint8_t *)&dbid;
+ data.dsize = sizeof(uint64_t); /* This is just wrong */
+
+ ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DB_SEQNUM,
+ 0, data, ctdb, &outdata, &res, &timeout, NULL);
+ if (ret != 0 || res != 0) {
+ DEBUG(DEBUG_ERR,("ctdb_control for getdbesqnum failed\n"));
+ return -1;
+ }
+
+ if (outdata.dsize != sizeof(uint64_t)) {
+ DEBUG(DEBUG_ERR,("Invalid return data in get_dbseqnum\n"));
+ talloc_free(outdata.dptr);
+ return -1;
+ }
+
+ if (seqnum != NULL) {
+ *seqnum = *(uint64_t *)outdata.dptr;
+ }
+ talloc_free(outdata.dptr);
+
+ return 0;
+}
+
/*
create a database
*/
int ret;
int32_t res;
TDB_DATA data;
+ uint64_t tdb_flags = 0;
data.dptr = discard_const(name);
data.dsize = strlen(name)+1;
- ret = ctdb_control(ctdb, destnode, 0,
+ /* Make sure that volatile databases use jenkins hash */
+ if (!persistent) {
+ tdb_flags = TDB_INCOMPATIBLE_HASH;
+ }
+
+#ifdef TDB_MUTEX_LOCKING
+ if (!persistent && ctdb->tunable.mutex_enabled == 1) {
+ tdb_flags |= (TDB_MUTEX_LOCKING | TDB_CLEAR_IF_FIRST);
+ }
+#endif
+
+ ret = ctdb_control(ctdb, destnode, tdb_flags,
persistent?CTDB_CONTROL_DB_ATTACH_PERSISTENT:CTDB_CONTROL_DB_ATTACH,
0, data,
mem_ctx, &data, &res, &timeout, NULL);
TALLOC_CTX *mem_ctx,
uint32_t *num_nodes)
{
- struct ctdb_node_map *map=NULL;
+ struct ctdb_node_map_old *map=NULL;
int ret, i;
uint32_t *nodes;
TDB_DATA data;
int ret;
int32_t res;
+#ifdef TDB_MUTEX_LOCKING
+ uint32_t mutex_enabled = 0;
+#endif
ctdb_db = ctdb_db_handle(ctdb, name);
if (ctdb_db) {
data.dptr = discard_const(name);
data.dsize = strlen(name)+1;
+ /* CTDB has switched to using jenkins hash for volatile databases.
+ * Even if tdb_flags do not explicitly mention TDB_INCOMPATIBLE_HASH,
+ * always set it.
+ */
+ if (!persistent) {
+ tdb_flags |= TDB_INCOMPATIBLE_HASH;
+ }
+
+#ifdef TDB_MUTEX_LOCKING
+ if (!persistent) {
+ ret = ctdb_ctrl_get_tunable(ctdb, timeval_current_ofs(3,0),
+ CTDB_CURRENT_NODE,
+ "TDBMutexEnabled",
+ &mutex_enabled);
+ if (ret != 0) {
+ DEBUG(DEBUG_WARNING, ("Assuming no mutex support.\n"));
+ }
+
+ if (mutex_enabled == 1) {
+ tdb_flags |= (TDB_MUTEX_LOCKING | TDB_CLEAR_IF_FIRST);
+ }
+ }
+#endif
+
/* tell ctdb daemon to attach */
ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, tdb_flags,
persistent?CTDB_CONTROL_DB_ATTACH_PERSISTENT:CTDB_CONTROL_DB_ATTACH,
return NULL;
}
- tdb_flags = persistent?TDB_DEFAULT:TDB_NOSYNC;
+ if (persistent) {
+ tdb_flags = TDB_DEFAULT;
+ } else {
+ tdb_flags = TDB_NOSYNC;
+#ifdef TDB_MUTEX_LOCKING
+ if (mutex_enabled) {
+ tdb_flags |= (TDB_MUTEX_LOCKING | TDB_CLEAR_IF_FIRST);
+ }
+#endif
+ }
if (ctdb->valgrinding) {
tdb_flags |= TDB_NOMMAP;
}
tdb_flags |= TDB_DISALLOW_NESTING;
- ctdb_db->ltdb = tdb_wrap_open(ctdb, ctdb_db->db_path, 0, tdb_flags, O_RDWR, 0);
+ ctdb_db->ltdb = tdb_wrap_open(ctdb_db, ctdb_db->db_path, 0, tdb_flags,
+ O_RDWR, 0);
if (ctdb_db->ltdb == NULL) {
ctdb_set_error(ctdb, "Failed to open tdb '%s'\n", ctdb_db->db_path);
talloc_free(ctdb_db);
return ctdb_db;
}
-
/*
- setup a call for a database
+ * detach from a specific database - client call
*/
-int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id)
+int ctdb_detach(struct ctdb_context *ctdb, uint32_t db_id)
{
- struct ctdb_registered_call *call;
-
-#if 0
- TDB_DATA data;
- int32_t status;
- struct ctdb_control_set_call c;
int ret;
+ int32_t status;
+ TDB_DATA data;
- /* this is no longer valid with the separate daemon architecture */
- c.db_id = ctdb_db->db_id;
- c.fn = fn;
- c.id = id;
-
- data.dptr = (uint8_t *)&c;
- data.dsize = sizeof(c);
+ data.dsize = sizeof(db_id);
+ data.dptr = (uint8_t *)&db_id;
- ret = ctdb_control(ctdb_db->ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_SET_CALL, 0,
- data, NULL, NULL, &status, NULL, NULL);
+ ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_DB_DETACH,
+ 0, data, NULL, NULL, &status, NULL, NULL);
if (ret != 0 || status != 0) {
- DEBUG(DEBUG_ERR,("ctdb_set_call failed for call %u\n", id));
return -1;
}
-#endif
+ return 0;
+}
+
+/*
+ setup a call for a database
+ */
+int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id)
+{
+ struct ctdb_registered_call *call;
- /* also register locally */
+ /* register locally */
call = talloc(ctdb_db, struct ctdb_registered_call);
call->fn = fn;
call->id = id;
- DLIST_ADD(ctdb_db->calls, call);
+ DLIST_ADD(ctdb_db->calls, call);
return 0;
}
/*
called on each key during a ctdb_traverse
*/
-static void traverse_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data, void *p)
+static void traverse_handler(uint64_t srvid, TDB_DATA data, void *p)
{
struct traverse_state *state = (struct traverse_state *)p;
- struct ctdb_rec_data *d = (struct ctdb_rec_data *)data.dptr;
+ struct ctdb_rec_data_old *d = (struct ctdb_rec_data_old *)data.dptr;
TDB_DATA key;
- if (data.dsize < sizeof(uint32_t) ||
- d->length != data.dsize) {
- DEBUG(DEBUG_ERR,("Bad data size %u in traverse_handler\n", (unsigned)data.dsize));
- state->done = True;
+ if (data.dsize < sizeof(uint32_t) || d->length != data.dsize) {
+ DEBUG(DEBUG_ERR, ("Bad data size %u in traverse_handler\n",
+ (unsigned)data.dsize));
+ state->done = true;
return;
}
if (key.dsize == 0 && data.dsize == 0) {
/* end of traverse */
- state->done = True;
+ state->done = true;
return;
}
return;
}
- if (state->fn(ctdb, key, data, state->private_data) != 0) {
- state->done = True;
+ if (state->fn(key, data, state->private_data) != 0) {
+ state->done = true;
}
state->count++;
uint64_t srvid = (getpid() | 0xFLL<<60);
struct traverse_state state;
- state.done = False;
+ state.done = false;
state.count = 0;
state.private_data = private_data;
state.fn = fn;
}
while (!state.done) {
- event_loop_once(ctdb_db->ctdb->ev);
+ tevent_loop_once(ctdb_db->ctdb->ev);
}
ret = ctdb_client_remove_message_handler(ctdb_db->ctdb, srvid, &state);
/*
called on each key during a catdb
*/
-int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *p)
+int ctdb_dumpdb_record(TDB_DATA key, TDB_DATA data, void *p)
{
int i;
struct ctdb_dump_db_context *c = (struct ctdb_dump_db_context *)p;
fprintf(f, "dmaster: %u\n", h->dmaster);
fprintf(f, "rsn: %llu\n", (unsigned long long)h->rsn);
- if (c->printlmaster && ctdb->vnn_map != NULL) {
- fprintf(f, "lmaster: %u\n", ctdb_lmaster(ctdb, &key));
+ if (c->printlmaster && c->ctdb->vnn_map != NULL) {
+ fprintf(f, "lmaster: %u\n", ctdb_lmaster(c->ctdb, &key));
}
if (c->printhash) {
-/*
+/*
sent to a node to make it take over an ip address
*/
-int ctdb_ctrl_takeover_ip(struct ctdb_context *ctdb, struct timeval timeout,
+int ctdb_ctrl_takeover_ip(struct ctdb_context *ctdb, struct timeval timeout,
uint32_t destnode, struct ctdb_public_ip *ip)
{
TDB_DATA data;
- struct ctdb_public_ipv4 ipv4;
int ret;
int32_t res;
- if (ip->addr.sa.sa_family == AF_INET) {
- ipv4.pnn = ip->pnn;
- ipv4.sin = ip->addr.ip;
-
- data.dsize = sizeof(ipv4);
- data.dptr = (uint8_t *)&ipv4;
-
- ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_TAKEOVER_IPv4, 0, data, NULL,
- NULL, &res, &timeout, NULL);
- } else {
- data.dsize = sizeof(*ip);
- data.dptr = (uint8_t *)ip;
-
- ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_TAKEOVER_IP, 0, data, NULL,
- NULL, &res, &timeout, NULL);
- }
+ data.dsize = sizeof(*ip);
+ data.dptr = (uint8_t *)ip;
+ ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_TAKEOVER_IP, 0,
+ data, NULL, NULL, &res, &timeout, NULL);
if (ret != 0 || res != 0) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for takeover_ip failed\n"));
return -1;
}
- return 0;
+ return 0;
}
-/*
+/*
sent to a node to make it release an ip address
*/
-int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout,
+int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout,
uint32_t destnode, struct ctdb_public_ip *ip)
{
TDB_DATA data;
- struct ctdb_public_ipv4 ipv4;
int ret;
int32_t res;
- if (ip->addr.sa.sa_family == AF_INET) {
- ipv4.pnn = ip->pnn;
- ipv4.sin = ip->addr.ip;
-
- data.dsize = sizeof(ipv4);
- data.dptr = (uint8_t *)&ipv4;
-
- ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_RELEASE_IPv4, 0, data, NULL,
- NULL, &res, &timeout, NULL);
- } else {
- data.dsize = sizeof(*ip);
- data.dptr = (uint8_t *)ip;
-
- ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_RELEASE_IP, 0, data, NULL,
- NULL, &res, &timeout, NULL);
- }
+ data.dsize = sizeof(*ip);
+ data.dptr = (uint8_t *)ip;
+ ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_RELEASE_IP, 0,
+ data, NULL, NULL, &res, &timeout, NULL);
if (ret != 0 || res != 0) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for release_ip failed\n"));
return -1;
}
- return 0;
+ return 0;
}
talloc_free(data.dptr);
if (ret != 0 || res != 0) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get_tunable failed\n"));
- return -1;
+ return ret != 0 ? ret : res;
}
if (outdata.dsize != sizeof(uint32_t)) {
uint32_t destnode,
const char *name, uint32_t value)
{
- struct ctdb_control_set_tunable *t;
+ struct ctdb_tunable_old *t;
TDB_DATA data;
int32_t res;
int ret;
- data.dsize = offsetof(struct ctdb_control_set_tunable, name) + strlen(name) + 1;
+ data.dsize = offsetof(struct ctdb_tunable_old, name) + strlen(name) + 1;
data.dptr = talloc_size(ctdb, data.dsize);
CTDB_NO_MEMORY(ctdb, data.dptr);
- t = (struct ctdb_control_set_tunable *)data.dptr;
+ t = (struct ctdb_tunable_old *)data.dptr;
t->length = strlen(name)+1;
memcpy(t->name, name, t->length);
t->value = value;
ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_TUNABLE, 0, data, NULL,
NULL, &res, &timeout, NULL);
talloc_free(data.dptr);
- if (ret != 0 || res != 0) {
+ if ((ret != 0) || (res == -1)) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set_tunable failed\n"));
return -1;
}
- return 0;
+ return res;
}
/*
struct timeval timeout, uint32_t destnode,
TALLOC_CTX *mem_ctx,
uint32_t flags,
- struct ctdb_all_public_ips **ips)
+ struct ctdb_public_ip_list_old **ips)
{
int ret;
TDB_DATA outdata;
int32_t res;
- ret = ctdb_control(ctdb, destnode, 0,
+ ret = ctdb_control(ctdb, destnode, 0,
CTDB_CONTROL_GET_PUBLIC_IPS, flags, tdb_null,
mem_ctx, &outdata, &res, &timeout, NULL);
- if (ret == 0 && res == -1) {
- DEBUG(DEBUG_ERR,(__location__ " ctdb_control to get public ips failed, falling back to ipv4-only version\n"));
- return ctdb_ctrl_get_public_ipsv4(ctdb, timeout, destnode, mem_ctx, ips);
- }
if (ret != 0 || res != 0) {
- DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getpublicips failed ret:%d res:%d\n", ret, res));
+ DEBUG(DEBUG_ERR,(__location__
+ " ctdb_control for getpublicips failed ret:%d res:%d\n",
+ ret, res));
return -1;
}
- *ips = (struct ctdb_all_public_ips *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+ *ips = (struct ctdb_public_ip_list_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
talloc_free(outdata.dptr);
-
+
return 0;
}
int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
struct timeval timeout, uint32_t destnode,
TALLOC_CTX *mem_ctx,
- struct ctdb_all_public_ips **ips)
+ struct ctdb_public_ip_list_old **ips)
{
return ctdb_ctrl_get_public_ips_flags(ctdb, timeout,
destnode, mem_ctx,
0, ips);
}
-int ctdb_ctrl_get_public_ipsv4(struct ctdb_context *ctdb,
- struct timeval timeout, uint32_t destnode,
- TALLOC_CTX *mem_ctx, struct ctdb_all_public_ips **ips)
+int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
+ struct timeval timeout, uint32_t destnode,
+ TALLOC_CTX *mem_ctx,
+ const ctdb_sock_addr *addr,
+ struct ctdb_public_ip_info_old **_info)
{
- int ret, i, len;
+ int ret;
+ TDB_DATA indata;
TDB_DATA outdata;
int32_t res;
- struct ctdb_all_public_ipsv4 *ipsv4;
-
- ret = ctdb_control(ctdb, destnode, 0,
- CTDB_CONTROL_GET_PUBLIC_IPSv4, 0, tdb_null,
- mem_ctx, &outdata, &res, &timeout, NULL);
- if (ret != 0 || res != 0) {
- DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getpublicips failed\n"));
- return -1;
- }
-
- ipsv4 = (struct ctdb_all_public_ipsv4 *)outdata.dptr;
- len = offsetof(struct ctdb_all_public_ips, ips) +
- ipsv4->num*sizeof(struct ctdb_public_ip);
- *ips = talloc_zero_size(mem_ctx, len);
- CTDB_NO_MEMORY(ctdb, *ips);
- (*ips)->num = ipsv4->num;
- for (i=0; i<ipsv4->num; i++) {
- (*ips)->ips[i].pnn = ipsv4->ips[i].pnn;
- (*ips)->ips[i].addr.ip = ipsv4->ips[i].sin;
- }
-
- talloc_free(outdata.dptr);
-
- return 0;
-}
-
-int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
- struct timeval timeout, uint32_t destnode,
- TALLOC_CTX *mem_ctx,
- const ctdb_sock_addr *addr,
- struct ctdb_control_public_ip_info **_info)
-{
- int ret;
- TDB_DATA indata;
- TDB_DATA outdata;
- int32_t res;
- struct ctdb_control_public_ip_info *info;
- uint32_t len;
- uint32_t i;
+ struct ctdb_public_ip_info_old *info;
+ uint32_t len;
+ uint32_t i;
indata.dptr = discard_const_p(uint8_t, addr);
indata.dsize = sizeof(*addr);
return -1;
}
- len = offsetof(struct ctdb_control_public_ip_info, ifaces);
+ len = offsetof(struct ctdb_public_ip_info_old, ifaces);
if (len > outdata.dsize) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
"returned invalid data with size %u > %u\n",
return -1;
}
- info = (struct ctdb_control_public_ip_info *)outdata.dptr;
- len += info->num*sizeof(struct ctdb_control_iface_info);
+ info = (struct ctdb_public_ip_info_old *)outdata.dptr;
+ len += info->num*sizeof(struct ctdb_iface);
if (len > outdata.dsize) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
info->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
}
- *_info = (struct ctdb_control_public_ip_info *)talloc_memdup(mem_ctx,
+ *_info = (struct ctdb_public_ip_info_old *)talloc_memdup(mem_ctx,
outdata.dptr,
outdata.dsize);
talloc_free(outdata.dptr);
int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
struct timeval timeout, uint32_t destnode,
TALLOC_CTX *mem_ctx,
- struct ctdb_control_get_ifaces **_ifaces)
+ struct ctdb_iface_list_old **_ifaces)
{
int ret;
TDB_DATA outdata;
int32_t res;
- struct ctdb_control_get_ifaces *ifaces;
+ struct ctdb_iface_list_old *ifaces;
uint32_t len;
uint32_t i;
return -1;
}
- len = offsetof(struct ctdb_control_get_ifaces, ifaces);
+ len = offsetof(struct ctdb_iface_list_old, ifaces);
if (len > outdata.dsize) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
"returned invalid data with size %u > %u\n",
return -1;
}
- ifaces = (struct ctdb_control_get_ifaces *)outdata.dptr;
- len += ifaces->num*sizeof(struct ctdb_control_iface_info);
+ ifaces = (struct ctdb_iface_list_old *)outdata.dptr;
+ len += ifaces->num*sizeof(struct ctdb_iface);
if (len > outdata.dsize) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
ifaces->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
}
- *_ifaces = (struct ctdb_control_get_ifaces *)talloc_memdup(mem_ctx,
+ *_ifaces = (struct ctdb_iface_list_old *)talloc_memdup(mem_ctx,
outdata.dptr,
outdata.dsize);
talloc_free(outdata.dptr);
int ctdb_ctrl_set_iface_link(struct ctdb_context *ctdb,
struct timeval timeout, uint32_t destnode,
TALLOC_CTX *mem_ctx,
- const struct ctdb_control_iface_info *info)
+ const struct ctdb_iface *info)
{
int ret;
TDB_DATA indata;
{
int ret;
TDB_DATA data;
- struct ctdb_node_map *nodemap=NULL;
+ struct ctdb_node_map_old *nodemap=NULL;
struct ctdb_node_flag_change c;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
uint32_t recmaster;
/*
get all tunables
*/
-int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb,
- struct timeval timeout,
+int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb,
+ struct timeval timeout,
uint32_t destnode,
- struct ctdb_tunable *tunables)
+ struct ctdb_tunable_list *tunables)
{
TDB_DATA outdata;
int ret;
if (outdata.dsize != sizeof(*tunables)) {
DEBUG(DEBUG_ERR,(__location__ " bad data size %u in ctdb_ctrl_get_all_tunables should be %u\n",
(unsigned)outdata.dsize, (unsigned)sizeof(*tunables)));
- return -1;
+ return -1;
}
- *tunables = *(struct ctdb_tunable *)outdata.dptr;
+ *tunables = *(struct ctdb_tunable_list *)outdata.dptr;
talloc_free(outdata.dptr);
return 0;
}
/*
add a public address to a node
*/
-int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb,
- struct timeval timeout,
- uint32_t destnode,
- struct ctdb_control_ip_iface *pub)
+int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb,
+ struct timeval timeout, uint32_t destnode,
+ struct ctdb_addr_info_old *pub)
{
TDB_DATA data;
int32_t res;
int ret;
- data.dsize = offsetof(struct ctdb_control_ip_iface, iface) + pub->len;
+ data.dsize = offsetof(struct ctdb_addr_info_old, iface) + pub->len;
data.dptr = (unsigned char *)pub;
ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_ADD_PUBLIC_IP, 0, data, NULL,
/*
delete a public address from a node
*/
-int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb,
- struct timeval timeout,
- uint32_t destnode,
- struct ctdb_control_ip_iface *pub)
+int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb,
+ struct timeval timeout, uint32_t destnode,
+ struct ctdb_addr_info_old *pub)
{
TDB_DATA data;
int32_t res;
int ret;
- data.dsize = offsetof(struct ctdb_control_ip_iface, iface) + pub->len;
+ data.dsize = offsetof(struct ctdb_addr_info_old, iface) + pub->len;
data.dptr = (unsigned char *)pub;
ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_DEL_PUBLIC_IP, 0, data, NULL,
int ctdb_ctrl_killtcp(struct ctdb_context *ctdb,
struct timeval timeout,
uint32_t destnode,
- struct ctdb_control_killtcp *killtcp)
+ struct ctdb_connection *killtcp)
{
TDB_DATA data;
int32_t res;
int ret;
- data.dsize = sizeof(struct ctdb_control_killtcp);
+ data.dsize = sizeof(struct ctdb_connection);
data.dptr = (unsigned char *)killtcp;
ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_KILL_TCP, 0, data, NULL,
/*
send a gratious arp
*/
-int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb,
- struct timeval timeout,
- uint32_t destnode,
- ctdb_sock_addr *addr,
- const char *ifname)
+int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb,
+ struct timeval timeout, uint32_t destnode,
+ ctdb_sock_addr *addr, const char *ifname)
{
TDB_DATA data;
int32_t res;
int ret, len;
- struct ctdb_control_gratious_arp *gratious_arp;
+ struct ctdb_addr_info_old *gratious_arp;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
len = strlen(ifname)+1;
- gratious_arp = talloc_size(tmp_ctx,
- offsetof(struct ctdb_control_gratious_arp, iface) + len);
+ gratious_arp = talloc_size(tmp_ctx,
+ offsetof(struct ctdb_addr_info_old, iface) + len);
CTDB_NO_MEMORY(ctdb, gratious_arp);
gratious_arp->addr = *addr;
memcpy(&gratious_arp->iface[0], ifname, len);
- data.dsize = offsetof(struct ctdb_control_gratious_arp, iface) + len;
+ data.dsize = offsetof(struct ctdb_addr_info_old, iface) + len;
data.dptr = (unsigned char *)gratious_arp;
- ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SEND_GRATIOUS_ARP, 0, data, NULL,
+ ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SEND_GRATUITOUS_ARP, 0, data, NULL,
NULL, &res, &timeout, NULL);
if (ret != 0 || res != 0) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for gratious_arp failed\n"));
struct timeval timeout, uint32_t destnode,
TALLOC_CTX *mem_ctx,
ctdb_sock_addr *addr,
- struct ctdb_control_tcp_tickle_list **list)
+ struct ctdb_tickle_list_old **list)
{
int ret;
TDB_DATA data, outdata;
return -1;
}
- *list = (struct ctdb_control_tcp_tickle_list *)outdata.dptr;
+ *list = (struct ctdb_tickle_list_old *)outdata.dptr;
return status;
}
/*
register a server id
*/
-int ctdb_ctrl_register_server_id(struct ctdb_context *ctdb,
- struct timeval timeout,
- struct ctdb_server_id *id)
+int ctdb_ctrl_register_server_id(struct ctdb_context *ctdb,
+ struct timeval timeout,
+ struct ctdb_client_id *id)
{
TDB_DATA data;
int32_t res;
int ret;
- data.dsize = sizeof(struct ctdb_server_id);
+ data.dsize = sizeof(struct ctdb_client_id);
data.dptr = (unsigned char *)id;
ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0,
/*
unregister a server id
*/
-int ctdb_ctrl_unregister_server_id(struct ctdb_context *ctdb,
- struct timeval timeout,
- struct ctdb_server_id *id)
+int ctdb_ctrl_unregister_server_id(struct ctdb_context *ctdb,
+ struct timeval timeout,
+ struct ctdb_client_id *id)
{
TDB_DATA data;
int32_t res;
int ret;
- data.dsize = sizeof(struct ctdb_server_id);
+ data.dsize = sizeof(struct ctdb_client_id);
data.dptr = (unsigned char *)id;
ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0,
if a server id does exist, return *status == 1, otherwise *status == 0
*/
-int ctdb_ctrl_check_server_id(struct ctdb_context *ctdb,
- struct timeval timeout,
- uint32_t destnode,
- struct ctdb_server_id *id,
- uint32_t *status)
+int ctdb_ctrl_check_server_id(struct ctdb_context *ctdb,
+ struct timeval timeout, uint32_t destnode,
+ struct ctdb_client_id *id, uint32_t *status)
{
TDB_DATA data;
int32_t res;
int ret;
- data.dsize = sizeof(struct ctdb_server_id);
+ data.dsize = sizeof(struct ctdb_client_id);
data.dptr = (unsigned char *)id;
ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_CHECK_SERVER_ID,
get the list of server ids that are registered on a node
*/
int ctdb_ctrl_get_server_id_list(struct ctdb_context *ctdb,
- TALLOC_CTX *mem_ctx,
- struct timeval timeout, uint32_t destnode,
- struct ctdb_server_id_list **svid_list)
+ TALLOC_CTX *mem_ctx,
+ struct timeval timeout, uint32_t destnode,
+ struct ctdb_client_id_list_old **svid_list)
{
int ret;
TDB_DATA outdata;
return -1;
}
- *svid_list = (struct ctdb_server_id_list *)talloc_steal(mem_ctx, outdata.dptr);
-
+ *svid_list = (struct ctdb_client_id_list_old *)talloc_steal(mem_ctx, outdata.dptr);
+
return 0;
}
NOTE: In current code the daemon does not fork. This is for testing purposes only
and to simplify the code.
*/
-struct ctdb_context *ctdb_init(struct event_context *ev)
+struct ctdb_context *ctdb_init(struct tevent_context *ev)
{
int ret;
struct ctdb_context *ctdb;
return NULL;
}
ctdb->ev = ev;
- ctdb->idr = idr_init(ctdb);
/* Wrap early to exercise code. */
- ctdb->lastid = INT_MAX-200;
- CTDB_NO_MEMORY_NULL(ctdb, ctdb->idr);
+ ret = reqid_init(ctdb, INT_MAX-200, &ctdb->idr);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("reqid_init failed (%s)\n", strerror(ret)));
+ talloc_free(ctdb);
+ return NULL;
+ }
- ret = ctdb_set_socketname(ctdb, CTDB_PATH);
+ ret = srvid_init(ctdb, &ctdb->srv);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("srvid_init failed (%s)\n", strerror(ret)));
+ talloc_free(ctdb);
+ return NULL;
+ }
+
+ ret = ctdb_set_socketname(ctdb, CTDB_SOCKET);
if (ret != 0) {
DEBUG(DEBUG_ERR,(__location__ " ctdb_set_socketname failed.\n"));
talloc_free(ctdb);
struct ctdb_context *ctdb = talloc_get_type(state->ctdb, struct ctdb_context);
int ret;
TDB_DATA outdata;
- int32_t res;
+ int32_t res = -1;
uint32_t destnode = state->c->hdr.destnode;
+ outdata.dsize = 0;
+ outdata.dptr = NULL;
+
/* one more node has responded with recmode data */
data->count--;
DEBUG(DEBUG_ERR,("Async operation failed with state %d, opcode:%u\n", state->state, data->opcode));
}
data->fail_count++;
+ if (state->state == CTDB_CONTROL_TIMEOUT) {
+ res = -ETIME;
+ } else {
+ res = -1;
+ }
if (data->fail_callback) {
data->fail_callback(ctdb, destnode, res, outdata,
data->callback_data);
int ctdb_client_async_wait(struct ctdb_context *ctdb, struct client_async_data *data)
{
while (data->count > 0) {
- event_loop_once(ctdb->ev);
+ tevent_loop_once(ctdb->ev);
}
if (data->fail_count != 0) {
if (!data->dont_log_errors) {
return nodes;
}
-uint32_t *list_of_active_nodes(struct ctdb_context *ctdb,
- struct ctdb_node_map *node_map,
- TALLOC_CTX *mem_ctx,
- bool include_self)
+/* Get list of nodes not including those with flags specified by mask.
+ * If exclude_pnn is not -1 then exclude that pnn from the list.
+ */
+uint32_t *list_of_nodes(struct ctdb_context *ctdb,
+ struct ctdb_node_map_old *node_map,
+ TALLOC_CTX *mem_ctx,
+ uint32_t mask,
+ int exclude_pnn)
{
int i, j, num_nodes;
uint32_t *nodes;
for (i=num_nodes=0;i<node_map->num;i++) {
- if (node_map->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+ if (node_map->nodes[i].flags & mask) {
continue;
}
- if (node_map->nodes[i].pnn == ctdb->pnn && !include_self) {
+ if (node_map->nodes[i].pnn == exclude_pnn) {
continue;
}
num_nodes++;
CTDB_NO_MEMORY_FATAL(ctdb, nodes);
for (i=j=0;i<node_map->num;i++) {
- if (node_map->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+ if (node_map->nodes[i].flags & mask) {
continue;
}
- if (node_map->nodes[i].pnn == ctdb->pnn && !include_self) {
+ if (node_map->nodes[i].pnn == exclude_pnn) {
continue;
}
nodes[j++] = node_map->nodes[i].pnn;
return nodes;
}
-uint32_t *list_of_active_nodes_except_pnn(struct ctdb_context *ctdb,
- struct ctdb_node_map *node_map,
+uint32_t *list_of_active_nodes(struct ctdb_context *ctdb,
+ struct ctdb_node_map_old *node_map,
TALLOC_CTX *mem_ctx,
- uint32_t pnn)
+ bool include_self)
{
- int i, j, num_nodes;
- uint32_t *nodes;
-
- for (i=num_nodes=0;i<node_map->num;i++) {
- if (node_map->nodes[i].flags & NODE_FLAGS_INACTIVE) {
- continue;
- }
- if (node_map->nodes[i].pnn == pnn) {
- continue;
- }
- num_nodes++;
- }
-
- nodes = talloc_array(mem_ctx, uint32_t, num_nodes);
- CTDB_NO_MEMORY_FATAL(ctdb, nodes);
-
- for (i=j=0;i<node_map->num;i++) {
- if (node_map->nodes[i].flags & NODE_FLAGS_INACTIVE) {
- continue;
- }
- if (node_map->nodes[i].pnn == pnn) {
- continue;
- }
- nodes[j++] = node_map->nodes[i].pnn;
- }
-
- return nodes;
+ return list_of_nodes(ctdb, node_map, mem_ctx, NODE_FLAGS_INACTIVE,
+ include_self ? -1 : ctdb->pnn);
}
uint32_t *list_of_connected_nodes(struct ctdb_context *ctdb,
- struct ctdb_node_map *node_map,
+ struct ctdb_node_map_old *node_map,
TALLOC_CTX *mem_ctx,
bool include_self)
{
- int i, j, num_nodes;
- uint32_t *nodes;
-
- for (i=num_nodes=0;i<node_map->num;i++) {
- if (node_map->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
- continue;
- }
- if (node_map->nodes[i].pnn == ctdb->pnn && !include_self) {
- continue;
- }
- num_nodes++;
- }
-
- nodes = talloc_array(mem_ctx, uint32_t, num_nodes);
- CTDB_NO_MEMORY_FATAL(ctdb, nodes);
-
- for (i=j=0;i<node_map->num;i++) {
- if (node_map->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
- continue;
- }
- if (node_map->nodes[i].pnn == ctdb->pnn && !include_self) {
- continue;
- }
- nodes[j++] = node_map->nodes[i].pnn;
- }
-
- return nodes;
+ return list_of_nodes(ctdb, node_map, mem_ctx, NODE_FLAGS_DISCONNECTED,
+ include_self ? -1 : ctdb->pnn);
}
/*
return ret;
}
-/**
- * check whether a transaction is active on a given db on a given node
- */
-int32_t ctdb_ctrl_transaction_active(struct ctdb_context *ctdb,
- uint32_t destnode,
- uint32_t db_id)
+static void get_capabilities_callback(struct ctdb_context *ctdb,
+ uint32_t node_pnn, int32_t res,
+ TDB_DATA outdata, void *callback_data)
{
- int32_t status;
- int ret;
- TDB_DATA indata;
+ struct ctdb_node_capabilities *caps =
+ talloc_get_type(callback_data,
+ struct ctdb_node_capabilities);
- indata.dptr = (uint8_t *)&db_id;
- indata.dsize = sizeof(db_id);
+ if ( (outdata.dsize != sizeof(uint32_t)) || (outdata.dptr == NULL) ) {
+ DEBUG(DEBUG_ERR, (__location__ " Invalid length/pointer for getcap callback : %u %p\n", (unsigned)outdata.dsize, outdata.dptr));
+ return;
+ }
- ret = ctdb_control(ctdb, destnode, 0,
- CTDB_CONTROL_TRANS2_ACTIVE,
- 0, indata, NULL, NULL, &status,
- NULL, NULL);
+ if (node_pnn >= talloc_array_length(caps)) {
+ DEBUG(DEBUG_ERR,
+ (__location__ " unexpected PNN %u\n", node_pnn));
+ return;
+ }
- if (ret != 0) {
- DEBUG(DEBUG_ERR, (__location__ " ctdb control for transaction_active failed\n"));
- return -1;
+ caps[node_pnn].retrieved = true;
+ caps[node_pnn].capabilities = *((uint32_t *)outdata.dptr);
+}
+
+struct ctdb_node_capabilities *
+ctdb_get_capabilities(struct ctdb_context *ctdb,
+ TALLOC_CTX *mem_ctx,
+ struct timeval timeout,
+ struct ctdb_node_map_old *nodemap)
+{
+ uint32_t *nodes;
+ uint32_t i, res;
+ struct ctdb_node_capabilities *ret;
+
+ nodes = list_of_active_nodes(ctdb, nodemap, mem_ctx, true);
+
+ ret = talloc_array(mem_ctx, struct ctdb_node_capabilities,
+ nodemap->num);
+ CTDB_NO_MEMORY_NULL(ctdb, ret);
+ /* Prepopulate the expected PNNs */
+ for (i = 0; i < talloc_array_length(ret); i++) {
+ ret[i].retrieved = false;
}
- return status;
+ res = ctdb_client_async_control(ctdb, CTDB_CONTROL_GET_CAPABILITIES,
+ nodes, 0, timeout,
+ false, tdb_null,
+ get_capabilities_callback, NULL,
+ ret);
+ if (res != 0) {
+ DEBUG(DEBUG_ERR,
+ (__location__ " Failed to read node capabilities.\n"));
+ TALLOC_FREE(ret);
+ }
+
+ return ret;
}
+uint32_t *
+ctdb_get_node_capabilities(struct ctdb_node_capabilities *caps,
+ uint32_t pnn)
+{
+ if (pnn < talloc_array_length(caps) && caps[pnn].retrieved) {
+ return &caps[pnn].capabilities;
+ }
-struct ctdb_transaction_handle {
- struct ctdb_db_context *ctdb_db;
- bool in_replay;
- /*
- * we store the reads and writes done under a transaction:
- * - one list stores both reads and writes (m_all),
- * - the other just writes (m_write)
- */
- struct ctdb_marshall_buffer *m_all;
- struct ctdb_marshall_buffer *m_write;
-};
+ return NULL;
+}
-/* start a transaction on a database */
-static int ctdb_transaction_destructor(struct ctdb_transaction_handle *h)
+bool ctdb_node_has_capabilities(struct ctdb_node_capabilities *caps,
+ uint32_t pnn,
+ uint32_t capabilities_required)
{
- tdb_transaction_cancel(h->ctdb_db->ltdb->tdb);
- return 0;
+ uint32_t *capp = ctdb_get_node_capabilities(caps, pnn);
+ return (capp != NULL) &&
+ ((*capp & capabilities_required) == capabilities_required);
}
-/* start a transaction on a database */
-static int ctdb_transaction_fetch_start(struct ctdb_transaction_handle *h)
+
+static struct ctdb_server_id server_id_fetch(struct ctdb_context *ctdb, uint32_t reqid)
{
- struct ctdb_record_handle *rh;
- TDB_DATA key;
- TDB_DATA data;
- struct ctdb_ltdb_header header;
- TALLOC_CTX *tmp_ctx;
- const char *keyname = CTDB_TRANSACTION_LOCK_KEY;
+ struct ctdb_server_id id;
+
+ id.pid = getpid();
+ id.task_id = reqid;
+ id.vnn = ctdb_get_pnn(ctdb);
+ id.unique_id = id.vnn;
+ id.unique_id = (id.unique_id << 32) | reqid;
+
+ return id;
+}
+
+/* This is basically a copy from Samba's server_id.*. However, a
+ * dependency chain stops us from using Samba's version, so use a
+ * renamed copy until a better solution is found. */
+static bool ctdb_server_id_equal(struct ctdb_server_id *id1, struct ctdb_server_id *id2)
+{
+ if (id1->pid != id2->pid) {
+ return false;
+ }
+
+ if (id1->task_id != id2->task_id) {
+ return false;
+ }
+
+ if (id1->vnn != id2->vnn) {
+ return false;
+ }
+
+ if (id1->unique_id != id2->unique_id) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool server_id_exists(struct ctdb_context *ctdb, struct ctdb_server_id *id)
+{
+ struct ctdb_client_id sid;
int ret;
- struct ctdb_db_context *ctdb_db = h->ctdb_db;
- pid_t pid;
- int32_t status;
+ uint32_t result = 0;
- key.dptr = discard_const(keyname);
- key.dsize = strlen(keyname);
+ sid.type = SERVER_TYPE_SAMBA;
+ sid.pnn = id->vnn;
+ sid.server_id = id->pid;
- if (!ctdb_db->persistent) {
- DEBUG(DEBUG_ERR,(__location__ " Attempted transaction on non-persistent database\n"));
- return -1;
+ ret = ctdb_ctrl_check_server_id(ctdb, timeval_current_ofs(3,0),
+ id->vnn, &sid, &result);
+ if (ret != 0) {
+ /* If control times out, assume server_id exists. */
+ return true;
+ }
+
+ if (result) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool g_lock_parse(TALLOC_CTX *mem_ctx, TDB_DATA data,
+ struct ctdb_g_lock_list **locks)
+{
+ struct ctdb_g_lock_list *recs;
+
+ recs = talloc_zero(mem_ctx, struct ctdb_g_lock_list);
+ if (recs == NULL) {
+ return false;
+ }
+
+ if (data.dsize == 0) {
+ goto done;
}
+ if (data.dsize % sizeof(struct ctdb_g_lock) != 0) {
+ DEBUG(DEBUG_ERR, (__location__ "invalid data size %lu in g_lock record\n",
+ (unsigned long)data.dsize));
+ talloc_free(recs);
+ return false;
+ }
+
+ recs->num = data.dsize / sizeof(struct ctdb_g_lock);
+ recs->lock = talloc_memdup(mem_ctx, data.dptr, data.dsize);
+ if (recs->lock == NULL) {
+ talloc_free(recs);
+ return false;
+ }
+
+done:
+ if (locks != NULL) {
+ *locks = recs;
+ }
+
+ return true;
+}
+
+
+static bool g_lock_lock(TALLOC_CTX *mem_ctx,
+ struct ctdb_db_context *ctdb_db,
+ const char *keyname, uint32_t reqid)
+{
+ TDB_DATA key, data;
+ struct ctdb_record_handle *h;
+ struct ctdb_g_lock_list *locks;
+ struct ctdb_server_id id;
+ struct timeval t_start;
+ int i;
+
+ key.dptr = (uint8_t *)discard_const(keyname);
+ key.dsize = strlen(keyname) + 1;
+
+ t_start = timeval_current();
+
again:
- tmp_ctx = talloc_new(h);
+ /* Keep trying for an hour. */
+ if (timeval_elapsed(&t_start) > 3600) {
+ return false;
+ }
- rh = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, NULL);
- if (rh == NULL) {
- DEBUG(DEBUG_ERR,(__location__ " Failed to fetch_lock database\n"));
- talloc_free(tmp_ctx);
- return -1;
+ h = ctdb_fetch_lock(ctdb_db, mem_ctx, key, &data);
+ if (h == NULL) {
+ return false;
}
- status = ctdb_ctrl_transaction_active(ctdb_db->ctdb,
- CTDB_CURRENT_NODE,
- ctdb_db->db_id);
- if (status == 1) {
- unsigned long int usec = (1000 + random()) % 100000;
- DEBUG(DEBUG_DEBUG, (__location__ " transaction is active "
- "on db_id[0x%08x]. waiting for %lu "
- "microseconds\n",
- ctdb_db->db_id, usec));
- talloc_free(tmp_ctx);
- usleep(usec);
+ if (!g_lock_parse(h, data, &locks)) {
+ DEBUG(DEBUG_ERR, ("g_lock: error parsing locks\n"));
+ talloc_free(data.dptr);
+ talloc_free(h);
+ return false;
+ }
+
+ talloc_free(data.dptr);
+
+ id = server_id_fetch(ctdb_db->ctdb, reqid);
+
+ i = 0;
+ while (i < locks->num) {
+ if (ctdb_server_id_equal(&locks->lock[i].sid, &id)) {
+ /* Internal error */
+ talloc_free(h);
+ return false;
+ }
+
+ if (!server_id_exists(ctdb_db->ctdb, &locks->lock[i].sid)) {
+ if (i < locks->num-1) {
+ locks->lock[i] = locks->lock[locks->num-1];
+ }
+ locks->num--;
+ continue;
+ }
+
+ /* This entry is locked. */
+ DEBUG(DEBUG_INFO, ("g_lock: lock already granted for "
+ "pid=0x%llx taskid=%x vnn=%d id=0x%llx\n",
+ (unsigned long long)id.pid,
+ id.task_id, id.vnn,
+ (unsigned long long)id.unique_id));
+ talloc_free(h);
goto again;
}
- /*
- * store the pid in the database:
- * it is not enough that the node is dmaster...
- */
- pid = getpid();
- data.dptr = (unsigned char *)&pid;
- data.dsize = sizeof(pid_t);
- rh->header.rsn++;
- rh->header.dmaster = ctdb_db->ctdb->pnn;
- ret = ctdb_ltdb_store(ctdb_db, key, &(rh->header), data);
- if (ret != 0) {
- DEBUG(DEBUG_ERR, (__location__ " Failed to store pid in "
- "transaction record\n"));
- talloc_free(tmp_ctx);
- return -1;
+ locks->lock = talloc_realloc(locks, locks->lock, struct ctdb_g_lock,
+ locks->num+1);
+ if (locks->lock == NULL) {
+ talloc_free(h);
+ return false;
}
- talloc_free(rh);
+ locks->lock[locks->num].type = CTDB_G_LOCK_WRITE;
+ locks->lock[locks->num].sid = id;
+ locks->num++;
- ret = tdb_transaction_start(ctdb_db->ltdb->tdb);
- if (ret != 0) {
- DEBUG(DEBUG_ERR,(__location__ " Failed to start tdb transaction\n"));
- talloc_free(tmp_ctx);
- return -1;
+ data.dptr = (uint8_t *)locks->lock;
+ data.dsize = locks->num * sizeof(struct ctdb_g_lock);
+
+ if (ctdb_record_store(h, data) != 0) {
+ DEBUG(DEBUG_ERR, ("g_lock: failed to write transaction lock for "
+ "pid=0x%llx taskid=%x vnn=%d id=0x%llx\n",
+ (unsigned long long)id.pid,
+ id.task_id, id.vnn,
+ (unsigned long long)id.unique_id));
+ talloc_free(h);
+ return false;
}
- ret = ctdb_ltdb_fetch(ctdb_db, key, &header, tmp_ctx, &data);
- if (ret != 0) {
- DEBUG(DEBUG_ERR,(__location__ " Failed to re-fetch transaction "
- "lock record inside transaction\n"));
- tdb_transaction_cancel(ctdb_db->ltdb->tdb);
- talloc_free(tmp_ctx);
- goto again;
+ DEBUG(DEBUG_INFO, ("g_lock: lock granted for "
+ "pid=0x%llx taskid=%x vnn=%d id=0x%llx\n",
+ (unsigned long long)id.pid,
+ id.task_id, id.vnn,
+ (unsigned long long)id.unique_id));
+
+ talloc_free(h);
+ return true;
+}
+
+static bool g_lock_unlock(TALLOC_CTX *mem_ctx,
+ struct ctdb_db_context *ctdb_db,
+ const char *keyname, uint32_t reqid)
+{
+ TDB_DATA key, data;
+ struct ctdb_record_handle *h;
+ struct ctdb_g_lock_list *locks;
+ struct ctdb_server_id id;
+ int i;
+ bool found = false;
+
+ key.dptr = (uint8_t *)discard_const(keyname);
+ key.dsize = strlen(keyname) + 1;
+ h = ctdb_fetch_lock(ctdb_db, mem_ctx, key, &data);
+ if (h == NULL) {
+ return false;
}
- if (header.dmaster != ctdb_db->ctdb->pnn) {
- DEBUG(DEBUG_DEBUG,(__location__ " not dmaster any more on "
- "transaction lock record\n"));
- tdb_transaction_cancel(ctdb_db->ltdb->tdb);
- talloc_free(tmp_ctx);
- goto again;
+ if (!g_lock_parse(h, data, &locks)) {
+ DEBUG(DEBUG_ERR, ("g_lock: error parsing locks\n"));
+ talloc_free(data.dptr);
+ talloc_free(h);
+ return false;
}
- if ((data.dsize != sizeof(pid_t)) || (*(pid_t *)(data.dptr) != pid)) {
- DEBUG(DEBUG_DEBUG, (__location__ " my pid is not stored in "
- "the transaction lock record\n"));
- tdb_transaction_cancel(ctdb_db->ltdb->tdb);
- talloc_free(tmp_ctx);
- goto again;
+ talloc_free(data.dptr);
+
+ id = server_id_fetch(ctdb_db->ctdb, reqid);
+
+ for (i=0; i<locks->num; i++) {
+ if (ctdb_server_id_equal(&locks->lock[i].sid, &id)) {
+ if (i < locks->num-1) {
+ locks->lock[i] = locks->lock[locks->num-1];
+ }
+ locks->num--;
+ found = true;
+ break;
+ }
}
- talloc_free(tmp_ctx);
+ if (!found) {
+ DEBUG(DEBUG_ERR, ("g_lock: lock not found\n"));
+ talloc_free(h);
+ return false;
+ }
+ data.dptr = (uint8_t *)locks->lock;
+ data.dsize = locks->num * sizeof(struct ctdb_g_lock);
+
+ if (ctdb_record_store(h, data) != 0) {
+ talloc_free(h);
+ return false;
+ }
+
+ talloc_free(h);
+ return true;
+}
+
+
+struct ctdb_transaction_handle {
+ struct ctdb_db_context *ctdb_db;
+ struct ctdb_db_context *g_lock_db;
+ char *lock_name;
+ uint32_t reqid;
+ /*
+ * we store reads and writes done under a transaction:
+ * - one list stores both reads and writes (m_all)
+ * - the other just writes (m_write)
+ */
+ struct ctdb_marshall_buffer *m_all;
+ struct ctdb_marshall_buffer *m_write;
+};
+
+static int ctdb_transaction_destructor(struct ctdb_transaction_handle *h)
+{
+ g_lock_unlock(h, h->g_lock_db, h->lock_name, h->reqid);
+ reqid_remove(h->ctdb_db->ctdb->idr, h->reqid);
return 0;
}
-/* start a transaction on a database */
+/**
+ * start a transaction on a database
+ */
struct ctdb_transaction_handle *ctdb_transaction_start(struct ctdb_db_context *ctdb_db,
TALLOC_CTX *mem_ctx)
{
struct ctdb_transaction_handle *h;
- int ret;
+ struct ctdb_client_id id;
h = talloc_zero(mem_ctx, struct ctdb_transaction_handle);
if (h == NULL) {
- DEBUG(DEBUG_ERR,(__location__ " oom for transaction handle\n"));
+ DEBUG(DEBUG_ERR, (__location__ " memory allocation error\n"));
return NULL;
}
h->ctdb_db = ctdb_db;
+ h->lock_name = talloc_asprintf(h, "transaction_db_0x%08x",
+ (unsigned int)ctdb_db->db_id);
+ if (h->lock_name == NULL) {
+ DEBUG(DEBUG_ERR, (__location__ " talloc asprintf failed\n"));
+ talloc_free(h);
+ return NULL;
+ }
- ret = ctdb_transaction_fetch_start(h);
- if (ret != 0) {
+ h->g_lock_db = ctdb_attach(h->ctdb_db->ctdb, timeval_current_ofs(3,0),
+ "g_lock.tdb", false, 0);
+ if (!h->g_lock_db) {
+ DEBUG(DEBUG_ERR, (__location__ " unable to attach to g_lock.tdb\n"));
talloc_free(h);
return NULL;
}
- talloc_set_destructor(h, ctdb_transaction_destructor);
+ id.type = SERVER_TYPE_SAMBA;
+ id.pnn = ctdb_get_pnn(ctdb_db->ctdb);
+ id.server_id = getpid();
- return h;
-}
+ if (ctdb_ctrl_register_server_id(ctdb_db->ctdb, timeval_current_ofs(3,0),
+ &id) != 0) {
+ DEBUG(DEBUG_ERR, (__location__ " unable to register server id\n"));
+ talloc_free(h);
+ return NULL;
+ }
+ h->reqid = reqid_new(h->ctdb_db->ctdb->idr, h);
+ if (!g_lock_lock(h, h->g_lock_db, h->lock_name, h->reqid)) {
+ DEBUG(DEBUG_ERR, (__location__ " Error locking g_lock.tdb\n"));
+ talloc_free(h);
+ return NULL;
+ }
-/*
- fetch a record inside a transaction
+ talloc_set_destructor(h, ctdb_transaction_destructor);
+ return h;
+}
+
+/**
+ * fetch a record inside a transaction
*/
-int ctdb_transaction_fetch(struct ctdb_transaction_handle *h,
- TALLOC_CTX *mem_ctx,
+int ctdb_transaction_fetch(struct ctdb_transaction_handle *h,
+ TALLOC_CTX *mem_ctx,
TDB_DATA key, TDB_DATA *data)
{
struct ctdb_ltdb_header header;
*data = tdb_null;
ret = 0;
}
-
+
if (ret != 0) {
return ret;
}
- if (!h->in_replay) {
- h->m_all = ctdb_marshall_add(h, h->m_all, h->ctdb_db->db_id, 1, key, NULL, *data);
- if (h->m_all == NULL) {
- DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n"));
- return -1;
- }
+ h->m_all = ctdb_marshall_add(h, h->m_all, h->ctdb_db->db_id, 1, key, NULL, *data);
+ if (h->m_all == NULL) {
+ DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n"));
+ return -1;
}
return 0;
}
-/*
- stores a record inside a transaction
+/**
+ * stores a record inside a transaction
*/
-int ctdb_transaction_store(struct ctdb_transaction_handle *h,
+int ctdb_transaction_store(struct ctdb_transaction_handle *h,
TDB_DATA key, TDB_DATA data)
{
TALLOC_CTX *tmp_ctx = talloc_new(h);
TDB_DATA olddata;
int ret;
- ZERO_STRUCT(header);
-
/* we need the header so we can update the RSN */
ret = ctdb_ltdb_fetch(h->ctdb_db, key, &header, tmp_ctx, &olddata);
if (ret == -1 && header.dmaster == (uint32_t)-1) {
}
if (data.dsize == olddata.dsize &&
- memcmp(data.dptr, olddata.dptr, data.dsize) == 0) {
+ memcmp(data.dptr, olddata.dptr, data.dsize) == 0 &&
+ header.rsn != 0) {
/* save writing the same data */
talloc_free(tmp_ctx);
return 0;
header.dmaster = h->ctdb_db->ctdb->pnn;
header.rsn++;
- if (!h->in_replay) {
- h->m_all = ctdb_marshall_add(h, h->m_all, h->ctdb_db->db_id, 0, key, NULL, data);
- if (h->m_all == NULL) {
- DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n"));
- talloc_free(tmp_ctx);
- return -1;
- }
- }
+ h->m_all = ctdb_marshall_add(h, h->m_all, h->ctdb_db->db_id, 0, key, NULL, data);
+ if (h->m_all == NULL) {
+ DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
h->m_write = ctdb_marshall_add(h, h->m_write, h->ctdb_db->db_id, 0, key, &header, data);
if (h->m_write == NULL) {
talloc_free(tmp_ctx);
return -1;
}
-
- ret = ctdb_ltdb_store(h->ctdb_db, key, &header, data);
talloc_free(tmp_ctx);
-
- return ret;
+ return 0;
}
-/*
- replay a transaction
- */
-static int ctdb_replay_transaction(struct ctdb_transaction_handle *h)
+static int ctdb_fetch_db_seqnum(struct ctdb_db_context *ctdb_db, uint64_t *seqnum)
{
- int ret, i;
- struct ctdb_rec_data *rec = NULL;
+ const char *keyname = CTDB_DB_SEQNUM_KEY;
+ TDB_DATA key, data;
+ struct ctdb_ltdb_header header;
+ int ret;
- h->in_replay = true;
- talloc_free(h->m_write);
- h->m_write = NULL;
+ key.dptr = (uint8_t *)discard_const(keyname);
+ key.dsize = strlen(keyname) + 1;
- ret = ctdb_transaction_fetch_start(h);
+ ret = ctdb_ltdb_fetch(ctdb_db, key, &header, ctdb_db, &data);
if (ret != 0) {
- return ret;
+ *seqnum = 0;
+ return 0;
}
- for (i=0;i<h->m_all->count;i++) {
- TDB_DATA key, data;
+ if (data.dsize == 0) {
+ *seqnum = 0;
+ return 0;
+ }
- rec = ctdb_marshall_loop_next(h->m_all, rec, NULL, NULL, &key, &data);
- if (rec == NULL) {
- DEBUG(DEBUG_ERR, (__location__ " Out of records in ctdb_replay_transaction?\n"));
- goto failed;
- }
+ if (data.dsize != sizeof(*seqnum)) {
+ DEBUG(DEBUG_ERR, (__location__ " Invalid data recived len=%zi\n",
+ data.dsize));
+ talloc_free(data.dptr);
+ return -1;
+ }
- if (rec->reqid == 0) {
- /* its a store */
- if (ctdb_transaction_store(h, key, data) != 0) {
- goto failed;
- }
- } else {
- TDB_DATA data2;
- TALLOC_CTX *tmp_ctx = talloc_new(h);
+ *seqnum = *(uint64_t *)data.dptr;
+ talloc_free(data.dptr);
- if (ctdb_transaction_fetch(h, tmp_ctx, key, &data2) != 0) {
- talloc_free(tmp_ctx);
- goto failed;
- }
- if (data2.dsize != data.dsize ||
- memcmp(data2.dptr, data.dptr, data.dsize) != 0) {
- /* the record has changed on us - we have to give up */
- talloc_free(tmp_ctx);
- goto failed;
- }
- talloc_free(tmp_ctx);
- }
- }
-
return 0;
-
-failed:
- tdb_transaction_cancel(h->ctdb_db->ltdb->tdb);
- return -1;
}
-/*
- commit a transaction
- */
-int ctdb_transaction_commit(struct ctdb_transaction_handle *h)
+static int ctdb_store_db_seqnum(struct ctdb_transaction_handle *h,
+ uint64_t seqnum)
{
- int ret, retries=0;
- int32_t status;
- struct ctdb_context *ctdb = h->ctdb_db->ctdb;
- struct timeval timeout;
- enum ctdb_controls failure_control = CTDB_CONTROL_TRANS2_ERROR;
+ const char *keyname = CTDB_DB_SEQNUM_KEY;
+ TDB_DATA key, data;
- talloc_set_destructor(h, NULL);
+ key.dptr = (uint8_t *)discard_const(keyname);
+ key.dsize = strlen(keyname) + 1;
- /* our commit strategy is quite complex.
+ data.dptr = (uint8_t *)&seqnum;
+ data.dsize = sizeof(seqnum);
- - we first try to commit the changes to all other nodes
+ return ctdb_transaction_store(h, key, data);
+}
- - if that works, then we commit locally and we are done
- - if a commit on another node fails, then we need to cancel
- the transaction, then restart the transaction (thus
- opening a window of time for a pending recovery to
- complete), then replay the transaction, checking all the
- reads and writes (checking that reads give the same data,
- and writes succeed). Then we retry the transaction to the
- other nodes
- */
+/**
+ * commit a transaction
+ */
+int ctdb_transaction_commit(struct ctdb_transaction_handle *h)
+{
+ int ret;
+ uint64_t old_seqnum, new_seqnum;
+ int32_t status;
+ struct timeval timeout;
-again:
if (h->m_write == NULL) {
/* no changes were made */
- tdb_transaction_cancel(h->ctdb_db->ltdb->tdb);
talloc_free(h);
return 0;
}
- /* tell ctdbd to commit to the other nodes */
- timeout = timeval_current_ofs(1, 0);
- ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id,
- retries==0?CTDB_CONTROL_TRANS2_COMMIT:CTDB_CONTROL_TRANS2_COMMIT_RETRY, 0,
- ctdb_marshall_finish(h->m_write), NULL, NULL, &status,
- &timeout, NULL);
- if (ret != 0 || status != 0) {
- tdb_transaction_cancel(h->ctdb_db->ltdb->tdb);
- DEBUG(DEBUG_NOTICE, (__location__ " transaction commit%s failed"
- ", retrying after 1 second...\n",
- (retries==0)?"":"retry "));
- sleep(1);
+ ret = ctdb_fetch_db_seqnum(h->ctdb_db, &old_seqnum);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, (__location__ " failed to fetch db sequence number\n"));
+ ret = -1;
+ goto done;
+ }
+ new_seqnum = old_seqnum + 1;
+ ret = ctdb_store_db_seqnum(h, new_seqnum);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, (__location__ " failed to store db sequence number\n"));
+ ret = -1;
+ goto done;
+ }
+
+again:
+ timeout = timeval_current_ofs(3,0);
+ ret = ctdb_control(h->ctdb_db->ctdb, CTDB_CURRENT_NODE,
+ h->ctdb_db->db_id,
+ CTDB_CONTROL_TRANS3_COMMIT, 0,
+ ctdb_marshall_finish(h->m_write), NULL, NULL,
+ &status, &timeout, NULL);
+ if (ret != 0 || status != 0) {
+ /*
+ * TRANS3_COMMIT control will only fail if recovery has been
+ * triggered. Check if the database has been updated or not.
+ */
+ ret = ctdb_fetch_db_seqnum(h->ctdb_db, &new_seqnum);
if (ret != 0) {
- failure_control = CTDB_CONTROL_TRANS2_ERROR;
- } else {
- /* work out what error code we will give if we
- have to fail the operation */
- switch ((enum ctdb_trans2_commit_error)status) {
- case CTDB_TRANS2_COMMIT_SUCCESS:
- case CTDB_TRANS2_COMMIT_SOMEFAIL:
- case CTDB_TRANS2_COMMIT_TIMEOUT:
- failure_control = CTDB_CONTROL_TRANS2_ERROR;
- break;
- case CTDB_TRANS2_COMMIT_ALLFAIL:
- failure_control = CTDB_CONTROL_TRANS2_FINISHED;
- break;
- }
+ DEBUG(DEBUG_ERR, (__location__ " failed to fetch db sequence number\n"));
+ goto done;
}
- if (++retries == 100) {
- DEBUG(DEBUG_ERR,(__location__ " Giving up transaction on db 0x%08x after %d retries failure_control=%u\n",
- h->ctdb_db->db_id, retries, (unsigned)failure_control));
- ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id,
- failure_control, CTDB_CTRL_FLAG_NOREPLY,
- tdb_null, NULL, NULL, NULL, NULL, NULL);
- talloc_free(h);
- return -1;
- }
-
- if (ctdb_replay_transaction(h) != 0) {
- DEBUG(DEBUG_ERR, (__location__ " Failed to replay "
- "transaction on db 0x%08x, "
- "failure control =%u\n",
- h->ctdb_db->db_id,
- (unsigned)failure_control));
- ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id,
- failure_control, CTDB_CTRL_FLAG_NOREPLY,
- tdb_null, NULL, NULL, NULL, NULL, NULL);
- talloc_free(h);
- return -1;
+ if (new_seqnum == old_seqnum) {
+ /* Database not yet updated, try again */
+ goto again;
}
- goto again;
- } else {
- failure_control = CTDB_CONTROL_TRANS2_ERROR;
- }
- /* do the real commit locally */
- ret = tdb_transaction_commit(h->ctdb_db->ltdb->tdb);
- if (ret != 0) {
- DEBUG(DEBUG_ERR, (__location__ " Failed to commit transaction "
- "on db id 0x%08x locally, "
- "failure_control=%u\n",
- h->ctdb_db->db_id,
- (unsigned)failure_control));
- ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id,
- failure_control, CTDB_CTRL_FLAG_NOREPLY,
- tdb_null, NULL, NULL, NULL, NULL, NULL);
- talloc_free(h);
- return ret;
+ if (new_seqnum != (old_seqnum + 1)) {
+ DEBUG(DEBUG_ERR, (__location__ " new seqnum [%llu] != old seqnum [%llu] + 1\n",
+ (long long unsigned)new_seqnum,
+ (long long unsigned)old_seqnum));
+ ret = -1;
+ goto done;
+ }
}
- /* tell ctdbd that we are finished with our local commit */
- ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id,
- CTDB_CONTROL_TRANS2_FINISHED, CTDB_CTRL_FLAG_NOREPLY,
- tdb_null, NULL, NULL, NULL, NULL, NULL);
+ ret = 0;
+
+done:
+ talloc_free(h);
+ return ret;
+}
+
+/**
+ * cancel a transaction
+ */
+int ctdb_transaction_cancel(struct ctdb_transaction_handle *h)
+{
talloc_free(h);
return 0;
}
+
/*
recovery daemon ping to main daemon
*/
return 0;
}
-/* when forking the main daemon and the child process needs to connect back
- * to the daemon as a client process, this function can be used to change
- * the ctdb context from daemon into client mode
- */
-int switch_from_server_to_client(struct ctdb_context *ctdb, const char *fmt, ...)
-{
- int ret;
- va_list ap;
-
- /* Add extra information so we can identify this in the logs */
- va_start(ap, fmt);
- debug_extra = talloc_strdup_append(talloc_vasprintf(NULL, fmt, ap), ":");
- va_end(ap);
-
- /* shutdown the transport */
- if (ctdb->methods) {
- ctdb->methods->shutdown(ctdb);
- }
-
- /* get a new event context */
- talloc_free(ctdb->ev);
- ctdb->ev = event_context_init(ctdb);
- tevent_loop_allow_nesting(ctdb->ev);
-
- close(ctdb->daemon.sd);
- ctdb->daemon.sd = -1;
-
- /* the client does not need to be realtime */
- if (ctdb->do_setsched) {
- ctdb_restore_scheduler(ctdb);
- }
-
- /* initialise ctdb */
- ret = ctdb_socket_connect(ctdb);
- if (ret != 0) {
- DEBUG(DEBUG_ALERT, (__location__ " Failed to init ctdb client\n"));
- return -1;
- }
-
- ctdb->can_send_controls = true;
-
- return 0;
-}
-
/*
get the status of running the monitor eventscripts: NULL means never run.
*/
-int ctdb_ctrl_getscriptstatus(struct ctdb_context *ctdb,
- struct timeval timeout, uint32_t destnode,
- TALLOC_CTX *mem_ctx, enum ctdb_eventscript_call type,
- struct ctdb_scripts_wire **scripts)
+int ctdb_ctrl_getscriptstatus(struct ctdb_context *ctdb,
+ struct timeval timeout, uint32_t destnode,
+ TALLOC_CTX *mem_ctx,
+ enum ctdb_event type,
+ struct ctdb_script_list_old **scripts)
{
int ret;
TDB_DATA outdata, indata;
if (outdata.dsize == 0) {
*scripts = NULL;
} else {
- *scripts = (struct ctdb_scripts_wire *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+ *scripts = (struct ctdb_script_list_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
talloc_free(outdata.dptr);
}
-
+
return 0;
}
}
-int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_ban_time *bantime)
+int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout,
+ uint32_t destnode, struct ctdb_ban_state *bantime)
{
int ret;
TDB_DATA data;
}
-int ctdb_ctrl_get_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_ban_time **bantime)
+int ctdb_ctrl_get_ban(struct ctdb_context *ctdb, struct timeval timeout,
+ uint32_t destnode, TALLOC_CTX *mem_ctx,
+ struct ctdb_ban_state **bantime)
{
int ret;
TDB_DATA outdata;
return -1;
}
- *bantime = (struct ctdb_ban_time *)talloc_steal(mem_ctx, outdata.dptr);
+ *bantime = (struct ctdb_ban_state *)talloc_steal(mem_ctx, outdata.dptr);
talloc_free(tmp_ctx);
return 0;
return 0;
}
-int ctdb_ctrl_getstathistory(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_statistics_wire **stats)
+int ctdb_ctrl_getstathistory(struct ctdb_context *ctdb,
+ struct timeval timeout, uint32_t destnode,
+ TALLOC_CTX *mem_ctx,
+ struct ctdb_statistics_list_old **stats)
{
int ret;
TDB_DATA outdata;
return -1;
}
- *stats = (struct ctdb_statistics_wire *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+ *stats = (struct ctdb_statistics_list_old *)talloc_memdup(mem_ctx,
+ outdata.dptr,
+ outdata.dsize);
talloc_free(outdata.dptr);
-
+
return 0;
}
{
struct ctdb_client_control_state *handle;
struct ctdb_marshall_buffer *m;
- struct ctdb_rec_data *rec;
+ struct ctdb_rec_data_old *rec;
TDB_DATA outdata;
m = talloc_zero(mem_ctx, struct ctdb_marshall_buffer);