<!ENTITY pcpCommonOptions SYSTEM "pcp_common_options.sgml">
<!ENTITY pcpNodeCount SYSTEM "pcp_node_count.sgml">
<!ENTITY pcpNodeInfo SYSTEM "pcp_node_info.sgml">
+<!ENTITY pcpHealthCheckStats SYSTEM "pcp_health_check_stats.sgml">
<!ENTITY pcpWatchdogInfo SYSTEM "pcp_watchdog_info.sgml">
<!ENTITY pcpProcCount SYSTEM "pcp_proc_count.sgml">
<!ENTITY pcpProcInfo SYSTEM "pcp_proc_info.sgml">
--- /dev/null
+<!--
+doc/src/sgml/ref/pcp_health_check_stats.sgml
+Pgpool-II documentation
+-->
+
+<refentry id="PCP-HEALTH-CHECK-STATS">
+ <indexterm zone="pcp-health-check-stats">
+ <primary>pcp_health_check_stats</primary>
+ </indexterm>
+
+ <refmeta>
+ <refentrytitle>pcp_health_check_stats</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo>PCP Command</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>pcp_health_check_stats</refname>
+ <refpurpose>
+ 与えられたノードIDのヘルスチェック統計データを表示する
+ </refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>pcp_health_check_stats</command>
+ <arg rep="repeat"><replaceable>option</replaceable></arg>
+ <arg><replaceable>node_id</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="R1-PCP-HEALTH-CHECK-STATS-1">
+ <title>Description</title>
+ <para>
+ <command>pcp_health_check_stats</command>
+ 与えられたノードIDのヘルスチェック統計データを表示します。
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>オプション</title>
+ <para>
+ <variablelist>
+
+ <varlistentry>
+ <term><option>-n <replaceable class="parameter">node_id</replaceable></option></term>
+ <term><option>--node-id=<replaceable class="parameter">node_id</replaceable></option></term>
+ <listitem>
+ <para>
+ 情報を表示するバックエンドノードのインデックスを指定します。
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>その他のオプション</option></term>
+ <listitem>
+ <para>
+ <xref linkend="pcp-common-options"> を参照してください。
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>例</title>
+ <para>
+ 例を示します。
+ <programlisting>
+$ pcp_health_check_stats -h localhost -p 11001 -w 0
+0 /tmp 11002 up primary 2020-02-24 22:02:42 3 3 0 0 0 0.000000 0 5 1 3.666667 2020-02-24 22:02:47 2020-02-24 22:02:47
+$ pcp_health_check_stats -h localhost -p 11001 -w -v 0
+Node Id : 0
+Host Name : /tmp
+Port : 11002
+Status : up
+Role : primary
+Last Status Change : 2020-02-24 22:02:42
+Total Count : 5
+Success Count : 5
+Fail Count : 0
+Skip Count : 0
+Retry Count : 0
+Average Retry Count : 0.000000
+Max Retry Count : 0
+Max Health Check Duration : 5
+Minimum Health Check Duration : 1
+Average Health Check Duration : 4.200000
+Last Health Check : 2020-02-24 22:03:07
+Last Successful Health Check : 2020-02-24 22:03:07
+Last Skip Health Check :
+Last Failed Health Check :
+ </programlisting>
+ </para>
+
+ <para>
+ 表示データの詳細に関しては<xref linkend="health-check-stats-data-table">をご覧ください。
+ </para>
+ </refsect1>
+
+</refentry>
&pcpCommonOptions;
&pcpNodeCount;
&pcpNodeInfo;
+ &pcpHealthCheckStats;
&pcpWatchdogInfo;
&pcpProcCount;
&pcpProcInfo;
<!ENTITY pcpCommonOptions SYSTEM "pcp_common_options.sgml">
<!ENTITY pcpNodeCount SYSTEM "pcp_node_count.sgml">
<!ENTITY pcpNodeInfo SYSTEM "pcp_node_info.sgml">
+<!ENTITY pcpHealthCheckStats SYSTEM "pcp_health_check_stats.sgml">
<!ENTITY pcpWatchdogInfo SYSTEM "pcp_watchdog_info.sgml">
<!ENTITY pcpProcCount SYSTEM "pcp_proc_count.sgml">
<!ENTITY pcpProcInfo SYSTEM "pcp_proc_info.sgml">
--- /dev/null
+<!--
+doc/src/sgml/ref/pcp_health_check_stats.sgml
+Pgpool-II documentation
+-->
+
+<refentry id="PCP-HEALTH-CHECK-STATS">
+ <indexterm zone="pcp-health-check-stats">
+ <primary>pcp_health_check_stats</primary>
+ </indexterm>
+
+ <refmeta>
+ <refentrytitle>pcp_health_check_stats</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo>PCP Command</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>pcp_health_check_stats</refname>
+ <refpurpose>
+ displays health check statistics data on given node ID</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>pcp_health_check_stats</command>
+ <arg rep="repeat"><replaceable>option</replaceable></arg>
+ <arg><replaceable>node_id</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="R1-PCP-HEALTH-CHECK-STATS-1">
+ <title>Description</title>
+ <para>
+ <command>pcp_health_check_stats</command>
+ displays health check statistics data on given node ID.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+ <para>
+ <variablelist>
+
+ <varlistentry>
+ <term><option>-n <replaceable class="parameter">node_id</replaceable></option></term>
+ <term><option>--node-id=<replaceable class="parameter">node_id</replaceable></option></term>
+ <listitem>
+ <para>
+ The index of backend node to get information of.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>Other options </option></term>
+ <listitem>
+ <para>
+ See <xref linkend="pcp-common-options">.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Example</title>
+ <para>
+ Here is an example output:
+ <programlisting>
+$ pcp_health_check_stats -h localhost -p 11001 -w 0
+0 /tmp 11002 up primary 2020-02-24 22:02:42 3 3 0 0 0 0.000000 0 5 1 3.666667 2020-02-24 22:02:47 2020-02-24 22:02:47
+$ pcp_health_check_stats -h localhost -p 11001 -w -v 0
+Node Id : 0
+Host Name : /tmp
+Port : 11002
+Status : up
+Role : primary
+Last Status Change : 2020-02-24 22:02:42
+Total Count : 5
+Success Count : 5
+Fail Count : 0
+Skip Count : 0
+Retry Count : 0
+Average Retry Count : 0.000000
+Max Retry Count : 0
+Max Health Check Duration : 5
+Minimum Health Check Duration : 1
+Average Health Check Duration : 4.200000
+Last Health Check : 2020-02-24 22:03:07
+Last Successful Health Check : 2020-02-24 22:03:07
+Last Skip Health Check :
+Last Failed Health Check :
+ </programlisting>
+ </para>
+
+ <para>
+ See <xref linkend="health-check-stats-data-table"> for details of data.
+ </para>
+ </refsect1>
+
+</refentry>
&pcpCommonOptions;
&pcpNodeCount;
&pcpNodeInfo;
+ &pcpHealthCheckStats;
&pcpWatchdogInfo;
&pcpProcCount;
&pcpProcInfo;
utils/base64.c \
utils/sha2.c \
utils/ssl_utils.c \
- utils/statistics.c
+ utils/statistics.c \
+ utils/pool_health_check_stats.c
DEFS = @DEFS@ \
-DDEFAULT_CONFIGDIR=\"$(sysconfdir)\" \
extern PCPResultInfo * pcp_terminate_pgpool(PCPConnInfo * pcpCon, char mode);
extern PCPResultInfo * pcp_node_count(PCPConnInfo * pcpCon);
extern PCPResultInfo * pcp_node_info(PCPConnInfo * pcpCon, int nid);
-
+extern PCPResultInfo * pcp_health_check_stats(PCPConnInfo * pcpCon, int nid);
extern PCPResultInfo * pcp_process_count(PCPConnInfo * pcpConn);
extern PCPResultInfo * pcp_process_info(PCPConnInfo * pcpConn, int pid);
extern char *role_to_str(SERVER_ROLE role);
+extern int * pool_health_check_stats_offsets(int *n);
+
/* ------------------------------
* pcp_error.c
* ------------------------------
../../utils/pool_path.c \
../../tools/fe_port.c \
../../tools/fe_memutils.c \
- ../../utils/strlcpy.c
+ ../../utils/strlcpy.c \
+ ../../utils/pool_health_check_stats.c
nodist_libpcp_la_SOURCES = pcp_stream.c \
md5.c \
json.c
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2019 PgPool Global Development Group
+ * Copyright (c) 2003-2020 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
static void setResultIntData(PCPResultInfo * res, unsigned int slotno, int value);
static void process_node_info_response(PCPConnInfo * pcpConn, char *buf, int len);
+static void process_health_check_stats_response(PCPConnInfo * pcpConn, char *buf, int len);
static void process_command_complete_response(PCPConnInfo * pcpConn, char *buf, int len);
static void process_watchdog_info_response(PCPConnInfo * pcpConn, char *buf, int len);
static void process_process_info_response(PCPConnInfo * pcpConn, char *buf, int len);
setResultStatus(pcpConn, PCP_RES_ERROR);
return pcpConn->pcpResInfo;
}
+
if (pcp_read(pcpConn->pcpConn, &rsize, sizeof(int)))
{
pcp_internal_error(pcpConn,
process_node_info_response(pcpConn, buf, rsize);
break;
+ case 'h':
+ if (sentMsg != 'H')
+ setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
+ else
+ process_health_check_stats_response(pcpConn, buf, rsize);
+ break;
+
case 'l':
if (sentMsg != 'L')
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
return process_pcp_response(pcpConn, 'I');
}
+
+/* --------------------------------
+ * pcp_health_check_stats - get information of health check stats pointed by given argument
+ *
+ * return structure of node information on success, -1 otherwise
+ * --------------------------------
+ */
+PCPResultInfo *
+pcp_health_check_stats(PCPConnInfo * pcpConn, int nid)
+{
+ int wsize;
+ char node_id[16];
+
+ if (PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
+ {
+ pcp_internal_error(pcpConn,
+ "invalid PCP connection");
+ return NULL;
+ }
+
+ snprintf(node_id, sizeof(node_id), "%d", nid);
+
+ pcp_write(pcpConn->pcpConn, "H", 1);
+ wsize = htonl(strlen(node_id) + 1 + sizeof(int));
+ pcp_write(pcpConn->pcpConn, &wsize, sizeof(int));
+ pcp_write(pcpConn->pcpConn, node_id, strlen(node_id) + 1);
+ if (PCPFlush(pcpConn) < 0)
+ return NULL;
+ if (pcpConn->Pfdebug)
+ fprintf(pcpConn->Pfdebug, "DEBUG: send: tos=\"L\", len=%d\n", ntohl(wsize));
+
+ return process_pcp_response(pcpConn, 'H');
+}
+
+/*
+ * Process health check response from PCP server.
+ * pcpConn: connection to the server
+ * buf: returned data from server
+ * len: length of the data
+ */
+static void
+process_health_check_stats_response
+(PCPConnInfo * pcpConn, char *buf, int len)
+{
+ POOL_HEALTH_CHECK_STATS *stats;
+ int *offsets;
+ int n;
+ int i;
+ char *p;
+ int maxstr;
+ char c[] = "CommandComplete";
+
+ if (strcmp(buf, c) != 0)
+ {
+ pcp_internal_error(pcpConn,
+ "command failed. invalid response");
+ setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
+ return;
+ }
+ buf += sizeof(c);
+
+ /* Allocate health stats memory */
+ stats = palloc0(sizeof(POOL_HEALTH_CHECK_STATS));
+ p = (char *)stats;
+
+ /* Calculate total packet length */
+ offsets = pool_health_check_stats_offsets(&n);
+
+ for (i = 0; i < n; i++)
+ {
+ if (i == n -1)
+ maxstr = sizeof(POOL_HEALTH_CHECK_STATS) - offsets[i];
+ else
+ maxstr = offsets[i + 1] - offsets[i];
+
+ StrNCpy(p + offsets[i], buf, maxstr -1);
+ buf += strlen(buf) + 1;
+ }
+
+ if (setNextResultBinaryData(pcpConn->pcpResInfo, (void *) stats, sizeof(POOL_HEALTH_CHECK_STATS), NULL) < 0)
+ {
+ if (stats)
+ pfree(stats);
+ pcp_internal_error(pcpConn,
+ "command failed. invalid response");
+ setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
+ }
+ else
+ setCommandSuccessful(pcpConn);
+
+}
+
static void
process_process_count_response(PCPConnInfo * pcpConn, char *buf, int len)
{
--- /dev/null
+How to add new PCP protocol
+
+src/pcp_con/pcp_worker.c is the server side process. We use "health
+check stats" as an example.
+
+1. In pcp_process_command() add case statement dedicated for each
+protocol. Typically server side protocol is indicated by single ASCII
+character (in the example 'H'). In the case statement,
+set_ps_display() is called to show what the PCP server is doing. Then
+"inform_xxx" function (in the example inform_health_check_stats) is
+called. this function is responsible for creating packet and sends to
+PCP frontend. The parameter is "pcp_frontend" which is the conection
+object to the PCP frontend and "buf" which includes data send from the
+PCP client.
+
+2. inform_xxx
+
+In inform_xxx (in the example inform_health_check_stats), first parse
+the data sent from client. In this particular example it's the backend
+id which should be used to create packet data.
+
+In the function first send character indicating the protocol using
+pcp_write(). Usually the character is lower case of the server side
+protocol character (in the example 'h').
+
+Next send an 4 byte integer representing the packet length in network
+byte order. Note that the length includes the interger itself.
+
+Finally send the protocol body followed by do_pcp_flush() which flush
+out the internal network write buffer.
+
+3. client side
+
+The main source code is src/tools/pcp/pcp_frontend_client.c.
+
+- output_xxx function needs to be defined.
+
+- add PCP_HEALTH_CHECK_STATS to enum PCP_UTILITIES.
+
+- add command name "pcp_health_check_stats" to struct AppTypes AllAppTypes[].
+
+- add "else if" below
+ /*
+ * Okay the connection is successful not call the actual PCP function
+ */
+ if (current_app_type->app_type == PCP_ATTACH_NODE)
+
+- add call to the output_xxx function.
+
+ if (current_app_type->app_type == PCP_HEALTH_CHECK_STATS)
+ output_health_check_stats_result(pcpResInfo, verbose);
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2019 PgPool Global Development Group
+ * Copyright (c) 2003-2020 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
static void inform_watchdog_info(PCP_CONNECTION * frontend, char *buf);
static void inform_node_info(PCP_CONNECTION * frontend, char *buf);
static void inform_node_count(PCP_CONNECTION * frontend);
+static void inform_health_check_stats(PCP_CONNECTION *frontend, char *buf);
static void process_detach_node(PCP_CONNECTION * frontend, char *buf, char tos);
static void process_attach_node(PCP_CONNECTION * frontend, char *buf);
static void process_recovery_request(PCP_CONNECTION * frontend, char *buf);
static void
pcp_process_command(char tos, char *buf, int buf_len)
{
-
if (tos == 'O' || tos == 'T')
{
if (Req_info->switching)
inform_node_count(pcp_frontend);
break;
+ case 'H': /* health check stats */
+ set_ps_display("PCP: processing health check stats request", false);
+ inform_health_check_stats(pcp_frontend, buf);
+ break;
+
case 'I': /* node info */
set_ps_display("PCP: processing node info request", false);
inform_node_info(pcp_frontend, buf);
do_pcp_flush(frontend);
}
+/*
+ * Send out health check stats data to pcp client. node id is provided as a
+ * string in buf parameter.
+ *
+ * The protocol starts with 'h', followed by 4-byte packet length integer in
+ * network byte order including self. Each data is represented as a null
+ * terminted string. The order of each data is defined in
+ * POOL_HEALTH_CHECK_STATS struct.
+ */
+static void
+inform_health_check_stats(PCP_CONNECTION *frontend, char *buf)
+{
+ POOL_HEALTH_CHECK_STATS *stats;
+ POOL_HEALTH_CHECK_STATS *s;
+ int *offsets;
+ int n;
+ int nrows;
+ int i;
+ int node_id;
+ bool node_id_ok = false;
+ int wsize;
+ char code[] = "CommandComplete";
+
+ node_id = atoi(buf);
+
+ if (node_id < 0 || node_id > NUM_BACKENDS)
+ {
+ ereport(ERROR,
+ (errmsg("informing health check stats info failed"),
+ errdetail("invalid node ID %d", node_id)));
+ }
+
+ stats = get_health_check_stats(&nrows);
+
+ for (i = 0; i < nrows; i++)
+ {
+ if (atoi(stats[i].node_id) == node_id)
+ {
+ node_id_ok = true;
+ s = &stats[i];
+ break;
+ }
+ }
+
+ if (!node_id_ok)
+ {
+ ereport(ERROR,
+ (errmsg("informing health check stats info failed"),
+ errdetail("stats data for node ID %d does not exist", node_id)));
+ }
+
+ pcp_write(frontend, "h", 1); /* indicate that this is a reply to health check stats request */
+
+ wsize = sizeof(code) + sizeof(int);
+
+ /* Calculate total packet length */
+ offsets = pool_health_check_stats_offsets(&n);
+
+ for (i = 0; i < n; i++)
+ {
+ wsize += strlen((char *)s + offsets[i]) + 1;
+ }
+ wsize = htonl(wsize); /* convert to network byte order */
+
+ /* send packet length to frontend */
+ pcp_write(frontend, &wsize, sizeof(int));
+ /* send "Command Complete" to frontend */
+ pcp_write(frontend, code, sizeof(code));
+
+ /* send each health check stats data to frontend */
+ for (i = 0; i < n; i++)
+ {
+ pcp_write(frontend, (char *)s + offsets[i], strlen((char *)s + offsets[i]) + 1);
+ }
+ pfree(stats);
+ do_pcp_flush(frontend);
+}
+
static void
inform_node_count(PCP_CONNECTION * frontend)
{
bin_PROGRAMS = pcp_stop_pgpool \
pcp_node_count \
pcp_node_info \
+ pcp_health_check_stats \
pcp_proc_count \
pcp_proc_info \
pcp_detach_node \
pcp_node_count_SOURCES = $(client_sources)
pcp_node_count_LDADD = $(libs_dir)/pcp/libpcp.la
pcp_node_info_SOURCES = $(client_sources)
+pcp_health_check_stats_LDADD = $(libs_dir)/pcp/libpcp.la
+pcp_health_check_stats_SOURCES = $(client_sources) ../../utils/pool_health_check_stats.c
pcp_node_info_LDADD = $(libs_dir)/pcp/libpcp.la
pcp_proc_count_SOURCES = $(client_sources)
pcp_proc_count_LDADD = $(libs_dir)/pcp/libpcp.la
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2019 PgPool Global Development Group
+ * Copyright (c) 2003-2020 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
static void output_proccount_result(PCPResultInfo * pcpResInfo, bool verbose);
static void output_poolstatus_result(PCPResultInfo * pcpResInfo, bool verbose);
static void output_nodeinfo_result(PCPResultInfo * pcpResInfo, bool verbose);
+static void output_health_check_stats_result(PCPResultInfo * pcpResInfo, bool verbose);
static void output_nodecount_result(PCPResultInfo * pcpResInfo, bool verbose);
static char *backend_status_to_string(BackendInfo * bi);
static char *format_titles(const char **titles, const char **types, int ntitles);
PCP_DETACH_NODE,
PCP_NODE_COUNT,
PCP_NODE_INFO,
+ PCP_HEALTH_CHECK_STATS,
PCP_POOL_STATUS,
PCP_PROC_COUNT,
PCP_PROC_INFO,
{"pcp_detach_node", PCP_DETACH_NODE, "n:h:p:U:gwWvd", "detach a node from pgpool-II"},
{"pcp_node_count", PCP_NODE_COUNT, "h:p:U:wWvd", "display the total number of nodes under pgpool-II's control"},
{"pcp_node_info", PCP_NODE_INFO, "n:h:p:U:wWvd", "display a pgpool-II node's information"},
+ {"pcp_health_check_stats", PCP_HEALTH_CHECK_STATS, "n:h:p:U:wWvd", "display a pgpool-II health check stats data"},
{"pcp_pool_status", PCP_POOL_STATUS, "h:p:U:wWvd", "display pgpool configuration and status"},
{"pcp_proc_count", PCP_PROC_COUNT, "h:p:U:wWvd", "display the list of pgpool-II child process PIDs"},
{"pcp_proc_info", PCP_PROC_INFO, "h:p:P:U:awWvd", "display a pgpool-II child process' information"},
pcpResInfo = pcp_node_info(pcpConn, nodeID);
}
+ else if (current_app_type->app_type == PCP_HEALTH_CHECK_STATS)
+ {
+ pcpResInfo = pcp_health_check_stats(pcpConn, nodeID);
+ }
+
else if (current_app_type->app_type == PCP_POOL_STATUS)
{
pcpResInfo = pcp_pool_status(pcpConn);
if (current_app_type->app_type == PCP_NODE_INFO)
output_nodeinfo_result(pcpResInfo, verbose);
+ if (current_app_type->app_type == PCP_HEALTH_CHECK_STATS)
+ output_health_check_stats_result(pcpResInfo, verbose);
+
if (current_app_type->app_type == PCP_POOL_STATUS)
output_poolstatus_result(pcpResInfo, verbose);
}
}
+/*
+ * Format and output health check stats
+ */
+static void
+output_health_check_stats_result(PCPResultInfo * pcpResInfo, bool verbose)
+{
+ POOL_HEALTH_CHECK_STATS *stats = (POOL_HEALTH_CHECK_STATS *)pcp_get_binary_data(pcpResInfo, 0);
+
+ if (verbose)
+ {
+ const char *titles[] = {"Node Id", "Host Name", "Port", "Status", "Role", "Last Status Change",
+ "Total Count", "Success Count", "Fail Count", "Skip Count", "Retry Count",
+ "Average Retry Count", "Max Retry Count", "Max Health Check Duration",
+ "Minimum Health Check Duration", "Average Health Check Duration",
+ "Last Health Check", "Last Successful Health Check",
+ "Last Skip Health Check", "Last Failed Health Check"};
+ const char *types[] = {"s", "s", "s", "s", "s", "s", "s", "s", "s", "s",
+ "s", "s", "s", "s", "s", "s", "s", "s", "s", "s"};
+ char *format_string;
+
+ format_string = format_titles(titles, types, sizeof(titles)/sizeof(char *));
+ printf(format_string,
+ stats->node_id,
+ stats->hostname,
+ stats->port,
+ stats->status,
+ stats->role,
+ stats->last_status_change,
+ stats->total_count,
+ stats->success_count,
+ stats->fail_count,
+ stats->skip_count,
+ stats->retry_count,
+ stats->average_retry_count,
+ stats->max_retry_count,
+ stats->max_health_check_duration,
+ stats->min_health_check_duration,
+ stats->average_health_check_duration,
+ stats->last_health_check,
+ stats->last_successful_health_check,
+ stats->last_skip_health_check,
+ stats->last_failed_health_check);
+ }
+ else
+ {
+ printf("%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n",
+ stats->node_id,
+ stats->hostname,
+ stats->port,
+ stats->status,
+ stats->role,
+ stats->last_status_change,
+ stats->total_count,
+ stats->success_count,
+ stats->fail_count,
+ stats->skip_count,
+ stats->retry_count,
+ stats->average_retry_count,
+ stats->max_retry_count,
+ stats->max_health_check_duration,
+ stats->min_health_check_duration,
+ stats->average_health_check_duration,
+ stats->last_health_check,
+ stats->last_successful_health_check,
+ stats->last_skip_health_check,
+ stats->last_failed_health_check);
+ }
+}
+
static void
output_poolstatus_result(PCPResultInfo * pcpResInfo, bool verbose)
{
return (current_app_type->app_type == PCP_ATTACH_NODE ||
current_app_type->app_type == PCP_DETACH_NODE ||
current_app_type->app_type == PCP_NODE_INFO ||
+ current_app_type->app_type == PCP_HEALTH_CHECK_STATS ||
current_app_type->app_type == PCP_PROMOTE_NODE ||
current_app_type->app_type == PCP_RECOVERY_NODE);
}
--- /dev/null
+/*
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL
+ * written by Tatsuo Ishii
+ *
+ * Copyright (c) 2003-2020 PgPool Global Development Group
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ */
+
+#include <stddef.h>
+#include "pool.h"
+#include "pcp/libpcp_ext.h"
+
+/*
+ * Returns an array consisting of POOL_HEALTH_CHECK_STATS struct member
+ * offsets. The reason why we have this as a function is the table data needs
+ * to be shared by both PCP server and clients.
+ * Number of struct members will be stored in *n.
+ */
+int * pool_health_check_stats_offsets(int *n)
+{
+ static int offsettbl[] = {
+ offsetof(POOL_HEALTH_CHECK_STATS, node_id),
+ offsetof(POOL_HEALTH_CHECK_STATS, hostname),
+ offsetof(POOL_HEALTH_CHECK_STATS, port),
+ offsetof(POOL_HEALTH_CHECK_STATS, status),
+ offsetof(POOL_HEALTH_CHECK_STATS, role),
+ offsetof(POOL_HEALTH_CHECK_STATS, last_status_change),
+ offsetof(POOL_HEALTH_CHECK_STATS, total_count),
+ offsetof(POOL_HEALTH_CHECK_STATS, success_count),
+ offsetof(POOL_HEALTH_CHECK_STATS, fail_count),
+ offsetof(POOL_HEALTH_CHECK_STATS, skip_count),
+ offsetof(POOL_HEALTH_CHECK_STATS, retry_count),
+ offsetof(POOL_HEALTH_CHECK_STATS, average_retry_count),
+ offsetof(POOL_HEALTH_CHECK_STATS, max_retry_count),
+ offsetof(POOL_HEALTH_CHECK_STATS, max_health_check_duration),
+ offsetof(POOL_HEALTH_CHECK_STATS, min_health_check_duration),
+ offsetof(POOL_HEALTH_CHECK_STATS, average_health_check_duration),
+ offsetof(POOL_HEALTH_CHECK_STATS, last_health_check),
+ offsetof(POOL_HEALTH_CHECK_STATS, last_successful_health_check),
+ offsetof(POOL_HEALTH_CHECK_STATS, last_skip_health_check),
+ offsetof(POOL_HEALTH_CHECK_STATS, last_failed_health_check),
+ };
+
+ *n = sizeof(offsettbl)/sizeof(int);
+ return offsettbl;
+}
int i;
POOL_HEALTH_CHECK_STATS *stats = palloc0(NUM_BACKENDS * sizeof(POOL_HEALTH_CHECK_STATS));
BackendInfo *bi = NULL;
- struct tm tm;
time_t t;
double f;
}
/* status last changed */
- localtime_r(&bi->status_changed_time, &tm);
- strftime(stats[i].last_status_change, POOLCONFIG_MAXDATELEN, "%F %T", &tm);
+ t = bi->status_changed_time;
+ ereport(LOG,(errmsg("status_changed_time %ld", t)));
+ strftime(stats[i].last_status_change, POOLCONFIG_MAXDATELEN, "%F %T", localtime(&t));
snprintf(stats[i].total_count, POOLCONFIG_MAXLONGCOUNTLEN, UINT64_FORMAT, health_check_stats[i].total_count);
snprintf(stats[i].success_count, POOLCONFIG_MAXLONGCOUNTLEN, UINT64_FORMAT, health_check_stats[i].success_count);