1 /*
2  *
3  * wd_escalation
4  *
5  * pgpool: a language independent connection pool server for PostgreSQL
6  * written by Tatsuo Ishii
7  *
8  * Copyright (c) 2003-2015	PgPool Global Development Group
9  *
10  * Permission to use, copy, modify, and distribute this software and
11  * its documentation for any purpose and without fee is hereby
12  * granted, provided that the above copyright notice appear in all
13  * copies and that both that copyright notice and this permission
14  * notice appear in supporting documentation, and that the name of the
15  * author not be used in advertising or publicity pertaining to
16  * distribution of the software without specific, written prior
17  * permission. The author makes no representations about the
18  * suitability of this software for any purpose.  It is provided "as
19  * is" without express or implied warranty.
20  *
21  */
22 
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <errno.h>
29 
30 #ifdef __FreeBSD__
31 #include <sys/wait.h>
32 #endif
33 
34 #include "pool.h"
35 #include "utils/elog.h"
36 #include "utils/palloc.h"
37 #include "utils/memutils.h"
38 #include "pool_config.h"
39 #include "watchdog/wd_utils.h"
40 
41 #include "query_cache/pool_memqcache.h"
42 
43 static void
wd_exit(int exit_signo)44 wd_exit(int exit_signo)
45 {
46 	sigset_t	mask;
47 
48 	sigemptyset(&mask);
49 	sigaddset(&mask, SIGTERM);
50 	sigaddset(&mask, SIGINT);
51 	sigaddset(&mask, SIGQUIT);
52 	sigaddset(&mask, SIGCHLD);
53 	sigprocmask(SIG_BLOCK, &mask, NULL);
54 
55 	exit(0);
56 }
57 
58 /*
59  * fork escalation process
60  */
61 pid_t
fork_escalation_process(void)62 fork_escalation_process(void)
63 {
64 	pid_t		pid;
65 
66 	pid = fork();
67 	if (pid != 0)
68 	{
69 		if (pid == -1)
70 			ereport(NOTICE,
71 					(errmsg("failed to fork a escalation process")));
72 		return pid;
73 	}
74 	on_exit_reset();
75 	processType = PT_WATCHDOG_UTILITY;
76 
77 	POOL_SETMASK(&UnBlockSig);
78 
79 	init_ps_display("", "", "", "");
80 
81 	pool_signal(SIGTERM, wd_exit);
82 	pool_signal(SIGINT, wd_exit);
83 	pool_signal(SIGQUIT, wd_exit);
84 	pool_signal(SIGCHLD, SIG_DFL);
85 	pool_signal(SIGHUP, SIG_IGN);
86 	pool_signal(SIGPIPE, SIG_IGN);
87 
88 	MemoryContextSwitchTo(TopMemoryContext);
89 
90 	set_ps_display("watchdog escalation", false);
91 
92 	ereport(LOG,
93 			(errmsg("watchdog: escalation started")));
94 
95 	/*
96 	 * STEP 1 clear shared memory cache
97 	 */
98 	if (pool_config->memory_cache_enabled && pool_is_shmem_cache() &&
99 		pool_config->clear_memqcache_on_escalation)
100 	{
101 		ereport(LOG,
102 				(errmsg("watchdog escalation"),
103 				 errdetail("clearing all the query cache on shared memory")));
104 
105 		pool_clear_memory_cache();
106 	}
107 
108 	/*
109 	 * STEP 2 execute escalation command provided by user in pgpool conf file
110 	 */
111 	if (strlen(pool_config->wd_escalation_command))
112 	{
113 		int			r = system(pool_config->wd_escalation_command);
114 
115 		if (WIFEXITED(r))
116 		{
117 			if (WEXITSTATUS(r) == EXIT_SUCCESS)
118 				ereport(LOG,
119 						(errmsg("watchdog escalation successful")));
120 			else
121 			{
122 				ereport(WARNING,
123 						(errmsg("watchdog escalation command failed with exit status: %d", WEXITSTATUS(r))));
124 			}
125 		}
126 		else
127 		{
128 			ereport(WARNING,
129 					(errmsg("watchdog escalation command exit abnormally")));
130 		}
131 	}
132 
133 	/*
134 	 * STEP 3 bring up the delegate IP
135 	 */
136 	if (strlen(pool_config->delegate_IP) != 0)
137 	{
138 		if (wd_IP_up() != WD_OK)
139 			ereport(WARNING,
140 					(errmsg("watchdog escalation failed to acquire delegate IP")));
141 
142 	}
143 	exit(0);
144 }
145 
146 /*
147  * fork de-escalation process
148  */
149 pid_t
fork_plunging_process(void)150 fork_plunging_process(void)
151 {
152 	pid_t		pid;
153 
154 	pid = fork();
155 	if (pid != 0)
156 	{
157 		if (pid == -1)
158 			ereport(NOTICE,
159 					(errmsg("failed to fork a de-escalation process")));
160 		return pid;
161 	}
162 	on_exit_reset();
163 	processType = PT_WATCHDOG_UTILITY;
164 
165 	POOL_SETMASK(&UnBlockSig);
166 
167 	init_ps_display("", "", "", "");
168 
169 	pool_signal(SIGTERM, wd_exit);
170 	pool_signal(SIGINT, wd_exit);
171 	pool_signal(SIGQUIT, wd_exit);
172 	pool_signal(SIGCHLD, SIG_DFL);
173 	pool_signal(SIGHUP, SIG_IGN);
174 	pool_signal(SIGPIPE, SIG_IGN);
175 
176 	MemoryContextSwitchTo(TopMemoryContext);
177 
178 	set_ps_display("watchdog de-escalation", false);
179 
180 	ereport(LOG,
181 			(errmsg("watchdog: de-escalation started")));
182 
183 	/*
184 	 * STEP 1 execute de-escalation command provided by user in pgpool conf
185 	 * file
186 	 */
187 	if (strlen(pool_config->wd_de_escalation_command))
188 	{
189 		int			r = system(pool_config->wd_de_escalation_command);
190 
191 		if (WIFEXITED(r))
192 		{
193 			if (WEXITSTATUS(r) == EXIT_SUCCESS)
194 				ereport(LOG,
195 						(errmsg("watchdog de-escalation successful")));
196 			else
197 			{
198 				ereport(WARNING,
199 						(errmsg("watchdog de-escalation command failed with exit status: %d", WEXITSTATUS(r))));
200 			}
201 		}
202 		else
203 		{
204 			ereport(WARNING,
205 					(errmsg("watchdog de-escalation command exit abnormally")));
206 		}
207 	}
208 
209 	/*
210 	 * STEP 2 bring down the delegate IP
211 	 */
212 
213 	if (strlen(pool_config->delegate_IP) != 0)
214 	{
215 		if (wd_IP_down() != WD_OK)
216 			ereport(WARNING,
217 					(errmsg("watchdog de-escalation failed to bring down delegate IP")));
218 	}
219 	exit(0);
220 }
221