tools/ctdb: Pass memory context for returning nodes in parse_nodestring
[ctdb.git] / libctdb / control.c
index 48add207c7da7eeceaa0d527a82cf049e9dc577c..447a1d1275c15ba5f719666178c14c776a98b17d 100644 (file)
@@ -16,6 +16,8 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
+#include <sys/time.h>
+#include <sys/socket.h>
 #include <string.h>
 #include <ctdb.h>
 #include <ctdb_protocol.h>
 #undef ctdb_getrecmaster_send
 #undef ctdb_getrecmode_send
 #undef ctdb_getpnn_send
+#undef ctdb_getdbstat_send
+#undef ctdb_check_message_handlers_send
 #undef ctdb_getnodemap_send
 #undef ctdb_getpublicips_send
+#undef ctdb_getdbseqnum_send
+#undef ctdb_getifaces_send
+#undef ctdb_getvnnmap_send
+#undef ctdb_getcapabilities_send
 
 bool ctdb_getrecmaster_recv(struct ctdb_connection *ctdb,
                           struct ctdb_request *req, uint32_t *recmaster)
@@ -41,6 +49,7 @@ bool ctdb_getrecmaster_recv(struct ctdb_connection *ctdb,
                DEBUG(ctdb, LOG_ERR, "ctdb_getrecmaster_recv: status -1");
                return false;
        }
+       /* Note: data is stashed in status - see ctdb_control_dispatch() */
        *recmaster = reply->status;
        return true;
 }
@@ -68,6 +77,7 @@ bool ctdb_getrecmode_recv(struct ctdb_connection *ctdb,
                DEBUG(ctdb, LOG_ERR, "ctdb_getrecmode_recv: status -1");
                return false;
        }
+       /* Note: data is stashed in status - see ctdb_control_dispatch() */
        *recmode = reply->status;
        return true;
 }
@@ -95,6 +105,7 @@ bool ctdb_getpnn_recv(struct ctdb_connection *ctdb,
                DEBUG(ctdb, LOG_ERR, "ctdb_getpnn_recv: status -1");
                return false;
        }
+       /* Note: data is stashed in status - see ctdb_control_dispatch() */
        *pnn = reply->status;
        return true;
 }
@@ -108,6 +119,77 @@ struct ctdb_request *ctdb_getpnn_send(struct ctdb_connection *ctdb,
                                        NULL, 0, callback, private_data);
 }
 
+bool ctdb_getdbstat_recv(struct ctdb_connection *ctdb,
+                        struct ctdb_request *req,
+                        struct ctdb_db_statistics **stat)
+{
+       struct ctdb_reply_control *reply;
+       struct ctdb_db_statistics *s, *wire;
+       int i;
+       char *ptr;
+
+       reply = unpack_reply_control(req, CTDB_CONTROL_GET_DB_STATISTICS);
+       if (!reply) {
+               return false;
+       }
+       if (reply->status == -1) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getpnn_recv: status -1");
+               return false;
+       }
+       if (reply->datalen < offsetof(struct ctdb_db_statistics, hot_keys_wire)) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getdbstat_recv: returned data is %d bytes but should be >= %d", reply->datalen, (int)sizeof(struct ctdb_db_statistics));
+               return false;
+       }
+
+       wire = (struct ctdb_db_statistics *)reply->data;
+
+       s = malloc(sizeof(struct ctdb_db_statistics));
+       if (!s) {
+               return false;
+       }
+
+       *s = *wire;
+       ptr = &wire->hot_keys_wire[0];
+       for (i = 0; i < wire->num_hot_keys; i++) {
+               s->hot_keys[i].key.dptr = malloc(s->hot_keys[i].key.dsize);
+               memcpy(s->hot_keys[i].key.dptr, ptr, s->hot_keys[i].key.dsize);
+               ptr += s->hot_keys[i].key.dsize;
+       }
+
+       *stat = s;
+
+       return true;
+}
+
+struct ctdb_request *ctdb_getdbstat_send(struct ctdb_connection *ctdb,
+                                     uint32_t destnode,
+                                     uint32_t db_id,
+                                     ctdb_callback_t callback,
+                                     void *private_data)
+{
+       uint32_t indata = db_id;
+
+       return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_DB_STATISTICS, destnode,
+                                       &indata, sizeof(indata), callback, private_data);
+}
+
+void ctdb_free_dbstat(struct ctdb_db_statistics *stat)
+{
+       int i;
+
+       if (stat == NULL) {
+               return;
+       }
+
+       for (i = 0; i < stat->num_hot_keys; i++) {
+               if (stat->hot_keys[i].key.dptr != NULL) {
+                       free(stat->hot_keys[i].key.dptr);
+               }
+       }
+
+       free(stat);
+}
+
 bool ctdb_getnodemap_recv(struct ctdb_connection *ctdb,
                      struct ctdb_request *req, struct ctdb_node_map **nodemap)
 {
@@ -200,3 +282,257 @@ void ctdb_free_publicips(struct ctdb_all_public_ips *ips)
        }
        free(ips);
 }
