From: Jehan-Guillaume de Rorthais Date: Fri, 31 Jul 2020 18:07:38 +0200 Subject: [PATCH 3/4] demote: add pg_demote() function --- src/backend/access/transam/xlogfuncs.c | 94 ++++++++++++++++++++++++++ src/backend/catalog/system_views.sql | 6 ++ src/include/catalog/pg_proc.dat | 4 ++ 3 files changed, 104 insertions(+) diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index 290658b22c..733f465d38 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -784,3 +784,97 @@ pg_promote(PG_FUNCTION_ARGS) (errmsg("server did not promote within %d seconds", wait_seconds))); PG_RETURN_BOOL(false); } + +/* + * Demotes a production server. + * + * A result of "true" means that demotion has been completed if "wait" is + * "true", or initiated if "wait" is false. + */ +Datum +pg_demote(PG_FUNCTION_ARGS) +{ + bool fast = PG_GETARG_BOOL(0); + bool wait = PG_GETARG_BOOL(1); + int wait_seconds = PG_GETARG_INT32(2); + char demote_filename[] = "demote_fast"; + FILE *demote_file; + int i; + + if (RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("recovery in progress"), + errhint("you can not demote while already in recovery."))); + + if (!EnableHotStandby) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("function pg_demote() requires hot_standby parameter to be enabled"), + errhint("The function can not return its status from a non hot_standby-enabled standby"))); + + if (wait_seconds <= 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("\"wait_seconds\" must not be negative or zero"))); + + if (!fast) + demote_filename[6] = '\0'; + + /* create the demote signal file */ + demote_file = AllocateFile(demote_filename, "w"); + if (!demote_file) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not create file \"%s\": %m", + demote_filename))); + + if (FreeFile(demote_file)) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not write file \"%s\": %m", + demote_filename))); + + /* signal the postmaster */ + if (kill(PostmasterPid, SIGUSR1) != 0) + { + ereport(WARNING, + (errmsg("failed to send signal to postmaster: %m"))); + (void) unlink(demote_filename); + PG_RETURN_BOOL(false); + } + + /* return immediately if waiting was not requested */ + if (!wait) + PG_RETURN_BOOL(true); + + /* wait for the amount of time wanted until demotion */ +#define WAITS_PER_SECOND 10 + for (i = 0; i < WAITS_PER_SECOND * wait_seconds; i++) + { + int rc; + + ResetLatch(MyLatch); + + if (RecoveryInProgress()) + PG_RETURN_BOOL(true); + + CHECK_FOR_INTERRUPTS(); + + rc = WaitLatch(MyLatch, + WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, + 1000L / WAITS_PER_SECOND, + WAIT_EVENT_DEMOTE); + + /* + * Emergency bailout if postmaster has died. This is to avoid the + * necessity for manual cleanup of all postmaster children. + */ + if (rc & WL_POSTMASTER_DEATH) + PG_RETURN_BOOL(false); + } + + ereport(WARNING, + (errmsg("server did not demote within %d seconds", wait_seconds))); + PG_RETURN_BOOL(false); +} diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 8625cbeab6..573d7b46eb 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1219,6 +1219,11 @@ CREATE OR REPLACE FUNCTION RETURNS boolean STRICT VOLATILE LANGUAGE INTERNAL AS 'pg_promote' PARALLEL SAFE; +CREATE OR REPLACE FUNCTION + pg_demote(fast boolean DEFAULT true, wait boolean DEFAULT true, wait_seconds integer DEFAULT 60) + RETURNS boolean STRICT VOLATILE LANGUAGE INTERNAL AS 'pg_demote' + PARALLEL SAFE; + -- legacy definition for compatibility with 9.3 CREATE OR REPLACE FUNCTION json_populate_record(base anyelement, from_json json, use_json_as_text boolean DEFAULT false) @@ -1435,6 +1440,7 @@ REVOKE EXECUTE ON FUNCTION pg_reload_conf() FROM public; REVOKE EXECUTE ON FUNCTION pg_current_logfile() FROM public; REVOKE EXECUTE ON FUNCTION pg_current_logfile(text) FROM public; REVOKE EXECUTE ON FUNCTION pg_promote(boolean, integer) FROM public; +REVOKE EXECUTE ON FUNCTION pg_demote(boolean, boolean, integer) FROM public; REVOKE EXECUTE ON FUNCTION pg_stat_reset() FROM public; REVOKE EXECUTE ON FUNCTION pg_stat_reset_shared(text) FROM public; diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 082a11f270..9e4d000d00 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -6084,6 +6084,10 @@ proname => 'pg_promote', provolatile => 'v', prorettype => 'bool', proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}', prosrc => 'pg_promote' }, +{ oid => '8967', descr => 'demote production server', + proname => 'pg_demote', provolatile => 'v', prorettype => 'bool', + proargtypes => 'bool bool int4', proargnames => '{fast,wait,wait_seconds}', + prosrc => 'pg_demote' }, { oid => '2848', descr => 'switch to new wal file', proname => 'pg_switch_wal', provolatile => 'v', prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_switch_wal' }, -- 2.20.1 --MP_/Mp45B_GpB5m14pibp/TRwlo Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=v4-0004-demote-add-various-tests-related-to-demote-and-promo.patch