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.register_srvid),
111 STATISTICS_FIELD(controls.deregister_srvid),
112 STATISTICS_FIELD(timeouts.call),
113 STATISTICS_FIELD(timeouts.control),
114 STATISTICS_FIELD(timeouts.traverse),
115 STATISTICS_FIELD(total_calls),
116 STATISTICS_FIELD(pending_calls),
117 STATISTICS_FIELD(lockwait_calls),
118 STATISTICS_FIELD(pending_lockwait_calls),
119 STATISTICS_FIELD(memory_used),
120 STATISTICS_FIELD(max_hop_count),
122 printf("CTDB version %u\n", CTDB_VERSION);
123 for (i=0;i<ARRAY_SIZE(fields);i++) {
124 if (strchr(fields[i].name, '.')) {
125 preflen = strcspn(fields[i].name, ".")+1;
126 if (!prefix || strncmp(prefix, fields[i].name, preflen) != 0) {
127 prefix = fields[i].name;
128 printf(" %*.*s\n", preflen-1, preflen-1, fields[i].name);
133 printf(" %*s%-22s%*s%10u\n",
135 fields[i].name+preflen,
137 *(uint32_t *)(fields[i].offset+(uint8_t *)s));
139 printf(" %-30s %.6f sec\n", "max_call_latency", s->max_call_latency);
140 printf(" %-30s %.6f sec\n", "max_lockwait_latency", s->max_lockwait_latency);
141 talloc_free(tmp_ctx);
145 display remote ctdb statistics combined from all nodes
147 static int control_statistics_all(struct ctdb_context *ctdb)
150 struct ctdb_statistics statistics;
154 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
155 CTDB_NO_MEMORY(ctdb, nodes);
157 ZERO_STRUCT(statistics);
159 for (i=0;i<num_nodes;i++) {
160 struct ctdb_statistics s1;
162 uint32_t *v1 = (uint32_t *)&s1;
163 uint32_t *v2 = (uint32_t *)&statistics;
165 offsetof(struct ctdb_statistics, __last_counter) / sizeof(uint32_t);
166 ret = ctdb_ctrl_statistics(ctdb, nodes[i], &s1);
168 printf("Unable to get statistics from node %u\n", nodes[i]);
171 for (j=0;j<num_ints;j++) {
174 statistics.max_hop_count =
175 MAX(statistics.max_hop_count, s1.max_hop_count);
176 statistics.max_call_latency =
177 MAX(statistics.max_call_latency, s1.max_call_latency);
178 statistics.max_lockwait_latency =
179 MAX(statistics.max_lockwait_latency, s1.max_lockwait_latency);
182 printf("Gathered statistics for %u nodes\n", num_nodes);
183 show_statistics(&statistics);
188 display remote ctdb statistics
190 static int control_statistics(struct ctdb_context *ctdb, int argc, const char **argv)
193 struct ctdb_statistics statistics;
195 if (options.vnn == CTDB_BROADCAST_ALL) {
196 return control_statistics_all(ctdb);
199 ret = ctdb_ctrl_statistics(ctdb, options.vnn, &statistics);
201 printf("Unable to get statistics from node %u\n", options.vnn);
204 show_statistics(&statistics);
210 reset statistics on all nodes
212 static int control_statistics_reset_all(struct ctdb_context *ctdb)
218 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
219 CTDB_NO_MEMORY(ctdb, nodes);
221 for (i=0;i<num_nodes;i++) {
222 ret = ctdb_statistics_reset(ctdb, nodes[i]);
224 printf("Unable to reset statistics on node %u\n", nodes[i]);
234 reset remote ctdb statistics
236 static int control_statistics_reset(struct ctdb_context *ctdb, int argc, const char **argv)
240 if (options.vnn == CTDB_BROADCAST_ALL) {
241 return control_statistics_reset_all(ctdb);
244 ret = ctdb_statistics_reset(ctdb, options.vnn);
246 printf("Unable to reset statistics on node %u\n", options.vnn);
254 display remote ctdb status
256 static int control_status(struct ctdb_context *ctdb, int argc, const char **argv)
259 struct ctdb_vnn_map *vnnmap=NULL;
260 struct ctdb_node_map *nodemap=NULL;
261 uint32_t recmode, recmaster;
264 if (options.vnn == CTDB_BROADCAST_ALL) {
269 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
270 CTDB_NO_MEMORY(ctdb, nodes);
272 for (i=0;i<num_nodes;i++) {
273 options.vnn = nodes[i];
274 ret |= control_status(ctdb, argc, argv);
279 myvnn = ctdb_ctrl_getvnn(ctdb, TIMELIMIT(), options.vnn);
281 ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.vnn, ctdb, &nodemap);
283 printf("Unable to get nodemap from node %u\n", options.vnn);
287 if(options.machinereadable){
288 printf(":Node:IP:Status:\n");
289 for(i=0;i<nodemap->num;i++){
290 printf(":%d:%s:%d:\n", nodemap->nodes[i].vnn,
291 inet_ntoa(nodemap->nodes[i].sin.sin_addr),
292 !!nodemap->nodes[i].flags&NODE_FLAGS_CONNECTED);
297 printf("Number of nodes:%d\n", nodemap->num);
298 for(i=0;i<nodemap->num;i++){
299 printf("vnn:%d %-16s %s%s\n", nodemap->nodes[i].vnn,
300 inet_ntoa(nodemap->nodes[i].sin.sin_addr),
301 nodemap->nodes[i].flags&NODE_FLAGS_CONNECTED?
302 "CONNECTED":"UNAVAILABLE",
303 nodemap->nodes[i].vnn == myvnn?" (THIS NODE)":"");
306 ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.vnn, ctdb, &vnnmap);
308 printf("Unable to get vnnmap from node %u\n", options.vnn);
311 printf("Generation:%d\n",vnnmap->generation);
312 printf("Size:%d\n",vnnmap->size);
313 for(i=0;i<vnnmap->size;i++){
314 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
317 ret = ctdb_ctrl_getrecmode(ctdb, TIMELIMIT(), options.vnn, &recmode);
319 printf("Unable to get recmode from node %u\n", options.vnn);
322 printf("Recovery mode:%s (%d)\n",recmode==CTDB_RECOVERY_NORMAL?"NORMAL":"RECOVERY",recmode);
324 ret = ctdb_ctrl_getrecmaster(ctdb, TIMELIMIT(), options.vnn, &recmaster);
326 printf("Unable to get recmaster from node %u\n", options.vnn);
329 printf("Recovery master:%d\n",recmaster);
335 display pid of a ctdb daemon
337 static int control_getpid(struct ctdb_context *ctdb, int argc, const char **argv)
342 ret = ctdb_ctrl_getpid(ctdb, TIMELIMIT(), options.vnn, &pid);
344 printf("Unable to get daemon pid from node %u\n", options.vnn);
347 printf("Pid:%d\n", pid);
355 static int control_shutdown(struct ctdb_context *ctdb, int argc, const char **argv)
359 ret = ctdb_ctrl_shutdown(ctdb, timeval_current_ofs(1, 0), options.vnn);
361 printf("Unable to shutdown node %u\n", options.vnn);
371 static int control_recover(struct ctdb_context *ctdb, int argc, const char **argv)
375 ret = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), options.vnn);
377 printf("Unable to freeze node\n");
381 ret = ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.vnn, CTDB_RECOVERY_ACTIVE);
383 printf("Unable to set recovery mode\n");
392 display monitoring mode of a remote node
394 static int control_getmonmode(struct ctdb_context *ctdb, int argc, const char **argv)
399 ret = ctdb_ctrl_getmonmode(ctdb, TIMELIMIT(), options.vnn, &monmode);
401 printf("Unable to get monmode from node %u\n", options.vnn);
404 printf("Monitoring mode:%s (%d)\n",monmode==CTDB_MONITORING_ACTIVE?"ACTIVE":"DISABLED",monmode);
410 set the monitoring mode of a remote node
412 static int control_setmonmode(struct ctdb_context *ctdb, int argc, const char **argv)
421 monmode = strtoul(argv[0], NULL, 0);
423 ret = ctdb_ctrl_setmonmode(ctdb, TIMELIMIT(), options.vnn, monmode);
425 printf("Unable to set monmode on node %u\n", options.vnn);
433 display remote list of keys/data for a db
435 static int control_catdb(struct ctdb_context *ctdb, int argc, const char **argv)
438 struct ctdb_db_context *ctdb_db;
446 ctdb_db = ctdb_attach(ctdb, db_name);
448 if (ctdb_db == NULL) {
449 DEBUG(0,("Unable to attach to database '%s'\n", db_name));
453 /* traverse and dump the cluster tdb */
454 ret = ctdb_dump_db(ctdb_db, stdout);
456 printf("Unable to dump database\n");
459 talloc_free(ctdb_db);
461 printf("Dumped %d records\n", ret);
467 display a list of the databases on a remote ctdb
469 static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **argv)
472 struct ctdb_dbid_map *dbmap=NULL;
474 ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.vnn, ctdb, &dbmap);
476 printf("Unable to get dbids from node %u\n", options.vnn);
480 printf("Number of databases:%d\n", dbmap->num);
481 for(i=0;i<dbmap->num;i++){
485 ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.vnn, dbmap->dbids[i], ctdb, &path);
486 ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.vnn, dbmap->dbids[i], ctdb, &name);
487 printf("dbid:0x%08x name:%s path:%s\n", dbmap->dbids[i], name, path);
496 static int control_ping(struct ctdb_context *ctdb, int argc, const char **argv)
502 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
503 CTDB_NO_MEMORY(ctdb, nodes);
505 for (i=0;i<num_nodes;i++) {
506 struct timeval tv = timeval_current();
507 ret = ctdb_ctrl_ping(ctdb, nodes[i]);
509 printf("Unable to get ping response from node %u\n", nodes[i]);
511 printf("response from %u time=%.6f sec (%d clients)\n",
512 nodes[i], timeval_elapsed(&tv), ret);
523 static int control_getvar(struct ctdb_context *ctdb, int argc, const char **argv)
534 ret = ctdb_ctrl_get_tunable(ctdb, TIMELIMIT(), options.vnn, name, &value);
536 printf("Unable to get tunable variable '%s'\n", name);
540 printf("%-17s = %u\n", name, value);
547 static int control_setvar(struct ctdb_context *ctdb, int argc, const char **argv)
558 value = strtoul(argv[1], NULL, 0);
560 ret = ctdb_ctrl_set_tunable(ctdb, TIMELIMIT(), options.vnn, name, value);
562 printf("Unable to set tunable variable '%s'\n", name);
571 static int control_listvars(struct ctdb_context *ctdb, int argc, const char **argv)
577 ret = ctdb_ctrl_list_tunables(ctdb, TIMELIMIT(), options.vnn, ctdb, &list, &count);
579 printf("Unable to list tunable variables\n");
583 for (i=0;i<count;i++) {
584 control_getvar(ctdb, 1, &list[i]);
593 display debug level on a node
595 static int control_getdebug(struct ctdb_context *ctdb, int argc, const char **argv)
602 if (options.vnn != CTDB_BROADCAST_ALL) {
603 ret = ctdb_ctrl_get_debuglevel(ctdb, options.vnn, &level);
605 printf("Unable to get debuglevel response from node %u\n",
608 printf("Node %u is at debug level %u\n", options.vnn, level);
613 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
614 CTDB_NO_MEMORY(ctdb, nodes);
616 for (i=0;i<num_nodes;i++) {
617 ret = ctdb_ctrl_get_debuglevel(ctdb, nodes[i], &level);
619 printf("Unable to get debuglevel response from node %u\n",
622 printf("Node %u is at debug level %u\n", nodes[i], level);
631 set debug level on a node or all nodes
633 static int control_setdebug(struct ctdb_context *ctdb, int argc, const char **argv)
644 level = strtoul(argv[0], NULL, 0);
646 if (options.vnn != CTDB_BROADCAST_ALL) {
647 ret = ctdb_ctrl_set_debuglevel(ctdb, options.vnn, level);
649 printf("Unable to set debug level on node %u\n", options.vnn);
654 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
655 CTDB_NO_MEMORY(ctdb, nodes);
656 for (i=0;i<num_nodes;i++) {
657 ret = ctdb_ctrl_set_debuglevel(ctdb, nodes[i], level);
659 printf("Unable to set debug level on node %u\n", nodes[i]);
671 static int control_freeze(struct ctdb_context *ctdb, int argc, const char **argv)
678 if (options.vnn != CTDB_BROADCAST_ALL) {
679 ret = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), options.vnn);
681 printf("Unable to freeze node %u\n", options.vnn);
686 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
687 CTDB_NO_MEMORY(ctdb, nodes);
688 for (i=0;i<num_nodes;i++) {
689 int res = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), nodes[i]);
691 printf("Warning: Unable to freeze node %u\n", nodes[i]);
697 printf("Froze %u nodes\n", count);
705 static int control_thaw(struct ctdb_context *ctdb, int argc, const char **argv)
712 if (options.vnn != CTDB_BROADCAST_ALL) {
713 ret = ctdb_ctrl_thaw(ctdb, TIMELIMIT(), options.vnn);
715 printf("Unable to thaw node %u\n", options.vnn);
720 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
721 CTDB_NO_MEMORY(ctdb, nodes);
722 for (i=0;i<num_nodes;i++) {
723 int res = ctdb_ctrl_thaw(ctdb, TIMELIMIT(), nodes[i]);
725 printf("Warning: Unable to thaw node %u\n", nodes[i]);
731 printf("Thawed %u nodes\n", count);
740 static int control_attach(struct ctdb_context *ctdb, int argc, const char **argv)
743 struct ctdb_db_context *ctdb_db;
750 ctdb_db = ctdb_attach(ctdb, db_name);
751 if (ctdb_db == NULL) {
752 DEBUG(0,("Unable to attach to database '%s'\n", db_name));
762 static int control_dumpmemory(struct ctdb_context *ctdb, int argc, const char **argv)
764 return ctdb_control(ctdb, options.vnn, 0, CTDB_CONTROL_DUMP_MEMORY,
765 CTDB_CTRL_FLAG_NOREPLY, tdb_null, NULL, NULL, NULL, NULL, NULL);
769 static const struct {
771 int (*fn)(struct ctdb_context *, int, const char **);
774 } ctdb_commands[] = {
775 { "status", control_status, "show node status" },
776 { "ping", control_ping, "ping all nodes" },
777 { "getvar", control_getvar, "get a tunable variable", "<name>"},
778 { "setvar", control_setvar, "set a tunable variable", "<name> <value>"},
779 { "listvars", control_listvars, "list tunable variables"},
780 { "statistics", control_statistics, "show statistics" },
781 { "statisticsreset", control_statistics_reset, "reset statistics"},
782 { "process-exists", control_process_exists, "check if a process exists on a node", "<pid>"},
783 { "getdbmap", control_getdbmap, "show the database map" },
784 { "catdb", control_catdb, "dump a database" , "<dbname>"},
785 { "getmonmode", control_getmonmode, "show monitoring mode" },
786 { "setmonmode", control_setmonmode, "set monitoring mode" },
787 { "setdebug", control_setdebug, "set debug level", "<debuglevel>" },
788 { "getdebug", control_getdebug, "get debug level" },
789 { "attach", control_attach, "attach to a database", "<dbname>" },
790 { "dumpmemory", control_dumpmemory, "dump memory map to logs" },
791 { "getpid", control_getpid, "get ctdbd process ID" },
792 { "shutdown", control_shutdown, "shutdown ctdbd" },
793 { "recover", control_recover, "force recovery" },
794 { "freeze", control_freeze, "freeze all databases" },
795 { "thaw", control_thaw, "thaw all databases" },
801 static void usage(void)
805 "Usage: ctdb [options] <control>\n" \
807 " -n <node> choose node number, or 'all' (defaults to local node)\n"
808 " -Y generate machinereadable output\n"
809 " -t <timelimit> set timelimit for control in seconds (default %u)\n", options.timelimit);
810 printf("Controls:\n");
811 for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
812 printf(" %-15s %-20s %s\n",
813 ctdb_commands[i].name,
814 ctdb_commands[i].args?ctdb_commands[i].args:"",
815 ctdb_commands[i].msg);
824 int main(int argc, const char *argv[])
826 struct ctdb_context *ctdb;
827 char *nodestring = NULL;
828 struct poptOption popt_options[] = {
831 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0, "timelimit", "integer" },
832 { "node", 'n', POPT_ARG_STRING, &nodestring, 0, "node", "integer|all" },
833 { "machinereadable", 'Y', POPT_ARG_NONE, &options.machinereadable, 0, "enable machinereadable output", NULL },
837 const char **extra_argv;
841 struct event_context *ev;
844 /* set some defaults */
845 options.timelimit = 3;
846 options.vnn = CTDB_CURRENT_NODE;
848 pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
850 while ((opt = poptGetNextOpt(pc)) != -1) {
853 fprintf(stderr, "Invalid option %s: %s\n",
854 poptBadOption(pc, 0), poptStrerror(opt));
859 /* setup the remaining options for the main program to use */
860 extra_argv = poptGetArgs(pc);
863 while (extra_argv[extra_argc]) extra_argc++;
866 if (extra_argc < 1) {
870 /* setup the node number to contact */
871 if (nodestring != NULL) {
872 if (strcmp(nodestring, "all") == 0) {
873 options.vnn = CTDB_BROADCAST_ALL;
875 options.vnn = strtoul(nodestring, NULL, 0);
879 control = extra_argv[0];
881 ev = event_context_init(NULL);
883 /* initialise ctdb */
884 ctdb = ctdb_cmdline_client(ev);
886 printf("Failed to init ctdb\n");
890 for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
891 if (strcmp(control, ctdb_commands[i].name) == 0) {
892 ret = ctdb_commands[i].fn(ctdb, extra_argc-1, extra_argv+1);
897 if (i == ARRAY_SIZE(ctdb_commands)) {
898 printf("Unknown control '%s'\n", control);