4 Copyright (C) Andrew Tridgell 2007
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 2 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "lib/events/events.h"
23 #include "system/filesys.h"
26 #include "../include/ctdb.h"
27 #include "../include/ctdb_private.h"
28 #include <arpa/inet.h>
30 static void usage(void);
38 #define TIMELIMIT() timeval_current_ofs(options.timelimit, 0)
41 see if a process exists
43 static int control_process_exists(struct ctdb_context *ctdb, int argc, const char **argv)
51 if (sscanf(argv[0], "%u:%u", &vnn, &pid) != 2) {
52 printf("Badly formed vnn:pid\n");
56 ret = ctdb_ctrl_process_exists(ctdb, vnn, pid);
58 printf("%u:%u exists\n", vnn, pid);
60 printf("%u:%u does not exist\n", vnn, pid);
66 display statistics structure
68 static void show_statistics(struct ctdb_statistics *s)
70 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
72 const char *prefix=NULL;
78 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
79 STATISTICS_FIELD(num_clients),
80 STATISTICS_FIELD(frozen),
81 STATISTICS_FIELD(recovering),
82 STATISTICS_FIELD(client_packets_sent),
83 STATISTICS_FIELD(client_packets_recv),
84 STATISTICS_FIELD(node_packets_sent),
85 STATISTICS_FIELD(node_packets_recv),
86 STATISTICS_FIELD(keepalive_packets_sent),
87 STATISTICS_FIELD(keepalive_packets_recv),
88 STATISTICS_FIELD(node.req_call),
89 STATISTICS_FIELD(node.reply_call),
90 STATISTICS_FIELD(node.req_dmaster),
91 STATISTICS_FIELD(node.reply_dmaster),
92 STATISTICS_FIELD(node.reply_error),
93 STATISTICS_FIELD(node.req_message),
94 STATISTICS_FIELD(node.req_control),
95 STATISTICS_FIELD(node.reply_control),
96 STATISTICS_FIELD(client.req_call),
97 STATISTICS_FIELD(client.req_message),
98 STATISTICS_FIELD(client.req_control),
99 STATISTICS_FIELD(controls.statistics),
100 STATISTICS_FIELD(controls.get_config),
101 STATISTICS_FIELD(controls.ping),
102 STATISTICS_FIELD(controls.attach),
103 STATISTICS_FIELD(controls.set_call),
104 STATISTICS_FIELD(controls.process_exists),
105 STATISTICS_FIELD(controls.traverse_start),
106 STATISTICS_FIELD(controls.traverse_all),
107 STATISTICS_FIELD(controls.traverse_data),
108 STATISTICS_FIELD(controls.update_seqnum),
109 STATISTICS_FIELD(controls.enable_seqnum),
110 STATISTICS_FIELD(controls.set_seqnum_frequency),
111 STATISTICS_FIELD(controls.register_srvid),
112 STATISTICS_FIELD(controls.deregister_srvid),
113 STATISTICS_FIELD(timeouts.call),
114 STATISTICS_FIELD(timeouts.control),
115 STATISTICS_FIELD(timeouts.traverse),
116 STATISTICS_FIELD(total_calls),
117 STATISTICS_FIELD(pending_calls),
118 STATISTICS_FIELD(lockwait_calls),
119 STATISTICS_FIELD(pending_lockwait_calls),
120 STATISTICS_FIELD(memory_used),
121 STATISTICS_FIELD(max_hop_count),
123 printf("CTDB version %u\n", CTDB_VERSION);
124 for (i=0;i<ARRAY_SIZE(fields);i++) {
125 if (strchr(fields[i].name, '.')) {
126 preflen = strcspn(fields[i].name, ".")+1;
127 if (!prefix || strncmp(prefix, fields[i].name, preflen) != 0) {
128 prefix = fields[i].name;
129 printf(" %*.*s\n", preflen-1, preflen-1, fields[i].name);
134 printf(" %*s%-22s%*s%10u\n",
136 fields[i].name+preflen,
138 *(uint32_t *)(fields[i].offset+(uint8_t *)s));
140 printf(" %-30s %.6f sec\n", "max_call_latency", s->max_call_latency);
141 printf(" %-30s %.6f sec\n", "max_lockwait_latency", s->max_lockwait_latency);
142 talloc_free(tmp_ctx);
146 display remote ctdb statistics combined from all nodes
148 static int control_statistics_all(struct ctdb_context *ctdb)
151 struct ctdb_statistics statistics;
155 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
156 CTDB_NO_MEMORY(ctdb, nodes);
158 ZERO_STRUCT(statistics);
160 for (i=0;i<num_nodes;i++) {
161 struct ctdb_statistics s1;
163 uint32_t *v1 = (uint32_t *)&s1;
164 uint32_t *v2 = (uint32_t *)&statistics;
166 offsetof(struct ctdb_statistics, __last_counter) / sizeof(uint32_t);
167 ret = ctdb_ctrl_statistics(ctdb, nodes[i], &s1);
169 printf("Unable to get statistics from node %u\n", nodes[i]);
172 for (j=0;j<num_ints;j++) {
175 statistics.max_hop_count =
176 MAX(statistics.max_hop_count, s1.max_hop_count);
177 statistics.max_call_latency =
178 MAX(statistics.max_call_latency, s1.max_call_latency);
179 statistics.max_lockwait_latency =
180 MAX(statistics.max_lockwait_latency, s1.max_lockwait_latency);
183 printf("Gathered statistics for %u nodes\n", num_nodes);
184 show_statistics(&statistics);
189 display remote ctdb statistics
191 static int control_statistics(struct ctdb_context *ctdb, int argc, const char **argv)
194 struct ctdb_statistics statistics;
196 if (options.vnn == CTDB_BROADCAST_ALL) {
197 return control_statistics_all(ctdb);
200 ret = ctdb_ctrl_statistics(ctdb, options.vnn, &statistics);
202 printf("Unable to get statistics from node %u\n", options.vnn);
205 show_statistics(&statistics);
211 reset statistics on all nodes
213 static int control_statistics_reset_all(struct ctdb_context *ctdb)
219 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
220 CTDB_NO_MEMORY(ctdb, nodes);
222 for (i=0;i<num_nodes;i++) {
223 ret = ctdb_statistics_reset(ctdb, nodes[i]);
225 printf("Unable to reset statistics on node %u\n", nodes[i]);
235 reset remote ctdb statistics
237 static int control_statistics_reset(struct ctdb_context *ctdb, int argc, const char **argv)
241 if (options.vnn == CTDB_BROADCAST_ALL) {
242 return control_statistics_reset_all(ctdb);
245 ret = ctdb_statistics_reset(ctdb, options.vnn);
247 printf("Unable to reset statistics on node %u\n", options.vnn);
255 display remote ctdb status
257 static int control_status(struct ctdb_context *ctdb, int argc, const char **argv)
260 struct ctdb_vnn_map *vnnmap=NULL;
261 struct ctdb_node_map *nodemap=NULL;
262 uint32_t recmode, recmaster;
265 if (options.vnn == CTDB_BROADCAST_ALL) {
270 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
271 CTDB_NO_MEMORY(ctdb, nodes);
273 for (i=0;i<num_nodes;i++) {
274 options.vnn = nodes[i];
275 ret |= control_status(ctdb, argc, argv);
280 myvnn = ctdb_ctrl_getvnn(ctdb, TIMELIMIT(), options.vnn);
282 ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.vnn, ctdb, &nodemap);
284 printf("Unable to get nodemap from node %u\n", options.vnn);
288 if(options.machinereadable){
289 printf(":Node:Status:\n");
290 for(i=0;i<nodemap->num;i++){
291 printf(":%d:%s:%d:\n", nodemap->nodes[i].vnn,
292 inet_ntoa(nodemap->nodes[i].sin.sin_addr),
293 !!nodemap->nodes[i].flags&NODE_FLAGS_CONNECTED);
298 printf("Number of nodes:%d\n", nodemap->num);
299 for(i=0;i<nodemap->num;i++){
300 printf("vnn:%d %-16s %s%s\n", nodemap->nodes[i].vnn,
301 inet_ntoa(nodemap->nodes[i].sin.sin_addr),
302 nodemap->nodes[i].flags&NODE_FLAGS_CONNECTED?
303 "CONNECTED":"UNAVAILABLE",
304 nodemap->nodes[i].vnn == myvnn?" (THIS NODE)":"");
307 ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.vnn, ctdb, &vnnmap);
309 printf("Unable to get vnnmap from node %u\n", options.vnn);
312 printf("Generation:%d\n",vnnmap->generation);
313 printf("Size:%d\n",vnnmap->size);
314 for(i=0;i<vnnmap->size;i++){
315 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
318 ret = ctdb_ctrl_getrecmode(ctdb, TIMELIMIT(), options.vnn, &recmode);
320 printf("Unable to get recmode from node %u\n", options.vnn);
323 printf("Recovery mode:%s (%d)\n",recmode==CTDB_RECOVERY_NORMAL?"NORMAL":"RECOVERY",recmode);
325 ret = ctdb_ctrl_getrecmaster(ctdb, TIMELIMIT(), options.vnn, &recmaster);
327 printf("Unable to get recmaster from node %u\n", options.vnn);
330 printf("Recovery master:%d\n",recmaster);
336 display pid of a ctdb daemon
338 static int control_getpid(struct ctdb_context *ctdb, int argc, const char **argv)
343 ret = ctdb_ctrl_getpid(ctdb, TIMELIMIT(), options.vnn, &pid);
345 printf("Unable to get daemon pid from node %u\n", options.vnn);
348 printf("Pid:%d\n", pid);
356 static int control_shutdown(struct ctdb_context *ctdb, int argc, const char **argv)
360 ret = ctdb_ctrl_shutdown(ctdb, timeval_current_ofs(1, 0), options.vnn);
362 printf("Unable to shutdown node %u\n", options.vnn);
372 static int control_recover(struct ctdb_context *ctdb, int argc, const char **argv)
376 ret = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), options.vnn);
378 printf("Unable to freeze node\n");
382 ret = ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.vnn, CTDB_RECOVERY_ACTIVE);
384 printf("Unable to set recovery mode\n");
393 display monitoring mode of a remote node
395 static int control_getmonmode(struct ctdb_context *ctdb, int argc, const char **argv)
400 ret = ctdb_ctrl_getmonmode(ctdb, TIMELIMIT(), options.vnn, &monmode);
402 printf("Unable to get monmode from node %u\n", options.vnn);
405 printf("Monitoring mode:%s (%d)\n",monmode==CTDB_MONITORING_ACTIVE?"ACTIVE":"DISABLED",monmode);
411 set the monitoring mode of a remote node
413 static int control_setmonmode(struct ctdb_context *ctdb, int argc, const char **argv)
422 monmode = strtoul(argv[0], NULL, 0);
424 ret = ctdb_ctrl_setmonmode(ctdb, TIMELIMIT(), options.vnn, monmode);
426 printf("Unable to set monmode on node %u\n", options.vnn);
434 display remote list of keys/data for a db
436 static int control_catdb(struct ctdb_context *ctdb, int argc, const char **argv)
439 struct ctdb_db_context *ctdb_db;
447 ctdb_db = ctdb_attach(ctdb, db_name);
449 if (ctdb_db == NULL) {
450 DEBUG(0,("Unable to attach to database '%s'\n", db_name));
454 /* traverse and dump the cluster tdb */
455 ret = ctdb_dump_db(ctdb_db, stdout);
457 printf("Unable to dump database\n");
460 talloc_free(ctdb_db);
462 printf("Dumped %d records\n", ret);
468 display a list of the databases on a remote ctdb
470 static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **argv)
473 struct ctdb_dbid_map *dbmap=NULL;
475 ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.vnn, ctdb, &dbmap);
477 printf("Unable to get dbids from node %u\n", options.vnn);
481 printf("Number of databases:%d\n", dbmap->num);
482 for(i=0;i<dbmap->num;i++){
486 ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.vnn, dbmap->dbids[i], ctdb, &path);
487 ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.vnn, dbmap->dbids[i], ctdb, &name);
488 printf("dbid:0x%08x name:%s path:%s\n", dbmap->dbids[i], name, path);
497 static int control_ping(struct ctdb_context *ctdb, int argc, const char **argv)
503 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
504 CTDB_NO_MEMORY(ctdb, nodes);
506 for (i=0;i<num_nodes;i++) {
507 struct timeval tv = timeval_current();
508 ret = ctdb_ctrl_ping(ctdb, nodes[i]);
510 printf("Unable to get ping response from node %u\n", nodes[i]);
512 printf("response from %u time=%.6f sec (%d clients)\n",
513 nodes[i], timeval_elapsed(&tv), ret);
522 display debug level on a node
524 static int control_getdebug(struct ctdb_context *ctdb, int argc, const char **argv)
531 if (options.vnn != CTDB_BROADCAST_ALL) {
532 ret = ctdb_ctrl_get_debuglevel(ctdb, options.vnn, &level);
534 printf("Unable to get debuglevel response from node %u\n",
537 printf("Node %u is at debug level %u\n", options.vnn, level);
542 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
543 CTDB_NO_MEMORY(ctdb, nodes);
545 for (i=0;i<num_nodes;i++) {
546 ret = ctdb_ctrl_get_debuglevel(ctdb, nodes[i], &level);
548 printf("Unable to get debuglevel response from node %u\n",
551 printf("Node %u is at debug level %u\n", nodes[i], level);
560 set debug level on a node or all nodes
562 static int control_setdebug(struct ctdb_context *ctdb, int argc, const char **argv)
573 level = strtoul(argv[0], NULL, 0);
575 if (options.vnn != CTDB_BROADCAST_ALL) {
576 ret = ctdb_ctrl_set_debuglevel(ctdb, options.vnn, level);
578 printf("Unable to set debug level on node %u\n", options.vnn);
583 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
584 CTDB_NO_MEMORY(ctdb, nodes);
585 for (i=0;i<num_nodes;i++) {
586 ret = ctdb_ctrl_set_debuglevel(ctdb, nodes[i], level);
588 printf("Unable to set debug level on node %u\n", nodes[i]);
600 static int control_freeze(struct ctdb_context *ctdb, int argc, const char **argv)
607 if (options.vnn != CTDB_BROADCAST_ALL) {
608 ret = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), options.vnn);
610 printf("Unable to freeze node %u\n", options.vnn);
615 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
616 CTDB_NO_MEMORY(ctdb, nodes);
617 for (i=0;i<num_nodes;i++) {
618 int res = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), nodes[i]);
620 printf("Warning: Unable to freeze node %u\n", nodes[i]);
626 printf("Froze %u nodes\n", count);
634 static int control_thaw(struct ctdb_context *ctdb, int argc, const char **argv)
641 if (options.vnn != CTDB_BROADCAST_ALL) {
642 ret = ctdb_ctrl_thaw(ctdb, TIMELIMIT(), options.vnn);
644 printf("Unable to thaw node %u\n", options.vnn);
649 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
650 CTDB_NO_MEMORY(ctdb, nodes);
651 for (i=0;i<num_nodes;i++) {
652 int res = ctdb_ctrl_thaw(ctdb, TIMELIMIT(), nodes[i]);
654 printf("Warning: Unable to thaw node %u\n", nodes[i]);
660 printf("Thawed %u nodes\n", count);
669 static int control_attach(struct ctdb_context *ctdb, int argc, const char **argv)
672 struct ctdb_db_context *ctdb_db;
679 ctdb_db = ctdb_attach(ctdb, db_name);
680 if (ctdb_db == NULL) {
681 DEBUG(0,("Unable to attach to database '%s'\n", db_name));
691 static int control_dumpmemory(struct ctdb_context *ctdb, int argc, const char **argv)
693 return ctdb_control(ctdb, options.vnn, 0, CTDB_CONTROL_DUMP_MEMORY,
694 CTDB_CTRL_FLAG_NOREPLY, tdb_null, NULL, NULL, NULL, NULL, NULL);
698 static const struct {
700 int (*fn)(struct ctdb_context *, int, const char **);
703 } ctdb_commands[] = {
704 { "status", control_status, "show node status" },
705 { "ping", control_ping, "ping all nodes" },
706 { "statistics", control_statistics, "show statistics" },
707 { "statisticsreset", control_statistics_reset, "reset statistics"},
708 { "process-exists", control_process_exists, "check if a process exists on a node", "<pid>"},
709 { "getdbmap", control_getdbmap, "show the database map" },
710 { "catdb", control_catdb, "dump a database" , "<dbname>"},
711 { "getmonmode", control_getmonmode, "show monitoring mode" },
712 { "setmonmode", control_setmonmode, "set monitoring mode" },
713 { "setdebug", control_setdebug, "set debug level", "<debuglevel>" },
714 { "getdebug", control_getdebug, "get debug level" },
715 { "attach", control_attach, "attach to a database", "<dbname>" },
716 { "dumpmemory", control_dumpmemory, "dump memory map to logs" },
717 { "getpid", control_getpid, "get ctdbd process ID" },
718 { "shutdown", control_shutdown, "shutdown ctdbd" },
719 { "recover", control_recover, "force recovery" },
720 { "freeze", control_freeze, "freeze all databases" },
721 { "thaw", control_thaw, "thaw all databases" },
727 static void usage(void)
731 "Usage: ctdb [options] <control>\n" \
733 " -n <node> choose node number, or 'all' (defaults to local node)\n"
734 " -Y generate machinereadable output\n"
735 " -t <timelimit> set timelimit for control in seconds (default %u)\n", options.timelimit);
736 printf("Controls:\n");
737 for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
738 printf(" %-15s %-20s %s\n",
739 ctdb_commands[i].name,
740 ctdb_commands[i].args?ctdb_commands[i].args:"",
741 ctdb_commands[i].msg);
750 int main(int argc, const char *argv[])
752 struct ctdb_context *ctdb;
753 char *nodestring = NULL;
754 struct poptOption popt_options[] = {
757 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0, "timelimit", "integer" },
758 { "node", 'n', POPT_ARG_STRING, &nodestring, 0, "node", "integer|all" },
759 { "machinereadable", 'Y', POPT_ARG_NONE, &options.machinereadable, 0, "enable machinereadable output", NULL },
763 const char **extra_argv;
767 struct event_context *ev;
770 /* set some defaults */
771 options.timelimit = 3;
772 options.vnn = CTDB_CURRENT_NODE;
774 pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
776 while ((opt = poptGetNextOpt(pc)) != -1) {
779 fprintf(stderr, "Invalid option %s: %s\n",
780 poptBadOption(pc, 0), poptStrerror(opt));
785 /* setup the remaining options for the main program to use */
786 extra_argv = poptGetArgs(pc);
789 while (extra_argv[extra_argc]) extra_argc++;
792 if (extra_argc < 1) {
796 /* setup the node number to contact */
797 if (nodestring != NULL) {
798 if (strcmp(nodestring, "all") == 0) {
799 options.vnn = CTDB_BROADCAST_ALL;
801 options.vnn = strtoul(nodestring, NULL, 0);
805 control = extra_argv[0];
807 ev = event_context_init(NULL);
809 /* initialise ctdb */
810 ctdb = ctdb_cmdline_client(ev);
812 printf("Failed to init ctdb\n");
816 for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
817 if (strcmp(control, ctdb_commands[i].name) == 0) {
818 ret = ctdb_commands[i].fn(ctdb, extra_argc-1, extra_argv+1);
823 if (i == ARRAY_SIZE(ctdb_commands)) {
824 printf("Unknown control '%s'\n", control);