mirror of
https://github.com/postgres/postgres.git
synced 2025-05-06 19:59:18 +03:00
Add functions to wait for backend termination
This adds a function, pg_wait_for_backend_termination(), and a new timeout argument to pg_terminate_backend(), which will wait for the backend to actually terminate (with or without signaling it to do so depending on which function is called). The default behaviour of pg_terminate_backend() remains being timeout=0 which does not waiting. For pg_wait_for_backend_termination() the default wait is 5 seconds. Author: Bharath Rupireddy Reviewed-By: Fujii Masao, David Johnston, Muhammad Usama, Hou Zhijie, Magnus Hagander Discussion: https://postgr.es/m/CALj2ACUBpunmyhYZw-kXCYs5NM+h6oG_7Df_Tn4mLmmUQifkqA@mail.gmail.com
This commit is contained in:
parent
fb310f1781
commit
aaf0432572
@ -24977,7 +24977,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
|
|||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>pg_terminate_backend</primary>
|
<primary>pg_terminate_backend</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
<function>pg_terminate_backend</function> ( <parameter>pid</parameter> <type>integer</type> )
|
<function>pg_terminate_backend</function> ( <parameter>pid</parameter> <type>integer</type>, <parameter>timeout</parameter> <type>bigint</type> <literal>DEFAULT</literal> <literal>0</literal> )
|
||||||
<returnvalue>boolean</returnvalue>
|
<returnvalue>boolean</returnvalue>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
@ -24986,6 +24986,34 @@ SELECT collation for ('foo' COLLATE "de_DE");
|
|||||||
is a member of the role whose backend is being terminated or the
|
is a member of the role whose backend is being terminated or the
|
||||||
calling role has been granted <literal>pg_signal_backend</literal>,
|
calling role has been granted <literal>pg_signal_backend</literal>,
|
||||||
however only superusers can terminate superuser backends.
|
however only superusers can terminate superuser backends.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
If <parameter>timeout</parameter> is not specified or zero, this
|
||||||
|
function returns <literal>true</literal> whether the process actually
|
||||||
|
terminates or not, indicating only that the sending of the signal was
|
||||||
|
successful. If the <parameter>timeout</parameter> is specified (in
|
||||||
|
milliseconds) and greater than zero, the function waits until the
|
||||||
|
process is actually terminated or until the given time has passed. If
|
||||||
|
the process is terminated, the function
|
||||||
|
returns <literal>true</literal>. On timeout a warning is emitted and
|
||||||
|
<literal>false</literal> is returned.
|
||||||
|
</para></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry role="func_table_entry"><para role="func_signature">
|
||||||
|
<indexterm>
|
||||||
|
<primary>pg_wait_for_backend_termination</primary>
|
||||||
|
</indexterm>
|
||||||
|
<function>pg_wait_for_backend_termination</function> ( <parameter>pid</parameter> <type>integer</type>, <parameter>timeout</parameter> <type>bigint</type> <literal>DEFAULT</literal> <literal>5000</literal> )
|
||||||
|
<returnvalue>boolean</returnvalue>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Waits for the backend process with the specified Process ID to
|
||||||
|
terminate. If the process terminates before
|
||||||
|
the <parameter>timeout</parameter> (in milliseconds)
|
||||||
|
expires, <literal>true</literal> is returned. On timeout, a warning
|
||||||
|
is emitted and <literal>false</literal> is returned.
|
||||||
</para></entry>
|
</para></entry>
|
||||||
</row>
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -1585,6 +1585,10 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
|
|||||||
<entry>Waiting for subplan nodes of an <literal>Append</literal> plan
|
<entry>Waiting for subplan nodes of an <literal>Append</literal> plan
|
||||||
node to be ready.</entry>
|
node to be ready.</entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><literal>BackendTermination</literal></entry>
|
||||||
|
<entry>Waiting for the termination of another backend.</entry>
|
||||||
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry><literal>BackupWaitWalArchive</literal></entry>
|
<entry><literal>BackupWaitWalArchive</literal></entry>
|
||||||
<entry>Waiting for WAL files required for a backup to be successfully
|
<entry>Waiting for WAL files required for a backup to be successfully
|
||||||
|
@ -1347,6 +1347,16 @@ CREATE OR REPLACE FUNCTION
|
|||||||
RETURNS boolean STRICT VOLATILE LANGUAGE INTERNAL AS 'pg_promote'
|
RETURNS boolean STRICT VOLATILE LANGUAGE INTERNAL AS 'pg_promote'
|
||||||
PARALLEL SAFE;
|
PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION
|
||||||
|
pg_terminate_backend(pid integer, timeout int8 DEFAULT 0)
|
||||||
|
RETURNS boolean STRICT VOLATILE LANGUAGE INTERNAL AS 'pg_terminate_backend'
|
||||||
|
PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION
|
||||||
|
pg_wait_for_backend_termination(pid integer, timeout int8 DEFAULT 5000)
|
||||||
|
RETURNS boolean STRICT VOLATILE LANGUAGE INTERNAL AS 'pg_wait_for_backend_termination'
|
||||||
|
PARALLEL SAFE;
|
||||||
|
|
||||||
-- legacy definition for compatibility with 9.3
|
-- legacy definition for compatibility with 9.3
|
||||||
CREATE OR REPLACE FUNCTION
|
CREATE OR REPLACE FUNCTION
|
||||||
json_populate_record(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
|
json_populate_record(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "catalog/pg_authid.h"
|
#include "catalog/pg_authid.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "pgstat.h"
|
||||||
#include "postmaster/syslogger.h"
|
#include "postmaster/syslogger.h"
|
||||||
#include "storage/pmsignal.h"
|
#include "storage/pmsignal.h"
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
@ -125,16 +126,91 @@ pg_cancel_backend(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
|
PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait until there is no backend process with the given PID and return true.
|
||||||
|
* On timeout, a warning is emitted and false is returned.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
pg_wait_until_termination(int pid, int64 timeout)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Wait in steps of waittime milliseconds until this function exits or
|
||||||
|
* timeout.
|
||||||
|
*/
|
||||||
|
int64 waittime = 100;
|
||||||
|
/*
|
||||||
|
* Initially remaining time is the entire timeout specified by the user.
|
||||||
|
*/
|
||||||
|
int64 remainingtime = timeout;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check existence of the backend. If the backend still exists, then wait
|
||||||
|
* for waittime milliseconds, again check for the existence. Repeat this
|
||||||
|
* until timeout or an error occurs or a pending interrupt such as query
|
||||||
|
* cancel gets processed.
|
||||||
|
*/
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (remainingtime < waittime)
|
||||||
|
waittime = remainingtime;
|
||||||
|
|
||||||
|
if (kill(pid, 0) == -1)
|
||||||
|
{
|
||||||
|
if (errno == ESRCH)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INTERNAL_ERROR),
|
||||||
|
errmsg("could not check the existence of the backend with PID %d: %m",
|
||||||
|
pid)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process interrupts, if any, before waiting */
|
||||||
|
CHECK_FOR_INTERRUPTS();
|
||||||
|
|
||||||
|
(void) WaitLatch(MyLatch,
|
||||||
|
WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
|
||||||
|
waittime,
|
||||||
|
WAIT_EVENT_BACKEND_TERMINATION);
|
||||||
|
|
||||||
|
ResetLatch(MyLatch);
|
||||||
|
|
||||||
|
remainingtime -= waittime;
|
||||||
|
} while (remainingtime > 0);
|
||||||
|
|
||||||
|
ereport(WARNING,
|
||||||
|
(errmsg("backend with PID %d did not terminate within %lld milliseconds",
|
||||||
|
pid, (long long int) timeout)));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signal to terminate a backend process. This is allowed if you are a member
|
* Signal to terminate a backend process. This is allowed if you are a member
|
||||||
* of the role whose process is being terminated.
|
* of the role whose process is being terminated. If timeout input argument is
|
||||||
|
* 0 (which is default), then this function just signals the backend and
|
||||||
|
* doesn't wait. Otherwise it waits until given the timeout milliseconds or no
|
||||||
|
* process has the given PID and returns true. On timeout, a warning is emitted
|
||||||
|
* and false is returned.
|
||||||
*
|
*
|
||||||
* Note that only superusers can signal superuser-owned processes.
|
* Note that only superusers can signal superuser-owned processes.
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
pg_terminate_backend(PG_FUNCTION_ARGS)
|
pg_terminate_backend(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
int r = pg_signal_backend(PG_GETARG_INT32(0), SIGTERM);
|
int pid;
|
||||||
|
int r;
|
||||||
|
int timeout;
|
||||||
|
|
||||||
|
pid = PG_GETARG_INT32(0);
|
||||||
|
timeout = PG_GETARG_INT64(1);
|
||||||
|
|
||||||
|
if (timeout < 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
|
errmsg("\"timeout\" must not be negative")));
|
||||||
|
|
||||||
|
r = pg_signal_backend(pid, SIGTERM);
|
||||||
|
|
||||||
if (r == SIGNAL_BACKEND_NOSUPERUSER)
|
if (r == SIGNAL_BACKEND_NOSUPERUSER)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -146,9 +222,49 @@ pg_terminate_backend(PG_FUNCTION_ARGS)
|
|||||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||||
errmsg("must be a member of the role whose process is being terminated or member of pg_signal_backend")));
|
errmsg("must be a member of the role whose process is being terminated or member of pg_signal_backend")));
|
||||||
|
|
||||||
|
/* Wait only on success and if actually requested */
|
||||||
|
if (r == SIGNAL_BACKEND_SUCCESS && timeout > 0)
|
||||||
|
PG_RETURN_BOOL(pg_wait_until_termination(pid, timeout));
|
||||||
|
else
|
||||||
PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
|
PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for a backend process with the given PID to exit or until the given
|
||||||
|
* timeout milliseconds occurs. Returns true if the backend has exited. On
|
||||||
|
* timeout a warning is emitted and false is returned.
|
||||||
|
*
|
||||||
|
* We allow any user to call this function, consistent with any user being
|
||||||
|
* able to view the pid of the process in pg_stat_activity etc.
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
pg_wait_for_backend_termination(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
int pid;
|
||||||
|
int64 timeout;
|
||||||
|
PGPROC *proc = NULL;
|
||||||
|
|
||||||
|
pid = PG_GETARG_INT32(0);
|
||||||
|
timeout = PG_GETARG_INT64(1);
|
||||||
|
|
||||||
|
if (timeout <= 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
|
errmsg("\"timeout\" must not be negative or zero")));
|
||||||
|
|
||||||
|
proc = BackendPidGetProc(pid);
|
||||||
|
|
||||||
|
if (proc == NULL)
|
||||||
|
{
|
||||||
|
ereport(WARNING,
|
||||||
|
(errmsg("PID %d is not a PostgreSQL server process", pid)));
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(pg_wait_until_termination(pid, timeout));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signal to reload the database configuration
|
* Signal to reload the database configuration
|
||||||
*
|
*
|
||||||
|
@ -313,6 +313,9 @@ pgstat_get_wait_ipc(WaitEventIPC w)
|
|||||||
case WAIT_EVENT_APPEND_READY:
|
case WAIT_EVENT_APPEND_READY:
|
||||||
event_name = "AppendReady";
|
event_name = "AppendReady";
|
||||||
break;
|
break;
|
||||||
|
case WAIT_EVENT_BACKEND_TERMINATION:
|
||||||
|
event_name = "BackendTermination";
|
||||||
|
break;
|
||||||
case WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE:
|
case WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE:
|
||||||
event_name = "BackupWaitWalArchive";
|
event_name = "BackupWaitWalArchive";
|
||||||
break;
|
break;
|
||||||
|
@ -6190,9 +6190,14 @@
|
|||||||
{ oid => '2171', descr => 'cancel a server process\' current query',
|
{ oid => '2171', descr => 'cancel a server process\' current query',
|
||||||
proname => 'pg_cancel_backend', provolatile => 'v', prorettype => 'bool',
|
proname => 'pg_cancel_backend', provolatile => 'v', prorettype => 'bool',
|
||||||
proargtypes => 'int4', prosrc => 'pg_cancel_backend' },
|
proargtypes => 'int4', prosrc => 'pg_cancel_backend' },
|
||||||
{ oid => '2096', descr => 'terminate a server process',
|
{ oid => '2096', descr => 'terminate a backend process and if timeout is specified, wait for its exit or until timeout occurs',
|
||||||
proname => 'pg_terminate_backend', provolatile => 'v', prorettype => 'bool',
|
proname => 'pg_terminate_backend', provolatile => 'v', prorettype => 'bool',
|
||||||
proargtypes => 'int4', prosrc => 'pg_terminate_backend' },
|
proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
|
||||||
|
prosrc => 'pg_terminate_backend' },
|
||||||
|
{ oid => '2137', descr => 'wait for a backend process exit or timeout occurs',
|
||||||
|
proname => 'pg_wait_for_backend_termination', provolatile => 'v', prorettype => 'bool',
|
||||||
|
proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
|
||||||
|
prosrc => 'pg_wait_for_backend_termination' },
|
||||||
{ oid => '2172', descr => 'prepare for taking an online backup',
|
{ oid => '2172', descr => 'prepare for taking an online backup',
|
||||||
proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
|
proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
|
||||||
prorettype => 'pg_lsn', proargtypes => 'text bool bool',
|
prorettype => 'pg_lsn', proargtypes => 'text bool bool',
|
||||||
|
@ -80,6 +80,7 @@ typedef enum
|
|||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
WAIT_EVENT_APPEND_READY = PG_WAIT_IPC,
|
WAIT_EVENT_APPEND_READY = PG_WAIT_IPC,
|
||||||
|
WAIT_EVENT_BACKEND_TERMINATION,
|
||||||
WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE,
|
WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE,
|
||||||
WAIT_EVENT_BGWORKER_SHUTDOWN,
|
WAIT_EVENT_BGWORKER_SHUTDOWN,
|
||||||
WAIT_EVENT_BGWORKER_STARTUP,
|
WAIT_EVENT_BGWORKER_STARTUP,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user