#include "db_wrap.h"
#include "lib/tdb/include/tdb.h"
#include "lib/util/dlinklist.h"
-#include "lib/events/events.h"
+#include "lib/tevent/tevent.h"
#include "system/network.h"
#include "system/filesys.h"
#include "system/locale.h"
*/
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, uint32_t caller)
+ TDB_DATA *data)
{
struct ctdb_call_info *c;
struct ctdb_registered_call *fn;
return -1;
}
- 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) {
+ /* we need to force the record to be written out if this was a remote access */
+ if (c->new_data == NULL) {
c->new_data = &c->record_data;
}
ctdb->daemon.queue = ctdb_queue_setup(ctdb, ctdb, ctdb->daemon.sd,
CTDB_DS_ALIGNMENT,
- ctdb_client_read_cb, ctdb);
+ ctdb_client_read_cb, ctdb, "to-ctdbd");
return 0;
}
*(state->call) = *call;
state->ctdb_db = ctdb_db;
- ret = ctdb_call_local(ctdb_db, state->call, header, state, data, ctdb->pnn);
+ ret = ctdb_call_local(ctdb_db, state->call, header, state, data);
return state;
}
tell the daemon what messaging srvid we will use, and register the message
handler function in the client
*/
-int ctdb_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
- ctdb_message_fn_t handler,
+int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
+ ctdb_msg_fn_t handler,
void *private_data)
{
/*
tell the daemon we no longer want a srvid
*/
-int ctdb_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;
/*
send a message - from client context
*/
-int ctdb_send_message(struct ctdb_context *ctdb, uint32_t pnn,
+int ctdb_client_send_message(struct ctdb_context *ctdb, uint32_t pnn,
uint64_t srvid, TDB_DATA data)
{
struct ctdb_req_message *r;
state.private_data = private_data;
state.fn = fn;
- ret = ctdb_set_message_handler(ctdb_db->ctdb, srvid, traverse_handler, &state);
+ ret = ctdb_client_set_message_handler(ctdb_db->ctdb, srvid, traverse_handler, &state);
if (ret != 0) {
DEBUG(DEBUG_ERR,("Failed to setup traverse handler\n"));
return -1;
data, NULL, NULL, &status, NULL, NULL);
if (ret != 0 || status != 0) {
DEBUG(DEBUG_ERR,("ctdb_traverse_all failed\n"));
- ctdb_remove_message_handler(ctdb_db->ctdb, srvid, &state);
+ ctdb_client_remove_message_handler(ctdb_db->ctdb, srvid, &state);
return -1;
}
event_loop_once(ctdb_db->ctdb->ev);
}
- ret = ctdb_remove_message_handler(ctdb_db->ctdb, srvid, &state);
+ ret = ctdb_client_remove_message_handler(ctdb_db->ctdb, srvid, &state);
if (ret != 0) {
DEBUG(DEBUG_ERR,("Failed to remove ctdb_traverse handler\n"));
return -1;
fprintf(f, "dmaster: %u\n", h->dmaster);
fprintf(f, "rsn: %llu\n", (unsigned long long)h->rsn);
- fprintf(f, "data(%u) = \"", (unsigned)data.dsize);
+ fprintf(f, "data(%u) = \"", (unsigned)(data.dsize - sizeof(*h)));
for (i=sizeof(*h);i<data.dsize;i++) {
if (ISASCII(data.dptr[i])) {
fprintf(f, "%c", data.dptr[i]);
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_control_get_ifaces **_ifaces)
{
- return -1;
+ int ret;
+ TDB_DATA outdata;
+ int32_t res;
+ struct ctdb_control_get_ifaces *ifaces;
+ uint32_t len;
+ uint32_t i;
+
+ ret = ctdb_control(ctdb, destnode, 0,
+ CTDB_CONTROL_GET_IFACES, 0, tdb_null,
+ mem_ctx, &outdata, &res, &timeout, NULL);
+ if (ret != 0 || res != 0) {
+ DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
+ "failed ret:%d res:%d\n",
+ ret, res));
+ return -1;
+ }
+
+ len = offsetof(struct ctdb_control_get_ifaces, ifaces);
+ if (len > outdata.dsize) {
+ DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
+ "returned invalid data with size %u > %u\n",
+ (unsigned int)outdata.dsize,
+ (unsigned int)len));
+ dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
+ return -1;
+ }
+
+ ifaces = (struct ctdb_control_get_ifaces *)outdata.dptr;
+ len += ifaces->num*sizeof(struct ctdb_control_iface_info);
+
+ if (len > outdata.dsize) {
+ DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
+ "returned invalid data with size %u > %u\n",
+ (unsigned int)outdata.dsize,
+ (unsigned int)len));
+ dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
+ return -1;
+ }
+
+ /* make sure we null terminate the returned strings */
+ for (i=0; i < ifaces->num; i++) {
+ ifaces->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
+ }
+
+ *_ifaces = (struct ctdb_control_get_ifaces *)talloc_memdup(mem_ctx,
+ outdata.dptr,
+ outdata.dsize);
+ talloc_free(outdata.dptr);
+ if (*_ifaces == NULL) {
+ DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
+ "talloc_memdup size %u failed\n",
+ (unsigned int)outdata.dsize));
+ return -1;
+ }
+
+ return 0;
}
int ctdb_ctrl_set_iface_link(struct ctdb_context *ctdb,
TALLOC_CTX *mem_ctx,
const struct ctdb_control_iface_info *info)
{
- return -1;
+ int ret;
+ TDB_DATA indata;
+ int32_t res;
+
+ indata.dptr = discard_const_p(uint8_t, info);
+ indata.dsize = sizeof(*info);
+
+ ret = ctdb_control(ctdb, destnode, 0,
+ CTDB_CONTROL_SET_IFACE_LINK_STATE, 0, indata,
+ mem_ctx, NULL, &res, &timeout, NULL);
+ if (ret != 0 || res != 0) {
+ DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set iface link "
+ "failed ret:%d res:%d\n",
+ ret, res));
+ return -1;
+ }
+
+ return 0;
}
/*
}
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 = ctdb_set_socketname(ctdb, CTDB_PATH);
return NULL;
}
+ ctdb->statistics.statistics_start_time = timeval_current();
+
return ctdb;
}
return 0;
}
+const char *ctdb_get_socketname(struct ctdb_context *ctdb)
+{
+ return ctdb->daemon.name;
+}
+
/*
return the pnn of this node
*/
* 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)
+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) {
/* 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) {
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 ret;
+ TDB_DATA outdata;
+ int32_t res;
+
+ ret = ctdb_control(ctdb, destnode, 0,
+ CTDB_CONTROL_GET_STAT_HISTORY, 0, tdb_null,
+ mem_ctx, &outdata, &res, &timeout, NULL);
+ if (ret != 0 || res != 0 || outdata.dsize == 0) {
+ DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getstathistory failed ret:%d res:%d\n", ret, res));
+ return -1;
+ }
+
+ *stats = (struct ctdb_statistics_wire *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+ talloc_free(outdata.dptr);
+
+ return 0;
+}