diff options
Diffstat (limited to 'src/repmgr/repmgr_stat.c')
-rw-r--r-- | src/repmgr/repmgr_stat.c | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/src/repmgr/repmgr_stat.c b/src/repmgr/repmgr_stat.c new file mode 100644 index 00000000..fd6dabd3 --- /dev/null +++ b/src/repmgr/repmgr_stat.c @@ -0,0 +1,363 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005, 2012 Oracle and/or its affiliates. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" + +#ifdef HAVE_STATISTICS +static int __repmgr_print_all __P((ENV *, u_int32_t)); +static int __repmgr_print_sites __P((ENV *)); +static int __repmgr_print_stats __P((ENV *, u_int32_t)); +static int __repmgr_stat __P((ENV *, DB_REPMGR_STAT **, u_int32_t)); + +/* + * __repmgr_stat_pp -- + * DB_ENV->repmgr_stat pre/post processing. + * + * PUBLIC: int __repmgr_stat_pp __P((DB_ENV *, DB_REPMGR_STAT **, u_int32_t)); + */ +int +__repmgr_stat_pp(dbenv, statp, flags) + DB_ENV *dbenv; + DB_REPMGR_STAT **statp; + u_int32_t flags; +{ + ENV *env; + int ret; + + env = dbenv->env; + + ENV_REQUIRES_CONFIG_XX( + env, rep_handle, "DB_ENV->repmgr_stat", DB_INIT_REP); + + if ((ret = __db_fchk(env, + "DB_ENV->repmgr_stat", flags, DB_STAT_CLEAR)) != 0) + return (ret); + + return (__repmgr_stat(env, statp, flags)); +} + +/* + * __repmgr_stat -- + * ENV->repmgr_stat. + */ +static int +__repmgr_stat(env, statp, flags) + ENV *env; + DB_REPMGR_STAT **statp; + u_int32_t flags; +{ + DB_REP *db_rep; + DB_REPMGR_STAT *copy, *stats; + uintmax_t tmp; + int ret; + + db_rep = env->rep_handle; + stats = &db_rep->region->mstat; + + *statp = NULL; + + /* Allocate a stat struct to return to the user. */ + if ((ret = __os_umalloc(env, sizeof(DB_REPMGR_STAT), ©)) != 0) + return (ret); + + memcpy(copy, stats, sizeof(*stats)); + if (LF_ISSET(DB_STAT_CLEAR)) { + tmp = stats->st_max_elect_threads; + memset(stats, 0, sizeof(DB_REPMGR_STAT)); + stats->st_max_elect_threads = tmp; + } + + *statp = copy; + return (0); +} + +/* + * __repmgr_stat_print_pp -- + * DB_ENV->repmgr_stat_print pre/post processing. + * + * PUBLIC: int __repmgr_stat_print_pp __P((DB_ENV *, u_int32_t)); + */ +int +__repmgr_stat_print_pp(dbenv, flags) + DB_ENV *dbenv; + u_int32_t flags; +{ + ENV *env; + int ret; + + env = dbenv->env; + + ENV_REQUIRES_CONFIG_XX( + env, rep_handle, "DB_ENV->repmgr_stat_print", DB_INIT_REP); + + if ((ret = __db_fchk(env, "DB_ENV->repmgr_stat_print", + flags, DB_STAT_ALL | DB_STAT_CLEAR)) != 0) + return (ret); + + return (__repmgr_stat_print(env, flags)); +} + +/* + * PUBLIC: int __repmgr_stat_print __P((ENV *, u_int32_t)); + */ +int +__repmgr_stat_print(env, flags) + ENV *env; + u_int32_t flags; +{ + u_int32_t orig_flags; + int ret; + + orig_flags = flags; + LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM); + if (flags == 0 || LF_ISSET(DB_STAT_ALL)) { + if ((ret = __repmgr_print_stats(env, orig_flags)) == 0) + ret = __repmgr_print_sites(env); + if (flags == 0 || ret != 0) + return (ret); + } + + if (LF_ISSET(DB_STAT_ALL) && + (ret = __repmgr_print_all(env, orig_flags)) != 0) + return (ret); + + return (0); +} + +static int +__repmgr_print_stats(env, flags) + ENV *env; + u_int32_t flags; +{ + DB_REPMGR_STAT *sp; + int ret; + + if ((ret = __repmgr_stat(env, &sp, flags)) != 0) + return (ret); + + __db_dl(env, "Number of PERM messages not acknowledged", + (u_long)sp->st_perm_failed); + __db_dl(env, "Number of messages queued due to network delay", + (u_long)sp->st_msgs_queued); + __db_dl(env, "Number of messages discarded due to queue length", + (u_long)sp->st_msgs_dropped); + __db_dl(env, "Number of existing connections dropped", + (u_long)sp->st_connection_drop); + __db_dl(env, "Number of failed new connection attempts", + (u_long)sp->st_connect_fail); + __db_dl(env, "Number of currently active election threads", + (u_long)sp->st_elect_threads); + __db_dl(env, "Election threads for which space is reserved", + (u_long)sp->st_max_elect_threads); + + __os_ufree(env, sp); + + return (0); +} + +static int +__repmgr_print_sites(env) + ENV *env; +{ + DB_REPMGR_SITE *list; + DB_MSGBUF mb; + u_int count, i; + int ret; + + if ((ret = __repmgr_site_list(env->dbenv, &count, &list)) != 0) + return (ret); + + if (count == 0) + return (0); + + __db_msg(env, "%s", DB_GLOBAL(db_line)); + __db_msg(env, "DB_REPMGR site information:"); + + DB_MSGBUF_INIT(&mb); + for (i = 0; i < count; ++i) { + __db_msgadd(env, &mb, "%s (eid: %d, port: %u", + list[i].host, list[i].eid, list[i].port); + if (list[i].status != 0) + __db_msgadd(env, &mb, ", %sconnected", + list[i].status == DB_REPMGR_CONNECTED ? "" : "dis"); + __db_msgadd(env, &mb, ", %speer", + F_ISSET(&list[i], DB_REPMGR_ISPEER) ? "" : "non-"); + __db_msgadd(env, &mb, ")"); + DB_MSGBUF_FLUSH(env, &mb); + } + + __os_ufree(env, list); + + return (0); +} + +/* + * __repmgr_print_all -- + * Display debugging replication manager statistics. + */ +static int +__repmgr_print_all(env, flags) + ENV *env; + u_int32_t flags; +{ + COMPQUIET(env, NULL); + COMPQUIET(flags, 0); + return (0); +} + +#else /* !HAVE_STATISTICS */ + +int +__repmgr_stat_pp(dbenv, statp, flags) + DB_ENV *dbenv; + DB_REPMGR_STAT **statp; + u_int32_t flags; +{ + COMPQUIET(statp, NULL); + COMPQUIET(flags, 0); + + return (__db_stat_not_built(dbenv->env)); +} + +int +__repmgr_stat_print_pp(dbenv, flags) + DB_ENV *dbenv; + u_int32_t flags; +{ + COMPQUIET(flags, 0); + + return (__db_stat_not_built(dbenv->env)); +} +#endif + +/* + * PUBLIC: int __repmgr_site_list __P((DB_ENV *, u_int *, DB_REPMGR_SITE **)); + */ +int +__repmgr_site_list(dbenv, countp, listp) + DB_ENV *dbenv; + u_int *countp; + DB_REPMGR_SITE **listp; +{ + DB_REP *db_rep; + REP *rep; + DB_REPMGR_SITE *status; + ENV *env; + DB_THREAD_INFO *ip; + REPMGR_SITE *site; + size_t array_size, total_size; + int eid, locked, ret; + u_int count, i; + char *name; + + env = dbenv->env; + db_rep = env->rep_handle; + ret = 0; + + ENV_NOT_CONFIGURED( + env, db_rep->region, "DB_ENV->repmgr_site_list", DB_INIT_REP); + + if (REP_ON(env)) { + rep = db_rep->region; + LOCK_MUTEX(db_rep->mutex); + locked = TRUE; + + ENV_ENTER(env, ip); + if (rep->siteinfo_seq > db_rep->siteinfo_seq) + ret = __repmgr_sync_siteaddr(env); + ENV_LEAVE(env, ip); + if (ret != 0) + goto err; + } else { + rep = NULL; + locked = FALSE; + } + + /* Initialize for empty list or error return. */ + *countp = 0; + *listp = NULL; + + /* + * First, add up how much memory we need for the host names, excluding + * the local site. + */ + for (i = 0, count = 0, total_size = 0; i < db_rep->site_cnt; i++) { + site = &db_rep->sites[i]; + + if ((int)i == db_rep->self_eid || site->membership == 0) + continue; + + /* Make room for the NUL terminating byte. */ + total_size += strlen(site->net_addr.host) + 1; + count++; + } + if (count == 0) + goto err; + array_size = sizeof(DB_REPMGR_SITE) * count; + total_size += array_size; + + if ((ret = __os_umalloc(env, total_size, &status)) != 0) + goto err; + + /* + * Put the storage for the host names after the array of structs. This + * way, the caller can free the whole thing in one single operation. + */ + name = (char *)((u_int8_t *)status + array_size); + for (eid = 0, i = 0; eid < (int)db_rep->site_cnt; eid++) { + site = &db_rep->sites[eid]; + if (eid == db_rep->self_eid || site->membership == 0) + continue; + + /* If we don't have rep, we can't really know EID yet. */ + status[i].eid = rep ? eid : DB_EID_INVALID; + + status[i].host = name; + (void)strcpy(name, site->net_addr.host); + name += strlen(name) + 1; + + status[i].port = site->net_addr.port; + + status[i].flags = 0; + + if (FLD_ISSET(site->config, DB_REPMGR_PEER)) + F_SET(&status[i], DB_REPMGR_ISPEER); + + /* + * If we haven't started a communications thread, connection + * status is kind of meaningless. This distinction is useful + * for calls from the db_stat utility: it could be useful for + * db_stat to display known sites with EID; but would be + * confusing for it to display "disconnected" if another process + * does indeed have a connection established (db_stat can't know + * that). + */ + if (db_rep->selector == NULL) + status[i].status = 0; + else if (site->state != SITE_CONNECTED) + status[i].status = DB_REPMGR_DISCONNECTED; + else if ((site->ref.conn.in != NULL && + IS_READY_STATE(site->ref.conn.in->state)) || + (site->ref.conn.out != NULL && + IS_READY_STATE(site->ref.conn.out->state))) + status[i].status = DB_REPMGR_CONNECTED; + else + status[i].status = DB_REPMGR_DISCONNECTED; + + i++; + } + + *countp = count; + *listp = status; + +err: if (locked) + UNLOCK_MUTEX(db_rep->mutex); + return (ret); +} |