Remove LACOUNT and LACCESSOR and migrate the records immediately.
[sahlberg/ctdb.git] / client / ctdb_client.c
index b623bfe352172e41018a0a4dbe28371eb8ec6875..1abea127a989cf9bc21b0afed89a340a33c365fb 100644 (file)
@@ -22,7 +22,7 @@
 #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"
@@ -72,7 +72,7 @@ struct ctdb_req_header *_ctdbd_allocate_pkt(struct ctdb_context *ctdb,
 */
 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;
@@ -105,15 +105,8 @@ int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call,
                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;
        }
 
@@ -281,7 +274,7 @@ int ctdb_socket_connect(struct ctdb_context *ctdb)
 
        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;
 }
 
@@ -368,7 +361,7 @@ static struct ctdb_client_call_state *ctdb_client_call_local_send(struct ctdb_db
        *(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;
 }
@@ -474,8 +467,8 @@ int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call)
   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)
                                    
 {
@@ -496,7 +489,7 @@ int ctdb_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
 /*
   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;
@@ -517,7 +510,7 @@ int ctdb_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void
 /*
   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;
@@ -1497,6 +1490,44 @@ int ctdb_ctrl_getdbname(struct ctdb_context *ctdb, struct timeval timeout, uint3
        return 0;
 }
 
+/*
+  get the health status of a db
+ */
+int ctdb_ctrl_getdbhealth(struct ctdb_context *ctdb,
+                         struct timeval timeout,
+                         uint32_t destnode,
+                         uint32_t dbid, TALLOC_CTX *mem_ctx,
+                         const char **reason)
+{
+       int ret;
+       int32_t res;
+       TDB_DATA data;
+
+       data.dptr = (uint8_t *)&dbid;
+       data.dsize = sizeof(dbid);
+
+       ret = ctdb_control(ctdb, destnode, 0,
+                          CTDB_CONTROL_DB_GET_HEALTH, 0, data,
+                          mem_ctx, &data, &res, &timeout, NULL);
+       if (ret != 0 || res != 0) {
+               return -1;
+       }
+
+       if (data.dsize == 0) {
+               (*reason) = NULL;
+               return 0;
+       }
+
+       (*reason) = talloc_strndup(mem_ctx, (const char *)data.dptr, data.dsize);
+       if ((*reason) == NULL) {
+               return -1;
+       }
+
+       talloc_free(data.dptr);
+
+       return 0;
+}
+
 /*
   create a database
  */
@@ -1683,7 +1714,7 @@ struct ctdb_db_context *ctdb_attach(struct ctdb_context *ctdb, const char *name,
        }
 
        tdb_flags = persistent?TDB_DEFAULT:TDB_NOSYNC;
-       if (!ctdb->do_setsched) {
+       if (ctdb->valgrinding) {
                tdb_flags |= TDB_NOMMAP;
        }
        tdb_flags |= TDB_DISALLOW_NESTING;
@@ -1811,7 +1842,7 @@ int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *
        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;
@@ -1828,7 +1859,7 @@ int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *
                           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;
        }
 
@@ -1836,7 +1867,7 @@ int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *
                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;
@@ -1849,7 +1880,7 @@ int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *
 /*
   called on each key during a catdb
  */
-static int dumpdb_fn(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *p)
+int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *p)
 {
        int i;
        FILE *f = (FILE *)p;
@@ -1868,7 +1899,7 @@ static int dumpdb_fn(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, voi
        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]);
@@ -1888,7 +1919,7 @@ static int dumpdb_fn(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, voi
  */
 int ctdb_dump_db(struct ctdb_db_context *ctdb_db, FILE *f)
 {
-       return ctdb_traverse(ctdb_db, dumpdb_fn, f);
+       return ctdb_traverse(ctdb_db, ctdb_dumpdb_record, f);
 }
 
 /*
@@ -2280,16 +2311,18 @@ int ctdb_ctrl_list_tunables(struct ctdb_context *ctdb,
 }
 
 
-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)
+int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb,
+                                  struct timeval timeout, uint32_t destnode,
+                                  TALLOC_CTX *mem_ctx,
+                                  uint32_t flags,
+                                  struct ctdb_all_public_ips **ips)
 {
        int ret;
        TDB_DATA outdata;
        int32_t res;
 
        ret = ctdb_control(ctdb, destnode, 0, 
-                          CTDB_CONTROL_GET_PUBLIC_IPS, 0, tdb_null, 
+                          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"));
@@ -2306,6 +2339,16 @@ int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
        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)
+{
+       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)
@@ -2339,6 +2382,162 @@ int ctdb_ctrl_get_public_ipsv4(struct ctdb_context *ctdb,
        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;
+
+       indata.dptr = discard_const_p(uint8_t, addr);
+       indata.dsize = sizeof(*addr);
+
+       ret = ctdb_control(ctdb, destnode, 0,
+                          CTDB_CONTROL_GET_PUBLIC_IP_INFO, 0, indata,
+                          mem_ctx, &outdata, &res, &timeout, NULL);
+       if (ret != 0 || res != 0) {
+               DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
+                               "failed ret:%d res:%d\n",
+                               ret, res));
+               return -1;
+       }
+
+       len = offsetof(struct ctdb_control_public_ip_info, ifaces);
+       if (len > outdata.dsize) {
+               DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
+                               "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;
+       }
+
+       info = (struct ctdb_control_public_ip_info *)outdata.dptr;
+       len += info->num*sizeof(struct ctdb_control_iface_info);
+
+       if (len > outdata.dsize) {
+               DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
+                               "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 < info->num; i++) {
+               info->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
+       }
+
+       *_info = (struct ctdb_control_public_ip_info *)talloc_memdup(mem_ctx,
+                                                               outdata.dptr,
+                                                               outdata.dsize);
+       talloc_free(outdata.dptr);
+       if (*_info == NULL) {
+               DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
+                               "talloc_memdup size %u failed\n",
+                               (unsigned int)outdata.dsize));
+               return -1;
+       }
+
+       return 0;
+}
+
+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)
+{
+       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,
+                            struct timeval timeout, uint32_t destnode,
+                            TALLOC_CTX *mem_ctx,
+                            const struct ctdb_control_iface_info *info)
+{
+       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;
+}
+
 /*
   set/clear the permanent disabled bit on a remote node
  */
@@ -2710,6 +2909,8 @@ struct ctdb_context *ctdb_init(struct event_context *ev)
        }
        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);
@@ -2719,6 +2920,8 @@ struct ctdb_context *ctdb_init(struct event_context *ev)
                return NULL;
        }
 
+       ctdb->statistics.statistics_start_time = timeval_current();
+
        return ctdb;
 }
 
@@ -2742,6 +2945,11 @@ int ctdb_set_socketname(struct ctdb_context *ctdb, const char *socketname)
        return 0;
 }
 
+const char *ctdb_get_socketname(struct ctdb_context *ctdb)
+{
+       return ctdb->daemon.name;
+}
+
 /*
   return the pnn of this node
 */
@@ -3612,9 +3820,15 @@ int ctdb_ctrl_recd_ping(struct ctdb_context *ctdb)
  * 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) {
@@ -3624,15 +3838,11 @@ int switch_from_server_to_client(struct ctdb_context *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) {
@@ -3999,3 +4209,23 @@ int ctdb_ctrl_get_db_priority(struct ctdb_context *ctdb, struct timeval timeout,
 
        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;
+}