STATISTICS_FIELD(timeouts.call),
STATISTICS_FIELD(timeouts.control),
STATISTICS_FIELD(timeouts.traverse),
+ STATISTICS_FIELD(locks.num_calls),
+ STATISTICS_FIELD(locks.num_current),
+ STATISTICS_FIELD(locks.num_pending),
+ STATISTICS_FIELD(locks.num_failed),
STATISTICS_FIELD(total_calls),
STATISTICS_FIELD(pending_calls),
STATISTICS_FIELD(lockwait_calls),
printf(" %d", s->hop_count_bucket[i]);
}
printf("\n");
- printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "reclock_ctdbd MIN/AVG/MAX", s->reclock.ctdbd.min, s->reclock.ctdbd.num?s->reclock.ctdbd.total/s->reclock.ctdbd.num:0.0, s->reclock.ctdbd.max, s->reclock.ctdbd.num);
+ printf(" lock_buckets:");
+ for (i=0; i<MAX_COUNT_BUCKETS; i++) {
+ printf(" %d", s->locks.buckets[i]);
+ }
+ printf("\n");
+ printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "locks_latency MIN/AVG/MAX", s->locks.latency.min, s->locks.latency.num?s->locks.latency.total/s->locks.latency.num:0.0, s->locks.latency.max, s->locks.latency.num);
+
+ printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "reclock_ctdbd MIN/AVG/MAX", s->reclock.ctdbd.min, s->reclock.ctdbd.num?s->reclock.ctdbd.total/s->reclock.ctdbd.num:0.0, s->reclock.ctdbd.max, s->reclock.ctdbd.num);
printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "reclock_recd MIN/AVG/MAX", s->reclock.recd.min, s->reclock.recd.num?s->reclock.recd.total/s->reclock.recd.num:0.0, s->reclock.recd.max, s->reclock.recd.num);
static int control_dbstatistics(struct ctdb_context *ctdb, int argc, const char **argv)
{
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
- struct ctdb_db_statistics *dbstatistics;
+ struct ctdb_db_statistics *dbstat;
struct ctdb_dbid_map *dbmap=NULL;
int i, ret;
return -1;
}
- if (!ctdb_getdbstat(ctdb_connection, options.pnn, dbmap->dbs[i].dbid, &dbstatistics)) {
+ if (!ctdb_getdbstat(ctdb_connection, options.pnn, dbmap->dbs[i].dbid, &dbstat)) {
DEBUG(DEBUG_ERR,("Failed to read db statistics from node\n"));
talloc_free(tmp_ctx);
return -1;
}
printf("DB Statistics:\n");
- printf("RO Delegations: %d\n", dbstatistics->db_ro_delegations);
- printf("RO Revokes: %d\n", dbstatistics->db_ro_revokes);
- printf(" hop_count_buckets:");
- for (i=0;i<MAX_COUNT_BUCKETS;i++) {
- printf(" %d", dbstatistics->hop_count_bucket[i]);
+ printf(" %*s%-22s%*s%10u\n", 0, "", "ro_delegations", 4, "",
+ dbstat->db_ro_delegations);
+ printf(" %*s%-22s%*s%10u\n", 0, "", "ro_revokes", 4, "",
+ dbstat->db_ro_delegations);
+ printf(" %s\n", "locks");
+ printf(" %*s%-22s%*s%10u\n", 4, "", "total", 0, "",
+ dbstat->locks.num_calls);
+ printf(" %*s%-22s%*s%10u\n", 4, "", "failed", 0, "",
+ dbstat->locks.num_failed);
+ printf(" %*s%-22s%*s%10u\n", 4, "", "current", 0, "",
+ dbstat->locks.num_current);
+ printf(" %*s%-22s%*s%10u\n", 4, "", "pending", 0, "",
+ dbstat->locks.num_pending);
+ printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
+ " latency_ctdbd MIN/AVG/MAX",
+ dbstat->locks.latency.min,
+ (dbstat->locks.latency.num ?
+ dbstat->locks.latency.total /dbstat->locks.latency.num :
+ 0.0),
+ dbstat->locks.latency.max,
+ dbstat->locks.latency.num);
+ printf(" %s", " buckets:");
+ for (i=0; i<MAX_COUNT_BUCKETS; i++) {
+ printf(" %d", dbstat->hop_count_bucket[i]);
}
printf("\n");
+ printf("Num Hot Keys: %d\n", dbstat->num_hot_keys);
+ for (i = 0; i < dbstat->num_hot_keys; i++) {
+ int j;
+ printf("Count:%d Key:", dbstat->hot_keys[i].count);
+ for (j = 0; j < dbstat->hot_keys[i].key.dsize; j++) {
+ printf("%02x", dbstat->hot_keys[i].key.dptr[j]&0xff);
+ }
+ printf("\n");
+ }
- ctdb_free_dbstat(dbstatistics);
+ ctdb_free_dbstat(dbstat);
return 0;
}
return ret;
}
+static void control_status_header_machine(void)
+{
+ printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped"
+ ":Inactive:PartiallyOnline:ThisNode:\n");
+}
+
static int control_status_1_machine(int mypnn, struct ctdb_node_and_flags *node)
{
printf(":%d:%s:%d:%d:%d:%d:%d:%d:%d:%c:\n", node->pnn,
}
if (options.machinereadable) {
- printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped"
- ":Inactive:PartiallyOnline:ThisNode:\n");
+ control_status_header_machine();
for (i=0;i<nodemap->num;i++) {
if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
continue;
}
if (options.machinereadable) {
- printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped"
- ":Inactive:PartiallyOnline:ThisNode:\n");
+ control_status_header_machine();
} else if (pnn_mode == CTDB_BROADCAST_ALL) {
printf("Number of nodes:%d\n", (int) talloc_array_length(nodes));
}
const char *addr;
};
+static int find_natgw(struct ctdb_context *ctdb,
+ struct ctdb_node_map *nodemap, uint32_t flags,
+ uint32_t *pnn, const char **ip)
+{
+ int i;
+ uint32_t capabilities;
+
+ for (i=0;i<nodemap->num;i++) {
+ if (!(nodemap->nodes[i].flags & flags)) {
+ if (!ctdb_getcapabilities(ctdb_connection, nodemap->nodes[i].pnn, &capabilities)) {
+ DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
+ return -1;
+ }
+ if (!(capabilities&CTDB_CAP_NATGW)) {
+ continue;
+ }
+ *pnn = nodemap->nodes[i].pnn;
+ *ip = ctdb_addr_to_str(&nodemap->nodes[i].addr);
+ return 0;
+ }
+ }
+
+ return 2; /* matches ENOENT */
+}
+
/*
display the list of nodes belonging to this natgw configuration
*/
static int control_natgwlist(struct ctdb_context *ctdb, int argc, const char **argv)
{
int i, ret;
- uint32_t capabilities;
const char *natgw_list;
int nlines;
char **lines;
struct natgw_node *natgw_nodes = NULL;
struct natgw_node *natgw_node;
struct ctdb_node_map *nodemap=NULL;
+ uint32_t mypnn, pnn;
+ const char *ip;
+ /* When we have some nodes that could be the NATGW, make a
+ * series of attempts to find the first node that doesn't have
+ * certain status flags set.
+ */
+ uint32_t exclude_flags[] = {
+ /* Look for a nice healthy node */
+ NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_UNHEALTHY,
+ /* If not found, an UNHEALTHY/BANNED node will do */
+ NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED,
+ /* If not found, a STOPPED node will do */
+ NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED,
+ 0,
+ };
/* read the natgw nodes file into a linked list */
- natgw_list = getenv("NATGW_NODES");
+ natgw_list = getenv("CTDB_NATGW_NODES");
if (natgw_list == NULL) {
natgw_list = "/etc/ctdb/natgw_nodes";
}
ctdb_set_error(ctdb, "Failed to load natgw node list '%s'\n", natgw_list);
return -1;
}
- while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
- nlines--;
- }
for (i=0;i<nlines;i++) {
char *node;
natgw_nodes = natgw_node;
}
- ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
- if (ret != 0) {
+ if (!ctdb_getnodemap(ctdb_connection, CTDB_CURRENT_NODE, &nodemap)) {
DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node.\n"));
- return ret;
+ return -1;
}
+ /* Trim the nodemap so it only includes connected nodes in the
+ * current natgw group.
+ */
i=0;
while(i<nodemap->num) {
for(natgw_node=natgw_nodes;natgw_node;natgw_node=natgw_node->next) {
}
i++;
- }
+ }
- /* pick a node to be natgwmaster
- * we dont allow STOPPED, DELETED, BANNED or UNHEALTHY nodes to become the natgwmaster
- */
- for(i=0;i<nodemap->num;i++){
- if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_UNHEALTHY))) {
- ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, &capabilities);
- if (ret != 0) {
- DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
- return ret;
- }
- if (!(capabilities&CTDB_CAP_NATGW)) {
- continue;
- }
- printf("%d %s\n", nodemap->nodes[i].pnn,ctdb_addr_to_str(&nodemap->nodes[i].addr));
- break;
+ ret = 2; /* matches ENOENT */
+ pnn = -1;
+ ip = "0.0.0.0";
+ for (i = 0; exclude_flags[i] != 0; i++) {
+ ret = find_natgw(ctdb, nodemap,
+ exclude_flags[i],
+ &pnn, &ip);
+ if (ret == -1) {
+ goto done;
}
- }
- /* we couldnt find any healthy node, try unhealthy ones */
- if (i == nodemap->num) {
- for(i=0;i<nodemap->num;i++){
- if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED))) {
- ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, &capabilities);
- if (ret != 0) {
- DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
- return ret;
- }
- if (!(capabilities&CTDB_CAP_NATGW)) {
- continue;
- }
- printf("%d %s\n", nodemap->nodes[i].pnn,ctdb_addr_to_str(&nodemap->nodes[i].addr));
- break;
- }
+ if (ret == 0) {
+ break;
}
}
- /* unless all nodes are STOPPED, when we pick one anyway */
- if (i == nodemap->num) {
- for(i=0;i<nodemap->num;i++){
- if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED))) {
- ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, &capabilities);
- if (ret != 0) {
- DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
- return ret;
- }
- if (!(capabilities&CTDB_CAP_NATGW)) {
- continue;
- }
- printf("%d %s\n", nodemap->nodes[i].pnn, ctdb_addr_to_str(&nodemap->nodes[i].addr));
- break;
- }
- }
- /* or if we still can not find any */
- if (i == nodemap->num) {
- printf("-1 0.0.0.0\n");
- ret = 2; /* matches ENOENT */
- }
+
+ if (options.machinereadable) {
+ printf(":Node:IP:\n");
+ printf(":%d:%s:\n", pnn, ip);
+ } else {
+ printf("%d %s\n", pnn, ip);
}
/* print the pruned list of nodes belonging to this natgw list */
+ if (!ctdb_getpnn(ctdb_connection, options.pnn, &mypnn)) {
+ DEBUG(DEBUG_NOTICE, ("Unable to get PNN from node %u\n", options.pnn));
+ /* This is actually harmless and will only result in
+ * the "this node" indication being missing
+ */
+ mypnn = -1;
+ }
+ if (options.machinereadable) {
+ control_status_header_machine();
+ } else {
+ printf("Number of nodes:%d\n", nodemap->num);
+ }
for(i=0;i<nodemap->num;i++){
if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
continue;
}
- printf(":%d:%s:%d:%d:%d:%d:%d\n", nodemap->nodes[i].pnn,
- ctdb_addr_to_str(&nodemap->nodes[i].addr),
- !!(nodemap->nodes[i].flags&NODE_FLAGS_DISCONNECTED),
- !!(nodemap->nodes[i].flags&NODE_FLAGS_BANNED),
- !!(nodemap->nodes[i].flags&NODE_FLAGS_PERMANENTLY_DISABLED),
- !!(nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY),
- !!(nodemap->nodes[i].flags&NODE_FLAGS_STOPPED));
+ if (options.machinereadable) {
+ control_status_1_machine(mypnn, &(nodemap->nodes[i]));
+ } else {
+ control_status_1_human(mypnn, &(nodemap->nodes[i]));
+ }
}
+done:
+ ctdb_free_nodemap(nodemap);
return ret;
}
return 0;
}
+/*
+ add a public ip address to a node
+ */
+static int control_ipiface(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ ctdb_sock_addr addr;
+
+ if (argc != 1) {
+ usage();
+ }
+
+ if (!parse_ip(argv[0], NULL, 0, &addr)) {
+ printf("Badly formed ip : %s\n", argv[0]);
+ return -1;
+ }
+
+ printf("IP on interface %s\n", ctdb_sys_find_ifname(&addr));
+
+ return 0;
+}
+
static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv);
static int control_delip_all(struct ctdb_context *ctdb, int argc, const char **argv, ctdb_sock_addr *addr)
static int control_getcapabilities(struct ctdb_context *ctdb, int argc, const char **argv)
{
uint32_t capabilities;
- int ret;
- ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), options.pnn, &capabilities);
- if (ret != 0) {
+ if (!ctdb_getcapabilities(ctdb_connection, options.pnn, &capabilities)) {
DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", options.pnn));
- return ret;
+ return -1;
}
if (!options.machinereadable){
int i, ret;
int healthy_count = 0;
- ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap);
- if (ret != 0) {
+ if (!ctdb_getnodemap(ctdb_connection, options.pnn, &nodemap)) {
DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
- return ret;
+ return -1;
}
capabilities = talloc_array(ctdb, uint32_t, nodemap->num);
CTDB_NO_MEMORY(ctdb, capabilities);
+ ret = 0;
+
/* collect capabilities for all connected nodes */
for (i=0; i<nodemap->num; i++) {
if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
continue;
}
- ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), i, &capabilities[i]);
- if (ret != 0) {
+ if (!ctdb_getcapabilities(ctdb_connection, i, &capabilities[i])) {
DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", i));
- return ret;
+ ret = -1;
+ goto done;
}
if (!(capabilities[i] & CTDB_CAP_LVS)) {
ctdb_addr_to_str(&nodemap->nodes[i].addr));
}
- return 0;
+done:
+ ctdb_free_nodemap(nodemap);
+ return ret;
}
/*
int i, ret;
int healthy_count = 0;
- ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap);
- if (ret != 0) {
+ if (!ctdb_getnodemap(ctdb_connection, options.pnn, &nodemap)) {
DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
- return ret;
+ return -1;
}
capabilities = talloc_array(ctdb, uint32_t, nodemap->num);
CTDB_NO_MEMORY(ctdb, capabilities);
+
+ ret = -1;
/* collect capabilities for all connected nodes */
for (i=0; i<nodemap->num; i++) {
continue;
}
- ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), i, &capabilities[i]);
- if (ret != 0) {
+ if (!ctdb_getcapabilities(ctdb_connection, i, &capabilities[i])) {
DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", i));
- return ret;
+ ret = -1;
+ goto done;
}
if (!(capabilities[i] & CTDB_CAP_LVS)) {
} else {
printf("Node %d is LVS master\n", i);
}
- return 0;
+ ret = 0;
+ goto done;
}
printf("There is no LVS master\n");
- return -1;
+done:
+ ctdb_free_nodemap(nodemap);
+ return ret;
}
/*
return -1;
}
- ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, false, 0);
+ ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
if (ctdb_db == NULL) {
DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
}
+static uint32_t reloadips_finished;
+
+static void reloadips_handler(struct ctdb_context *ctdb, uint64_t srvid,
+ TDB_DATA data, void *private_data)
+{
+ reloadips_finished = 1;
+}
+
+static int reloadips_all(struct ctdb_context *ctdb)
+{
+ struct reloadips_all_reply rips;
+ struct ctdb_node_map *nodemap=NULL;
+ TDB_DATA data;
+ uint32_t recmaster;
+ int ret, i;
+
+ /* check that there are valid nodes available */
+ if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+ return 1;
+ }
+ for (i=0; i<nodemap->num;i++) {
+ if (nodemap->nodes[i].flags != 0) {
+ DEBUG(DEBUG_ERR,("reloadips -n all can only be used when all nodes are up and healthy. Aborting due to problem with node %d\n", i));
+ return 1;
+ }
+ }
+
+
+ rips.pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+ if (rips.pnn == -1) {
+ DEBUG(DEBUG_ERR, ("Failed to get pnn of local node\n"));
+ return 1;
+ }
+ rips.srvid = getpid();
+
+
+ /* register a message port for receiveing the reply so that we
+ can receive the reply
+ */
+ ctdb_client_set_message_handler(ctdb, rips.srvid, reloadips_handler, NULL);
+
+ if (!ctdb_getrecmaster(ctdb_connection, CTDB_CURRENT_NODE, &recmaster)) {
+ DEBUG(DEBUG_ERR, ("Unable to get recmaster from node\n"));
+ return -1;
+ }
+
+
+ data.dptr = (uint8_t *)&rips;
+ data.dsize = sizeof(rips);
+
+ ret = ctdb_client_send_message(ctdb, recmaster, CTDB_SRVID_RELOAD_ALL_IPS, data);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR,("Failed to send reload all ips request message to %u\n", options.pnn));
+ return 1;
+ }
+
+ reloadips_finished = 0;
+ while (reloadips_finished == 0) {
+ event_loop_once(ctdb->ev);
+ }
+
+ return 0;
+}
+
+/*
+ reload public ips on a specific node
+ */
+static int control_reloadips(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ int ret;
+ int32_t res;
+ char *errmsg;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+ if (options.pnn == CTDB_BROADCAST_ALL) {
+ return reloadips_all(ctdb);
+ }
+
+ ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_RELOAD_PUBLIC_IPS,
+ 0, tdb_null, tmp_ctx, NULL, &res, NULL, &errmsg);
+ if (ret != 0 || res != 0) {
+ DEBUG(DEBUG_ERR,("Failed to reload ips\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ talloc_free(tmp_ctx);
+ return 0;
+}
/*
display a list of the databases on a remote ctdb
{ "restoredb", control_restoredb, false, false, "restore the database from a file.", "<file> [dbname]"},
{ "dumpdbbackup", control_dumpdbbackup, false, true, "dump database backup from a file.", "<file>"},
{ "wipedb", control_wipedb, false, false, "wipe the contents of a database.", "<dbname>"},
- { "recmaster", control_recmaster, false, false, "show the pnn for the recovery master."},
+ { "recmaster", control_recmaster, true, false, "show the pnn for the recovery master."},
{ "scriptstatus", control_scriptstatus, true, false, "show the status of the monitoring scripts (or all scripts)", "[all]"},
{ "enablescript", control_enablescript, false, false, "enable an eventscript", "<script>"},
{ "disablescript", control_disablescript, false, false, "disable an eventscript", "<script>"},
{ "getdbseqnum", control_getdbseqnum, false, false, "get the sequence number off a database", "<dbid>" },
{ "nodestatus", control_nodestatus, true, false, "show and return node status" },
{ "dbstatistics", control_dbstatistics, false, false, "show db statistics", "<db>" },
+ { "reloadips", control_reloadips, false, false, "reload the public addresses file on a node" },
+ { "ipiface", control_ipiface, true, true, "Find which interface an ip address is hsoted on", "<ip>" },
};
/*
DEBUG(DEBUG_ERR, ("Failed to initialize event system\n"));
exit(1);
}
- tevent_loop_allow_nesting(ev);
for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
if (strcmp(control, ctdb_commands[i].name) == 0) {
ctdb_disconnect(ctdb_connection);
talloc_free(ctdb);
+ talloc_free(ev);
(void)poptFreeContext(pc);
return ret;