/* ctdb control tool Copyright (C) Andrew Tridgell 2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" #include "lib/events/events.h" #include "system/filesys.h" #include "popt.h" #include "cmdline.h" #include "../include/ctdb.h" #include "../include/ctdb_private.h" #include static void usage(void); static struct { int timelimit; uint32_t vnn; } options; #define TIMELIMIT() timeval_current_ofs(options.timelimit, 0) /* see if a process exists */ static int control_process_exists(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t vnn, pid; int ret; if (argc < 1) { usage(); } if (sscanf(argv[0], "%u:%u", &vnn, &pid) != 2) { printf("Badly formed vnn:pid\n"); return -1; } ret = ctdb_ctrl_process_exists(ctdb, vnn, pid); if (ret == 0) { printf("%u:%u exists\n", vnn, pid); } else { printf("%u:%u does not exist\n", vnn, pid); } return ret; } /* display statistics structure */ static void show_statistics(struct ctdb_statistics *s) { TALLOC_CTX *tmp_ctx = talloc_new(NULL); int i; const char *prefix=NULL; int preflen=0; const struct { const char *name; uint32_t offset; } fields[] = { #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) } STATISTICS_FIELD(num_clients), STATISTICS_FIELD(frozen), STATISTICS_FIELD(recovering), STATISTICS_FIELD(client_packets_sent), STATISTICS_FIELD(client_packets_recv), STATISTICS_FIELD(node_packets_sent), STATISTICS_FIELD(node_packets_recv), STATISTICS_FIELD(keepalive_packets_sent), STATISTICS_FIELD(keepalive_packets_recv), STATISTICS_FIELD(node.req_call), STATISTICS_FIELD(node.reply_call), STATISTICS_FIELD(node.req_dmaster), STATISTICS_FIELD(node.reply_dmaster), STATISTICS_FIELD(node.reply_error), STATISTICS_FIELD(node.req_message), STATISTICS_FIELD(node.req_finished), STATISTICS_FIELD(node.req_control), STATISTICS_FIELD(node.reply_control), STATISTICS_FIELD(client.req_call), STATISTICS_FIELD(client.req_message), STATISTICS_FIELD(client.req_finished), STATISTICS_FIELD(client.req_connect_wait), STATISTICS_FIELD(client.req_shutdown), STATISTICS_FIELD(client.req_control), STATISTICS_FIELD(controls.statistics), STATISTICS_FIELD(controls.get_config), STATISTICS_FIELD(controls.ping), STATISTICS_FIELD(controls.attach), STATISTICS_FIELD(controls.set_call), STATISTICS_FIELD(controls.process_exists), STATISTICS_FIELD(controls.traverse_start), STATISTICS_FIELD(controls.traverse_all), STATISTICS_FIELD(controls.traverse_data), STATISTICS_FIELD(controls.update_seqnum), STATISTICS_FIELD(controls.enable_seqnum), STATISTICS_FIELD(controls.set_seqnum_frequency), STATISTICS_FIELD(controls.register_srvid), STATISTICS_FIELD(controls.deregister_srvid), STATISTICS_FIELD(timeouts.call), STATISTICS_FIELD(timeouts.control), STATISTICS_FIELD(timeouts.traverse), STATISTICS_FIELD(total_calls), STATISTICS_FIELD(pending_calls), STATISTICS_FIELD(lockwait_calls), STATISTICS_FIELD(pending_lockwait_calls), STATISTICS_FIELD(memory_used), STATISTICS_FIELD(max_hop_count), }; printf("CTDB version %u\n", CTDB_VERSION); for (i=0;imax_call_latency); printf(" %-30s %.6f sec\n", "max_lockwait_latency", s->max_lockwait_latency); talloc_free(tmp_ctx); } /* display remote ctdb statistics combined from all nodes */ static int control_statistics_all(struct ctdb_context *ctdb) { int ret, i; struct ctdb_statistics statistics; uint32_t *nodes; uint32_t num_nodes; nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes); CTDB_NO_MEMORY(ctdb, nodes); ZERO_STRUCT(statistics); for (i=0;inum); for(i=0;inum;i++){ printf("vnn:%d %s%s\n", nodemap->nodes[i].vnn, nodemap->nodes[i].flags&NODE_FLAGS_CONNECTED? "CONNECTED":"UNAVAILABLE", nodemap->nodes[i].vnn == myvnn?" (THIS NODE)":""); } ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.vnn, ctdb, &vnnmap); if (ret != 0) { printf("Unable to get vnnmap from node %u\n", options.vnn); return ret; } printf("Generation:%d\n",vnnmap->generation); printf("Size:%d\n",vnnmap->size); for(i=0;isize;i++){ printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]); } ret = ctdb_ctrl_getrecmode(ctdb, TIMELIMIT(), options.vnn, &recmode); if (ret != 0) { printf("Unable to get recmode from node %u\n", options.vnn); return ret; } printf("Recovery mode:%s (%d)\n",recmode==CTDB_RECOVERY_NORMAL?"NORMAL":"RECOVERY",recmode); ret = ctdb_ctrl_getrecmaster(ctdb, TIMELIMIT(), options.vnn, &recmaster); if (ret != 0) { printf("Unable to get recmaster from node %u\n", options.vnn); return ret; } printf("Recovery master:%d\n",recmaster); return 0; } /* display pid of a ctdb daemon */ static int control_getpid(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t pid; int ret; ret = ctdb_ctrl_getpid(ctdb, TIMELIMIT(), options.vnn, &pid); if (ret != 0) { printf("Unable to get daemon pid from node %u\n", options.vnn); return ret; } printf("Pid:%d\n", pid); return 0; } /* shutdown a daemon */ static int control_shutdown(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; ret = ctdb_ctrl_shutdown(ctdb, timeval_current_ofs(1, 0), options.vnn); if (ret != 0) { printf("Unable to shutdown node %u\n", options.vnn); return ret; } return 0; } /* trigger a recovery */ static int control_recover(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; ret = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), options.vnn); if (ret != 0) { printf("Unable to freeze node\n"); return ret; } ret = ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.vnn, CTDB_RECOVERY_ACTIVE); if (ret != 0) { printf("Unable to set recovery mode\n"); return ret; } return 0; } /* display monitoring mode of a remote node */ static int control_getmonmode(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t monmode; int ret; ret = ctdb_ctrl_getmonmode(ctdb, TIMELIMIT(), options.vnn, &monmode); if (ret != 0) { printf("Unable to get monmode from node %u\n", options.vnn); return ret; } printf("Monitoring mode:%s (%d)\n",monmode==CTDB_MONITORING_ACTIVE?"ACTIVE":"DISABLED",monmode); return 0; } /* set the monitoring mode of a remote node */ static int control_setmonmode(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t monmode; int ret; if (argc < 1) { usage(); } monmode = strtoul(argv[0], NULL, 0); ret = ctdb_ctrl_setmonmode(ctdb, TIMELIMIT(), options.vnn, monmode); if (ret != 0) { printf("Unable to set monmode on node %u\n", options.vnn); return ret; } return 0; } /* display remote list of keys/data for a db */ static int control_catdb(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; struct ctdb_db_context *ctdb_db; int ret; if (argc < 1) { usage(); } db_name = argv[0]; ctdb_db = ctdb_attach(ctdb, db_name); if (ctdb_db == NULL) { DEBUG(0,("Unable to attach to database '%s'\n", db_name)); return -1; } /* traverse and dump the cluster tdb */ ret = ctdb_dump_db(ctdb_db, stdout); if (ret == -1) { printf("Unable to dump database\n"); return -1; } talloc_free(ctdb_db); printf("Dumped %d records\n", ret); return 0; } /* display a list of the databases on a remote ctdb */ static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **argv) { int i, ret; struct ctdb_dbid_map *dbmap=NULL; ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.vnn, ctdb, &dbmap); if (ret != 0) { printf("Unable to get dbids from node %u\n", options.vnn); return ret; } printf("Number of databases:%d\n", dbmap->num); for(i=0;inum;i++){ const char *path; const char *name; ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.vnn, dbmap->dbids[i], ctdb, &path); ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.vnn, dbmap->dbids[i], ctdb, &name); printf("dbid:0x%08x name:%s path:%s\n", dbmap->dbids[i], name, path); } return 0; } /* ping a node */ static int control_ping(struct ctdb_context *ctdb, int argc, const char **argv) { int ret, i; uint32_t *nodes; uint32_t num_nodes; nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes); CTDB_NO_MEMORY(ctdb, nodes); for (i=0;i"}, { "getdbmap", control_getdbmap, "show the database map" }, { "catdb", control_catdb, "dump a database" , ""}, { "getmonmode", control_getmonmode, "show monitoring mode" }, { "setmonmode", control_setmonmode, "set monitoring mode" }, { "setdebug", control_setdebug, "set debug level", "" }, { "getdebug", control_getdebug, "get debug level" }, { "attach", control_attach, "attach to a database", "" }, { "dumpmemory", control_dumpmemory, "dump memory map to logs" }, { "getpid", control_getpid, "get ctdbd process ID" }, { "shutdown", control_shutdown, "shutdown ctdbd" }, { "recover", control_recover, "force recovery" }, { "freeze", control_freeze, "freeze all databases" }, { "thaw", control_thaw, "thaw all databases" }, }; /* show usage message */ static void usage(void) { int i; printf( "Usage: ctdb [options] \n" \ "Options:\n" \ " -n choose node number, or 'all' (defaults to local node)\n" " -t set timelimit for control in seconds (default %u)\n", options.timelimit); printf("Controls:\n"); for (i=0;i