STATISTICS: Add tracking of the 10 hottest keys per database measured in hopcount
[ctdb.git] / libctdb / control.c
1 /*
2    Misc control routines of libctdb
3
4    Copyright (C) Rusty Russell 2010
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include <sys/socket.h>
20 #include <string.h>
21 #include <ctdb.h>
22 #include <ctdb_protocol.h>
23 #include "libctdb_private.h"
24
25 /* Remove type-safety macros. */
26 #undef ctdb_getrecmaster_send
27 #undef ctdb_getrecmode_send
28 #undef ctdb_getpnn_send
29 #undef ctdb_getdbstat_send
30 #undef ctdb_check_message_handlers_send
31 #undef ctdb_getnodemap_send
32 #undef ctdb_getpublicips_send
33 #undef ctdb_getdbseqnum_send
34 #undef ctdb_getifaces_send
35 #undef ctdb_getvnnmap_send
36
37 bool ctdb_getrecmaster_recv(struct ctdb_connection *ctdb,
38                            struct ctdb_request *req, uint32_t *recmaster)
39 {
40         struct ctdb_reply_control *reply;
41
42         reply = unpack_reply_control(req, CTDB_CONTROL_GET_RECMASTER);
43         if (!reply) {
44                 return false;
45         }
46         if (reply->status == -1) {
47                 DEBUG(ctdb, LOG_ERR, "ctdb_getrecmaster_recv: status -1");
48                 return false;
49         }
50         *recmaster = reply->status;
51         return true;
52 }
53
54 struct ctdb_request *ctdb_getrecmaster_send(struct ctdb_connection *ctdb,
55                                             uint32_t destnode,
56                                             ctdb_callback_t callback,
57                                             void *private_data)
58 {
59         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_RECMASTER,
60                                         destnode, NULL, 0,
61                                         callback, private_data);
62 }
63
64 bool ctdb_getrecmode_recv(struct ctdb_connection *ctdb,
65                           struct ctdb_request *req, uint32_t *recmode)
66 {
67         struct ctdb_reply_control *reply;
68
69         reply = unpack_reply_control(req, CTDB_CONTROL_GET_RECMODE);
70         if (!reply) {
71                 return false;
72         }
73         if (reply->status == -1) {
74                 DEBUG(ctdb, LOG_ERR, "ctdb_getrecmode_recv: status -1");
75                 return false;
76         }
77         *recmode = reply->status;
78         return true;
79 }
80
81 struct ctdb_request *ctdb_getrecmode_send(struct ctdb_connection *ctdb,
82                                             uint32_t destnode,
83                                             ctdb_callback_t callback,
84                                             void *private_data)
85 {
86         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_RECMODE,
87                                         destnode, NULL, 0,
88                                         callback, private_data);
89 }
90
91 bool ctdb_getpnn_recv(struct ctdb_connection *ctdb,
92                      struct ctdb_request *req, uint32_t *pnn)
93 {
94         struct ctdb_reply_control *reply;
95
96         reply = unpack_reply_control(req, CTDB_CONTROL_GET_PNN);
97         if (!reply) {
98                 return false;
99         }
100         if (reply->status == -1) {
101                 DEBUG(ctdb, LOG_ERR, "ctdb_getpnn_recv: status -1");
102                 return false;
103         }
104         *pnn = reply->status;
105         return true;
106 }
107
108 struct ctdb_request *ctdb_getpnn_send(struct ctdb_connection *ctdb,
109                                       uint32_t destnode,
110                                       ctdb_callback_t callback,
111                                       void *private_data)
112 {
113         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_PNN, destnode,
114                                         NULL, 0, callback, private_data);
115 }
116
117 bool ctdb_getdbstat_recv(struct ctdb_connection *ctdb,
118                          struct ctdb_request *req,
119                          struct ctdb_db_statistics **stat)
120 {
121         struct ctdb_reply_control *reply;
122         struct ctdb_db_statistics *s;
123         struct ctdb_db_statistics_wire *wire;
124         int i;
125         char *ptr;
126
127         reply = unpack_reply_control(req, CTDB_CONTROL_GET_DB_STATISTICS);
128         if (!reply) {
129                 return false;
130         }
131         if (reply->status == -1) {
132                 DEBUG(ctdb, LOG_ERR, "ctdb_getpnn_recv: status -1");
133                 return false;
134         }
135         if (reply->datalen < offsetof(struct ctdb_db_statistics_wire, hot_keys)) {
136                 DEBUG(ctdb, LOG_ERR, "ctdb_getdbstat_recv: returned data is %d bytes but should be >= %d", reply->datalen, (int)sizeof(struct ctdb_db_statistics));
137                 return false;
138         }
139
140         wire = reply->data;
141
142         s = malloc(offsetof(struct ctdb_db_statistics, hot_keys) + sizeof(struct ctdb_db_hot_key) * wire->num_hot_keys);
143         if (!s) {
144                 return false;
145         }
146         s->db_ro_delegations = wire->db_ro_delegations;
147         s->db_ro_revokes     = wire->db_ro_revokes;
148         for (i = 0; i < MAX_COUNT_BUCKETS; i++) {
149                 s->hop_count_bucket[i] = wire->hop_count_bucket[i];
150         }
151         s->num_hot_keys      = wire->num_hot_keys;
152         ptr = &wire->hot_keys[0];
153         for (i = 0; i < wire->num_hot_keys; i++) {
154                 s->hot_keys[i].count = *(uint32_t *)ptr;
155                 ptr += 4;
156
157                 s->hot_keys[i].key.dsize = *(uint32_t *)ptr;
158                 ptr += 4;
159
160                 s->hot_keys[i].key.dptr = malloc(s->hot_keys[i].key.dsize);
161                 memcpy(s->hot_keys[i].key.dptr, ptr, s->hot_keys[i].key.dsize);
162                 ptr += s->hot_keys[i].key.dsize;
163         }
164
165         *stat = s;
166
167         return true;
168 }
169
170 struct ctdb_request *ctdb_getdbstat_send(struct ctdb_connection *ctdb,
171                                       uint32_t destnode,
172                                       uint32_t db_id,
173                                       ctdb_callback_t callback,
174                                       void *private_data)
175 {
176         uint32_t indata = db_id;
177
178         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_DB_STATISTICS, destnode,
179                                         &indata, sizeof(indata), callback, private_data);
180 }
181
182 void ctdb_free_dbstat(struct ctdb_db_statistics *stat)
183 {
184         int i;
185
186         if (stat == NULL) {
187                 return;
188         }
189
190         for (i = 0; i < stat->num_hot_keys; i++) {
191                 if (stat->hot_keys[i].key.dptr != NULL) {
192                         free(stat->hot_keys[i].key.dptr);
193                 }
194         }
195
196         free(stat);
197 }
198
199 bool ctdb_getnodemap_recv(struct ctdb_connection *ctdb,
200                       struct ctdb_request *req, struct ctdb_node_map **nodemap)
201 {
202         struct ctdb_reply_control *reply;
203
204         *nodemap = NULL;
205         reply = unpack_reply_control(req, CTDB_CONTROL_GET_NODEMAP);
206         if (!reply) {
207                 return false;
208         }
209         if (reply->status == -1) {
210                 DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: status -1");
211                 return false;
212         }
213         if (reply->datalen == 0) {
214                 DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: returned data is 0 bytes");
215                 return false;
216         }
217
218         *nodemap = malloc(reply->datalen);
219         if (*nodemap == NULL) {
220                 DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: failed to malloc buffer");
221                 return false;
222         }
223         memcpy(*nodemap, reply->data, reply->datalen);
224
225         return true;
226 }
227 struct ctdb_request *ctdb_getnodemap_send(struct ctdb_connection *ctdb,
228                                           uint32_t destnode,
229                                           ctdb_callback_t callback,
230                                           void *private_data)
231 {
232         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_NODEMAP,
233                                         destnode,
234                                         NULL, 0, callback, private_data);
235 }
236
237 void ctdb_free_nodemap(struct ctdb_node_map *nodemap)
238 {
239         if (nodemap == NULL) {
240                 return;
241         }
242         free(nodemap);
243 }
244
245 bool ctdb_getpublicips_recv(struct ctdb_connection *ctdb,
246                             struct ctdb_request *req,
247                             struct ctdb_all_public_ips **ips)
248 {
249         struct ctdb_reply_control *reply;
250
251         *ips = NULL;
252         reply = unpack_reply_control(req, CTDB_CONTROL_GET_PUBLIC_IPS);
253         if (!reply) {
254                 return false;
255         }
256         if (reply->status == -1) {
257                 DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: status -1");
258                 return false;
259         }
260         if (reply->datalen == 0) {
261                 DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: returned data is 0 bytes");
262                 return false;
263         }
264
265         *ips = malloc(reply->datalen);
266         if (*ips == NULL) {
267                 DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: failed to malloc buffer");
268                 return false;
269         }
270         memcpy(*ips, reply->data, reply->datalen);
271
272         return true;
273 }
274 struct ctdb_request *ctdb_getpublicips_send(struct ctdb_connection *ctdb,
275                                             uint32_t destnode,
276                                             ctdb_callback_t callback,
277                                             void *private_data)
278 {
279         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_PUBLIC_IPS,
280                                         destnode,
281                                         NULL, 0, callback, private_data);
282 }
283
284 void ctdb_free_publicips(struct ctdb_all_public_ips *ips)
285 {
286         if (ips == NULL) {
287                 return;
288         }
289         free(ips);
290 }
291
292 bool ctdb_getdbseqnum_recv(struct ctdb_connection *ctdb,
293                            struct ctdb_request *req, uint64_t *seqnum)
294 {
295         struct ctdb_reply_control *reply;
296
297         reply = unpack_reply_control(req, CTDB_CONTROL_GET_DB_SEQNUM);
298         if (!reply) {
299                 return false;
300         }
301         if (reply->status == -1) {
302                 DEBUG(ctdb, LOG_ERR, "ctdb_getdbseqnum_recv: status -1");
303                 return false;
304         }
305
306         if (reply->datalen != sizeof(uint64_t)) {
307                 DEBUG(ctdb, LOG_ERR, "ctdb_getdbseqnum wrong size of data was %d but expected %d bytes", reply->datalen, (int)sizeof(uint64_t));
308                 return false;
309         }
310
311         *seqnum = *((uint64_t *)reply->data);
312
313         return true;
314 }
315
316 struct ctdb_request *ctdb_getdbseqnum_send(struct ctdb_connection *ctdb,
317                                             uint32_t destnode,
318                                             uint32_t dbid,
319                                             ctdb_callback_t callback,
320                                             void *private_data)
321 {
322         uint64_t indata;
323
324         *((uint32_t *)&indata) = dbid;
325
326         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_DB_SEQNUM,
327                                         destnode, &indata, sizeof(uint64_t),
328                                         callback, private_data);
329 }
330
331 bool ctdb_check_message_handlers_recv(struct ctdb_connection *ctdb,
332                                       struct ctdb_request *req,
333                                       uint32_t num, uint8_t *result)
334 {
335         struct ctdb_reply_control *reply;
336         int i, count;
337
338         reply = unpack_reply_control(req, CTDB_CONTROL_CHECK_SRVIDS);
339         if (!reply) {
340                 return false;
341         }
342         if (reply->status == -1) {
343                 DEBUG(ctdb, LOG_ERR, "ctdb_check_message_handlers_recv: status -1");
344                 return false;
345         }
346         
347         count = (num + 7) / 8;
348         if (count != reply->datalen) {
349                 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);
350                 return false;
351         }
352
353         for (i = 0; i < num; i++) {
354                 result[i] = !!(reply->data[i / 8] & (1 << (i % 8)));
355         }
356
357         return true;
358 }
359
360 struct ctdb_request *
361 ctdb_check_message_handlers_send(struct ctdb_connection *ctdb,
362                                 uint32_t destnode,
363                                 uint32_t num,
364                                 uint64_t *mhs,
365                                 ctdb_callback_t callback,
366                                 void *private_data)
367 {
368         return new_ctdb_control_request(ctdb, CTDB_CONTROL_CHECK_SRVIDS,
369                                         destnode,
370                                         mhs, num * sizeof(uint64_t) ,
371                                         callback, private_data);
372 }
373
374
375 bool ctdb_getifaces_recv(struct ctdb_connection *ctdb,
376                          struct ctdb_request *req,
377                          struct ctdb_ifaces_list **ifaces)
378 {
379         struct ctdb_reply_control *reply;
380         struct ctdb_ifaces_list *ifc;
381         int i, len;
382
383         *ifaces = NULL;
384         reply = unpack_reply_control(req, CTDB_CONTROL_GET_IFACES);
385         if (!reply) {
386                 return false;
387         }
388         if (reply->status == -1) {
389                 DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: status -1");
390                 return false;
391         }
392         if (reply->datalen == 0) {
393                 DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: returned data is 0 bytes");
394                 return false;
395         }
396
397         len = offsetof(struct ctdb_ifaces_list, ifaces);
398         if (len > reply->datalen) {
399                 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));
400                 return false;
401         }
402
403         ifc = (struct ctdb_ifaces_list *)(reply->data);
404         len += ifc->num * sizeof(struct ctdb_iface_info);
405
406         if (len != reply->datalen) {
407                 DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: returned data is %d bytes but should be %d", reply->datalen,  len);
408                 return false;
409         }
410
411         ifc = malloc(reply->datalen);
412         if (ifc == NULL) {
413                 DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: failed to malloc buffer");
414                 return false;
415         }
416         memcpy(ifc, reply->data, reply->datalen);
417
418         /* make sure we null terminate the returned strings */
419         for (i = 0; i < ifc->num; i++) {
420                 ifc->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
421         }
422
423         *ifaces = ifc;
424
425         return true;
426 }
427
428 void ctdb_free_ifaces(struct ctdb_ifaces_list *ifaces)
429 {
430         free(ifaces);
431 }
432
433 struct ctdb_request *ctdb_getifaces_send(struct ctdb_connection *ctdb,
434                                           uint32_t destnode,
435                                           ctdb_callback_t callback,
436                                           void *private_data)
437 {
438         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_IFACES,
439                                         destnode,
440                                         NULL, 0, callback, private_data);
441 }
442
443 bool ctdb_getvnnmap_recv(struct ctdb_connection *ctdb,
444                          struct ctdb_request *req,
445                          struct ctdb_vnn_map **vnnmap)
446 {
447         struct ctdb_reply_control *reply;
448         struct ctdb_vnn_map_wire *map;
449         struct ctdb_vnn_map *tmap;
450         int len;
451
452         *vnnmap = NULL;
453         reply = unpack_reply_control(req, CTDB_CONTROL_GETVNNMAP);
454         if (!reply) {
455                 return false;
456         }
457         if (reply->status == -1) {
458                 DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: status -1");
459                 return false;
460         }
461         if (reply->datalen == 0) {
462                 DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: returned data is 0 bytes");
463                 return false;
464         }
465
466         len = offsetof(struct ctdb_vnn_map_wire, map);
467         if (len > reply->datalen) {
468                 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));
469                 return false;
470         }
471
472         map = (struct ctdb_vnn_map_wire *)(reply->data);
473         len += map->size * sizeof(uint32_t);
474
475         if (len != reply->datalen) {
476                 DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: returned data is %d bytes but should be %d", reply->datalen,  len);
477                 return false;
478         }
479
480         tmap = malloc(sizeof(struct ctdb_vnn_map));
481         if (tmap == NULL) {
482                 DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: failed to malloc buffer");
483                 return false;
484         }
485
486         tmap->generation = map->generation;
487         tmap->size       = map->size;
488         tmap->map        = malloc(sizeof(uint32_t) * map->size);
489         if (tmap->map == NULL) {
490                 DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: failed to malloc buffer");
491                 free(tmap);
492                 return false;
493         }
494
495         memcpy(tmap->map, map->map, sizeof(uint32_t)*map->size);
496
497         *vnnmap = tmap;
498
499         return true;
500 }
501
502 void ctdb_free_vnnmap(struct ctdb_vnn_map *vnnmap)
503 {
504         free(vnnmap->map);
505         free(vnnmap);
506 }
507
508 struct ctdb_request *ctdb_getvnnmap_send(struct ctdb_connection *ctdb,
509                                          uint32_t destnode,
510                                          ctdb_callback_t callback,
511                                          void *private_data)
512 {
513         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GETVNNMAP,
514                                         destnode,
515                                         NULL, 0, callback, private_data);
516 }
517