[pgpool-general: 9263] Re: Segmentation fault during shutdown

Tatsuo Ishii ishii at postgresql.org
Fri Nov 8 20:22:58 JST 2024


> Hi Emond,
> Thank you for the report. I will look into this.
> Best reagards,
> --
> Tatsuo Ishii
> SRA OSS K.K.
> English: http://www.sraoss.co.jp/index_en/
> Japanese:http://www.sraoss.co.jp
>> Hi,
>> Unfortunately, it seems the patch did not fix this issue. Yesterday we
 had
>> a segmentation fault at this same point again. The top of the backtrace
 now
>> is:
>> #0  close_all_backend_connections () at
 protocol/pool_connection_pool.c:1082
>> #1  0x0000563a51f9280f in proc_exit_prepare (code=-1) at
>> ../../src/utils/error/elog.c:2707
>> #2  0x00007f0926782da7 in __funcs_on_exit () at src/exit/atexit.c:34
>> #3  0x00007f092677a08f in exit (code=code at entry=0) at src/exit/exit.c:29
>> #4  0x0000563a51f4e4e2 in child_exit (code=0) at protocol/child.c:1378
>> #5  die (sig=3) at protocol/child.c:1174
>> #6  <signal handler called>
>> As you can see, it now crashes at line 1082 in pool_connection_pool.c,
>> which looks like this in our patched version:
>> 1074  for (i = 0; i < pool_config->max_pool; i++, p++)
>> 1075  {
>> 1076      int backend_id = in_use_backend_id(p);
>> 1077
>> 1078      if (backend_id < 0)
>> 1079          continue;
>> 1080      if (CONNECTION_SLOT(p, backend_id) == NULL)
>> 1081          continue;
>> 1082      if (CONNECTION_SLOT(p, backend_id)->sp == NULL)
>> 1083          continue;
>> 1084      if (CONNECTION_SLOT(p, backend_id)->sp->user == NULL)
>> 1085          continue;
>> 1086      pool_send_frontend_exits(p);
>> 1087  }
>> At the moment of the crash, a lot is happening at the same time. We are
>> reducing a cluster back to a single node. The crash happens at the very
>> last moment, when only the final remaining node is still up and running,
>> but it still is running with cluster configuration (with a watchdog and 2
>> backends, the local one up, the remote one down). Our configuration
>> management then restarts the database (to force a configuration change on
>> postgresql). Looking at the logs, this shutdown is noticed by pgpool, but
>> the watchdog does not hold a quorum, so it cannot initiate a failover
>> (also, there's no backend to failover to). Then, within a second, pgpool
>> itself is also shutdown. This is when the process segfaults. Something
 that
>> does seem interesting is that the pid (183) that segfaults, seems to be
>> started during the failover process. pgpool is simultaneously killing all
>> connection pids and starting this one. Also, this pid is killed within a
>> single ms of being started (see timestamp 2024-11-07T00:48:06.906935
>> and 2024-11-07T00:48:06.907304 in the logs). I hope this helps in
 tracking
>> this issue down.
The crash is inside close_all_backend_connections(), which is called
when pgpool child process is about to exit. The function should never
crash if the connection pool has been already initialized. The
initialization is done in pool_init_cp(). The function is called at
the very early stage of pgpool child process starts up. It allocates
memory by using palloc then clear the memory using memset().
>> connection pids and starting this one. Also, this pid is killed within a
>> single ms of being started (see timestamp 2024-11-07T00:48:06.906935
>> and 2024-11-07T00:48:06.907304 in the logs). I hope this helps in
 tracking
So my guess is, the process (pid 183) was killed in the middle of
memset() and the connection pool object was left with uninitialized
data.
The purpose of close_all_backend_connections() is sending an 'X'
(terminate) message to backend telling that pgpool is about to
disconnect. This is a polite way from frontend/backend protocol's
point of view, but it's hard to make it work in the situation you
reported because we need to establish a way to not call
close_all_backend_connections() if the initialization is not
done. Alternative way is, to not call close_all_backend_connections()
at all at the process exit. This will solve the problem in simple and
reliable way. Disconnecting connection to backend without sending 'X'
message is not prohibited by the protocol, I believe. Also as far as I
know PostgreSQL can handle the situation (disconnected without a prior
'X' message from frontend).
Patch attached.
Best reagards,
--
Tatsuo Ishii
SRA OSS K.K.
English: http://www.sraoss.co.jp/index_en/
Japanese:http://www.sraoss.co.jp
Mime-Version: 1.0
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="fix_segfault.patch"

diff --git a/src/protocol/child.c b/src/protocol/child.c
index c12a5a2c1..4e2a3443b 100644
--- a/src/protocol/child.c
+++ b/src/protocol/child.c
@@ -1350,9 +1350,12 @@ child_will_go_down(int code, Datum arg)
 		memcached_disconnect();
 	}
 
-	/* let backend know now we are exiting */
-	if (pool_connection_pool)
-		close_all_backend_connections();
+	/*
+	 * We used to call close_all_backend_connections() here so that we send
+	 * 'X' (terminate) message to backend. However it was possible that the
+	 * function is called while initializing the connection pool object, which
+	 * leads to crash. So we stopped to call close_all_backend_connections().
+	 */
 }
 
 /*


More information about the pgpool-general mailing list