diff --git a/src/include/pcp/libpcp_ext.h b/src/include/pcp/libpcp_ext.h index 179f15ab..addab914 100644 --- a/src/include/pcp/libpcp_ext.h +++ b/src/include/pcp/libpcp_ext.h @@ -319,6 +319,7 @@ 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 PCPResultInfo * pcp_reload_config(PCPConnInfo * pcpConn,char command_scope); extern PCPResultInfo * pcp_detach_node(PCPConnInfo * pcpConn, int nid); extern PCPResultInfo * pcp_detach_node_gracefully(PCPConnInfo * pcpConn, int nid); diff --git a/src/include/watchdog/wd_ipc_defines.h b/src/include/watchdog/wd_ipc_defines.h index 74f9b85c..b7ccb786 100644 --- a/src/include/watchdog/wd_ipc_defines.h +++ b/src/include/watchdog/wd_ipc_defines.h @@ -74,6 +74,7 @@ typedef enum WDValueDataType #define WD_COMMAND_RESTART_CLUSTER "RESTART_CLUSTER" #define WD_COMMAND_REELECT_MASTER "REELECT_MASTER" #define WD_COMMAND_SHUTDOWN_CLUSTER "SHUTDOWN_CLUSTER" +#define WD_COMMAND_RELOAD_CONFIG_CLUSTER "RELOAD_CONFIG_CLUSTER" #define WD_FUNCTION_START_RECOVERY "START_RECOVERY" diff --git a/src/libs/pcp/pcp.c b/src/libs/pcp/pcp.c index 0e25ff84..865dd029 100644 --- a/src/libs/pcp/pcp.c +++ b/src/libs/pcp/pcp.c @@ -470,6 +470,13 @@ static PCPResultInfo * process_pcp_response(PCPConnInfo * pcpConn, char sentMsg) process_command_complete_response(pcpConn, buf, rsize); break; + case 'z': + if (sentMsg != 'Z') + setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE); + else + process_command_complete_response(pcpConn, buf, rsize); + break; + case 'w': if (sentMsg != 'W') setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE); @@ -853,6 +860,33 @@ pcp_health_check_stats(PCPConnInfo * pcpConn, int nid) return process_pcp_response(pcpConn, 'H'); } +PCPResultInfo * +pcp_reload_config(PCPConnInfo * pcpConn,char command_scope) +{ + int wsize; +/* + * pcp packet format for pcp_reload_config + * z[size][commmand_scope] + */ + if (PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK) + { + pcp_internal_error(pcpConn, "invalid PCP connection"); + return NULL; + } + + pcp_write(pcpConn->pcpConn, "Z", 1); + wsize = htonl(sizeof(int) + sizeof(char)); + pcp_write(pcpConn->pcpConn, &wsize, sizeof(int)); + pcp_write(pcpConn->pcpConn, &command_scope, sizeof(char)); + if (PCPFlush(pcpConn) < 0) + return NULL; + if (pcpConn->Pfdebug) + fprintf(pcpConn->Pfdebug, "DEBUG: send: tos=\"Z\", len=%d\n", ntohl(wsize)); + + return process_pcp_response(pcpConn, 'Z'); +} + + /* * Process health check response from PCP server. * pcpConn: connection to the server diff --git a/src/pcp_con/pcp_worker.c b/src/pcp_con/pcp_worker.c index c547d2a7..775bc953 100644 --- a/src/pcp_con/pcp_worker.c +++ b/src/pcp_con/pcp_worker.c @@ -81,6 +81,7 @@ static void inform_process_info(PCP_CONNECTION * frontend, char *buf); 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 process_reload_config(PCP_CONNECTION * frontend,char scope); 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); @@ -319,6 +320,11 @@ pcp_process_command(char tos, char *buf, int buf_len) process_status_request(pcp_frontend); break; + case 'Z': /*reload config file */ + set_ps_display("PCP: processing reload config request", false); + process_reload_config(pcp_frontend, buf[0]); + break; + case 'J': /* promote node */ case 'j': /* promote node gracefully */ set_ps_display("PCP: processing promote node request", false); @@ -1005,6 +1011,36 @@ inform_node_count(PCP_CONNECTION * frontend) (errmsg("PCP: informing node count"), errdetail("%d node(s) found", node_count))); } +static void +process_reload_config(PCP_CONNECTION * frontend, char scope) +{ + char code[] = "CommandComplete"; + int wsize; + + if (scope == 'c' && pool_config->use_watchdog) + { + ereport(LOG, + (errmsg("PCP: sending command to watchdog to reload config cluster"))); + + if (wd_execute_cluster_command(WD_COMMAND_RELOAD_CONFIG_CLUSTER,0, NULL) != COMMAND_OK) + ereport(ERROR, + (errmsg("PCP: error while processing reload config request for cluster"), + errdetail("failed to propogate reload config command through watchdog"))); + } + + if(pool_signal_parent(SIGHUP) == -1) + { + ereport(ERROR, + (errmsg("process reload config request failed"), + errdetail("failed to signal pgpool parent process"))); + } + + pcp_write(frontend, "z", 1); + wsize = htonl(sizeof(code) + sizeof(int)); + pcp_write(frontend, &wsize, sizeof(int)); + pcp_write(frontend, code, sizeof(code)); + do_pcp_flush(frontend); +} static void process_detach_node(PCP_CONNECTION * frontend, char *buf, char tos) diff --git a/src/tools/pcp/Makefile.am b/src/tools/pcp/Makefile.am index 4c4a063d..a0942f48 100644 --- a/src/tools/pcp/Makefile.am +++ b/src/tools/pcp/Makefile.am @@ -12,7 +12,8 @@ bin_PROGRAMS = pcp_stop_pgpool \ pcp_recovery_node \ pcp_promote_node \ pcp_pool_status \ - pcp_watchdog_info + pcp_watchdog_info\ + pcp_reload_config client_sources = pcp_frontend_client.c ../fe_memutils.c ../../utils/sprompt.c ../../utils/pool_path.c @@ -40,4 +41,6 @@ pcp_promote_node_SOURCES = $(client_sources) pcp_promote_node_LDADD = $(libs_dir)/pcp/libpcp.la pcp_watchdog_info_SOURCES = $(client_sources) pcp_watchdog_info_LDADD = $(libs_dir)/pcp/libpcp.la +pcp_reload_config_SOURCES = $(client_sources) +pcp_reload_config_LDADD = $(libs_dir)/pcp/libpcp.la diff --git a/src/tools/pcp/pcp_frontend_client.c b/src/tools/pcp/pcp_frontend_client.c index 6637d249..a992026c 100644 --- a/src/tools/pcp/pcp_frontend_client.c +++ b/src/tools/pcp/pcp_frontend_client.c @@ -43,6 +43,7 @@ char *last_dir_separator(const char *filename); static void usage(void); static inline bool app_require_nodeID(void); +static inline bool app_support_cluster_mode(void); static void output_watchdog_info_result(PCPResultInfo * pcpResInfo, bool verbose); static void output_procinfo_result(PCPResultInfo * pcpResInfo, bool all, bool verbose); static void output_proccount_result(PCPResultInfo * pcpResInfo, bool verbose); @@ -67,6 +68,7 @@ typedef enum PCP_RECOVERY_NODE, PCP_STOP_PGPOOL, PCP_WATCHDOG_INFO, + PCP_RELOAD_CONFIG, UNKNOWN, } PCP_UTILITIES; @@ -92,6 +94,7 @@ struct AppTypes AllAppTypes[] = {"pcp_recovery_node", PCP_RECOVERY_NODE, "n:h:p:U:wWvd", "recover a node"}, {"pcp_stop_pgpool", PCP_STOP_PGPOOL, "m:h:p:U:s:wWvda", "terminate pgpool-II"}, {"pcp_watchdog_info", PCP_WATCHDOG_INFO, "n:h:p:U:wWvd", "display a pgpool-II watchdog's information"}, + {"pcp_reload_config",PCP_RELOAD_CONFIG,"h:p:U:s:wWvd", "reload a pgpool-II config file"}, {NULL, UNKNOWN, NULL, NULL}, }; struct AppTypes *current_app_type; @@ -196,7 +199,7 @@ main(int argc, char **argv) break; case 's': - if (current_app_type->app_type == PCP_STOP_PGPOOL) + if (app_support_cluster_mode()) { if (strcmp(optarg, "c") == 0 || strcmp(optarg, "cluster") == 0) command_scope = 'c'; @@ -434,6 +437,11 @@ main(int argc, char **argv) pcpResInfo = pcp_watchdog_info(pcpConn, nodeID); } + else if (current_app_type->app_type == PCP_RELOAD_CONFIG) + { + pcpResInfo = pcp_reload_config(pcpConn,command_scope); + } + else { /* should never happen */ @@ -808,6 +816,12 @@ app_require_nodeID(void) current_app_type->app_type == PCP_RECOVERY_NODE); } +static inline bool +app_support_cluster_mode(void) +{ + return (current_app_type->app_type == PCP_STOP_PGPOOL || + current_app_type->app_type == PCP_RELOAD_CONFIG); +} static void usage(void) @@ -837,13 +851,16 @@ usage(void) { fprintf(stderr, " -n, --node-id=NODEID ID of a backend node\n"); } - if (current_app_type->app_type == PCP_STOP_PGPOOL) { fprintf(stderr, " -m, --mode=MODE MODE can be \"smart\", \"fast\", or \"immediate\"\n"); + } + + if (app_support_cluster_mode()) + { fprintf(stderr, " -s, --scope=SCOPE SCOPE can be \"cluster\", or \"local\"\n"); - fprintf(stderr, " cluster scope terminates all Pgpool-II nodes part\n"); - fprintf(stderr, " of the watchdog cluster\n"); + fprintf(stderr, " cluster scope do operations on all Pgpool-II nodes\n"); + fprintf(stderr, " part of the watchdog cluster\n"); } if (current_app_type->app_type == PCP_PROMOTE_NODE || current_app_type->app_type == PCP_DETACH_NODE) diff --git a/src/watchdog/watchdog.c b/src/watchdog/watchdog.c index f13e7632..1e15bb1c 100644 --- a/src/watchdog/watchdog.c +++ b/src/watchdog/watchdog.c @@ -2049,6 +2049,11 @@ process_IPC_execute_cluster_command(WDCommandData * ipcCommand) ereport(LOG, (errmsg("Watchdog has received shutdown cluster command from IPC channel"))); } + else if (strcasecmp(WD_COMMAND_RELOAD_CONFIG_CLUSTER, clusterCommand) == 0) + { + ereport(LOG, + (errmsg("Watchdog has received reload config cluster command from IPC channel"))); + } else { ipcCommand->errorMessage = MemoryContextStrdup(ipcCommand->memoryContext, @@ -4033,6 +4038,12 @@ wd_execute_cluster_command_processor(WatchdogNode * wdNode, WDPacketData * pkt) (errmsg("processing shutdown command from remote node \"%s\"", wdNode->nodeName))); terminate_pgpool(mode, false); } + else if (strcasecmp(WD_COMMAND_RELOAD_CONFIG_CLUSTER, clusterCommand) == 0) + { + ereport(LOG, + (errmsg("processing reload config command from remote node \"%s\"", wdNode->nodeName))); + pool_signal_parent(SIGHUP); + } else { ereport(WARNING, diff --git a/src/watchdog/wd_json_data.c b/src/watchdog/wd_json_data.c index 3d60bd9e..faff82ed 100644 --- a/src/watchdog/wd_json_data.c +++ b/src/watchdog/wd_json_data.c @@ -825,15 +825,19 @@ get_wd_exec_cluster_command_json(char *clusterCommand, int nArgs, jw_put_int(jNode, "nArgs", nArgs); /* Array of arguments */ - jw_start_array(jNode, "argument_list"); - for (i = 0; i < nArgs; i++) + if(nArgs > 0) { - jw_start_object(jNode, "Arg"); - jw_put_string(jNode, "arg_name", wdExecCommandArg[i].arg_name); - jw_put_string(jNode, "arg_value", wdExecCommandArg[i].arg_value); - jw_end_element(jNode); + jw_start_array(jNode, "argument_list"); + for (i = 0; i < nArgs; i++) + { + jw_start_object(jNode, "Arg"); + jw_put_string(jNode, "arg_name", wdExecCommandArg[i].arg_name); + jw_put_string(jNode, "arg_value", wdExecCommandArg[i].arg_value); + jw_end_element(jNode); + } + jw_end_element(jNode); /* argument_list array End */ } - jw_end_element(jNode); /* argument_list array End */ + jw_finish_document(jNode); json_str = pstrdup(jw_get_json_string(jNode));