+
+bool ctdb_getdbseqnum_recv(struct ctdb_connection *ctdb,
+                          struct ctdb_request *req, uint64_t *seqnum)
+{
+       struct ctdb_reply_control *reply;
+
+       reply = unpack_reply_control(req, CTDB_CONTROL_GET_DB_SEQNUM);
+       if (!reply) {
+               return false;
+       }
+       if (reply->status == -1) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getdbseqnum_recv: status -1");
+               return false;
+       }
+
+       if (reply->datalen != sizeof(uint64_t)) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getdbseqnum wrong size of data was %d but expected %d bytes", reply->datalen, (int)sizeof(uint64_t));
+               return false;
+       }
+
+       *seqnum = *((uint64_t *)reply->data);
+
+       return true;
+}
+
+struct ctdb_request *ctdb_getdbseqnum_send(struct ctdb_connection *ctdb,
+                                           uint32_t destnode,
+                                           uint32_t dbid,
+                                           ctdb_callback_t callback,
+                                           void *private_data)
+{
+       uint64_t indata;
+
+       *((uint32_t *)&indata) = dbid;
+
+       return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_DB_SEQNUM,
+                                       destnode, &indata, sizeof(uint64_t),
+                                       callback, private_data);
+}
+
+bool ctdb_check_message_handlers_recv(struct ctdb_connection *ctdb,
+                                     struct ctdb_request *req,
+                                     uint32_t num, uint8_t *result)
+{
+       struct ctdb_reply_control *reply;
+       int i, count;
+
+       reply = unpack_reply_control(req, CTDB_CONTROL_CHECK_SRVIDS);
+       if (!reply) {
+               return false;
+       }
+       if (reply->status == -1) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_check_message_handlers_recv: status -1");
+               return false;
+       }
+       
+       count = (num + 7) / 8;
+       if (count != reply->datalen) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_check_message_handlers_recv: wrong amount of data returned, expected %d bytes for %d srvids but received %d bytes", count, num, reply->datalen);
+               return false;
+       }
+
+       for (i = 0; i < num; i++) {
+               result[i] = !!(reply->data[i / 8] & (1 << (i % 8)));
+       }
+
+       return true;
+}
+
+struct ctdb_request *
+ctdb_check_message_handlers_send(struct ctdb_connection *ctdb,
+                               uint32_t destnode,
+                               uint32_t num,
+                               uint64_t *mhs,
+                               ctdb_callback_t callback,
+                               void *private_data)
+{
+       return new_ctdb_control_request(ctdb, CTDB_CONTROL_CHECK_SRVIDS,
+                                       destnode,
+                                       mhs, num * sizeof(uint64_t) ,
+                                       callback, private_data);
+}
+
+
+bool ctdb_getifaces_recv(struct ctdb_connection *ctdb,
+                        struct ctdb_request *req,
+                        struct ctdb_ifaces_list **ifaces)
+{
+       struct ctdb_reply_control *reply;
+       struct ctdb_ifaces_list *ifc;
+       int i, len;
+
+       *ifaces = NULL;
+       reply = unpack_reply_control(req, CTDB_CONTROL_GET_IFACES);
+       if (!reply) {
+               return false;
+       }
+       if (reply->status == -1) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: status -1");
+               return false;
+       }
+       if (reply->datalen == 0) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: returned data is 0 bytes");
+               return false;
+       }
+
+       len = offsetof(struct ctdb_ifaces_list, ifaces);
+       if (len > reply->datalen) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: returned data is %d bytes but %d is minimum", reply->datalen,  (int)offsetof(struct ctdb_ifaces_list, ifaces));
+               return false;
+       }
+
+       ifc = (struct ctdb_ifaces_list *)(reply->data);
+       len += ifc->num * sizeof(struct ctdb_iface_info);
+
+       if (len != reply->datalen) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: returned data is %d bytes but should be %d", reply->datalen,  len);
+               return false;
+       }
+
+       ifc = malloc(reply->datalen);
+       if (ifc == NULL) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: failed to malloc buffer");
+               return false;
+       }
+       memcpy(ifc, reply->data, reply->datalen);
+
+       /* make sure we null terminate the returned strings */
+       for (i = 0; i < ifc->num; i++) {
+               ifc->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
+       }
+
+       *ifaces = ifc;
+
+       return true;
+}
+
+void ctdb_free_ifaces(struct ctdb_ifaces_list *ifaces)
+{
+       free(ifaces);
+}
+
+struct ctdb_request *ctdb_getifaces_send(struct ctdb_connection *ctdb,
+                                         uint32_t destnode,
+                                         ctdb_callback_t callback,
+                                         void *private_data)
+{
+       return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_IFACES,
+                                       destnode,
+                                       NULL, 0, callback, private_data);
+}
+
+bool ctdb_getvnnmap_recv(struct ctdb_connection *ctdb,
+                        struct ctdb_request *req,
+                        struct ctdb_vnn_map **vnnmap)
+{
+       struct ctdb_reply_control *reply;
+       struct ctdb_vnn_map_wire *map;
+       struct ctdb_vnn_map *tmap;
+       int len;
+
+       *vnnmap = NULL;
+       reply = unpack_reply_control(req, CTDB_CONTROL_GETVNNMAP);
+       if (!reply) {
+               return false;
+       }
+       if (reply->status == -1) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: status -1");
+               return false;
+       }
+       if (reply->datalen == 0) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: returned data is 0 bytes");
+               return false;
+       }
+
+       len = offsetof(struct ctdb_vnn_map_wire, map);
+       if (len > reply->datalen) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: returned data is %d bytes but %d is minimum", reply->datalen,  (int)offsetof(struct ctdb_vnn_map_wire, map));
+               return false;
+       }
+
+       map = (struct ctdb_vnn_map_wire *)(reply->data);
+       len += map->size * sizeof(uint32_t);
+
+       if (len != reply->datalen) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: returned data is %d bytes but should be %d", reply->datalen,  len);
+               return false;
+       }
+
+       tmap = malloc(sizeof(struct ctdb_vnn_map));
+       if (tmap == NULL) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: failed to malloc buffer");
+               return false;
+       }
+
+       tmap->generation = map->generation;
+       tmap->size       = map->size;
+       tmap->map        = malloc(sizeof(uint32_t) * map->size);
+       if (tmap->map == NULL) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: failed to malloc buffer");
+               free(tmap);
+               return false;
+       }
+
+       memcpy(tmap->map, map->map, sizeof(uint32_t)*map->size);
+
+       *vnnmap = tmap;
+
+       return true;
+}
+
+void ctdb_free_vnnmap(struct ctdb_vnn_map *vnnmap)
+{
+       free(vnnmap->map);
+       free(vnnmap);
+}
+
+struct ctdb_request *ctdb_getvnnmap_send(struct ctdb_connection *ctdb,
+                                        uint32_t destnode,
+                                        ctdb_callback_t callback,
+                                        void *private_data)
+{
+       return new_ctdb_control_request(ctdb, CTDB_CONTROL_GETVNNMAP,
+                                       destnode,
+                                       NULL, 0, callback, private_data);
+}
+
+bool ctdb_getcapabilities_recv(struct ctdb_connection *ctdb,
+                              struct ctdb_request *req, uint32_t *capabilities)
+{
+       struct ctdb_reply_control *reply;
+
+       reply = unpack_reply_control(req, CTDB_CONTROL_GET_CAPABILITIES);
+       if (!reply) {
+               return false;
+       }
+       if (reply->status == -1) {
+               DEBUG(ctdb, LOG_ERR, "ctdb_getcapabilities_recv: status -1");
+               return false;
+       }
+       *capabilities = *((uint32_t *)reply->data);
+       return true;
+}
+
+struct ctdb_request *ctdb_getcapabilities_send(struct ctdb_connection *ctdb,
+                                              uint32_t destnode,
+                                              ctdb_callback_t callback,
+                                              void *private_data)
+{
+       return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_CAPABILITIES,
+                                       destnode,
+                                       NULL, 0, callback, private_data);
+}
+