diff options
author | Michael Paquier | 2021-11-23 10:29:42 +0000 |
---|---|---|
committer | Michael Paquier | 2021-11-23 10:29:42 +0000 |
commit | 1922d7c6e1a74178bd2f1d5aa5a6ab921b3fcd34 (patch) | |
tree | f50330db40f2049bf53b7f7f3801d46b20058d05 | |
parent | b55f2b6926556115155930c4b2d006c173f45e65 (diff) |
Add SQL functions to monitor the directory contents of replication slots
This commit adds a set of functions able to look at the contents of
various paths related to replication slots:
- pg_ls_logicalsnapdir, for pg_logical/snapshots/
- pg_ls_logicalmapdir, for pg_logical/mappings/
- pg_ls_replslotdir, for pg_replslot/<slot_name>/
These are intended to be used by monitoring tools. Unlike pg_ls_dir(),
execution permission can be granted to non-superusers. Roles members of
pg_monitor gain have access to those functions.
Bump catalog version.
Author: Bharath Rupireddy
Reviewed-by: Nathan Bossart, Justin Pryzby
Discussion: https://postgr.es/m/CALj2ACWsfizZjMN6bzzdxOk1ADQQeSw8HhEjhmVXn_Pu+7VzLw@mail.gmail.com
-rw-r--r-- | contrib/test_decoding/expected/slot.out | 21 | ||||
-rw-r--r-- | contrib/test_decoding/sql/slot.sql | 6 | ||||
-rw-r--r-- | doc/src/sgml/func.sgml | 73 | ||||
-rw-r--r-- | src/backend/catalog/system_functions.sql | 12 | ||||
-rw-r--r-- | src/backend/utils/adt/genfile.c | 44 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/catalog/pg_proc.dat | 22 | ||||
-rw-r--r-- | src/test/regress/expected/misc_functions.out | 50 | ||||
-rw-r--r-- | src/test/regress/sql/misc_functions.sql | 21 |
9 files changed, 250 insertions, 1 deletions
diff --git a/contrib/test_decoding/expected/slot.out b/contrib/test_decoding/expected/slot.out index 75b4b5cc625..63a9940f73a 100644 --- a/contrib/test_decoding/expected/slot.out +++ b/contrib/test_decoding/expected/slot.out @@ -48,6 +48,27 @@ SELECT pg_drop_replication_slot('regression_slot_t'); ERROR: replication slot "regression_slot_t" does not exist SELECT pg_drop_replication_slot('regression_slot_t2'); ERROR: replication slot "regression_slot_t2" does not exist +-- monitoring functions for slot directories +SELECT count(*) >= 0 AS ok FROM pg_ls_logicalmapdir(); + ok +---- + t +(1 row) + +SELECT count(*) >= 0 AS ok FROM pg_ls_logicalsnapdir(); + ok +---- + t +(1 row) + +SELECT count(*) >= 0 AS ok FROM pg_ls_replslotdir('regression_slot_p'); + ok +---- + t +(1 row) + +SELECT count(*) >= 0 AS ok FROM pg_ls_replslotdir('not_existing_slot'); -- fails +ERROR: replication slot "not_existing_slot" does not exist -- permanent slot has survived SELECT pg_drop_replication_slot('regression_slot_p'); pg_drop_replication_slot diff --git a/contrib/test_decoding/sql/slot.sql b/contrib/test_decoding/sql/slot.sql index 6d83fb26782..1aa27c56674 100644 --- a/contrib/test_decoding/sql/slot.sql +++ b/contrib/test_decoding/sql/slot.sql @@ -28,6 +28,12 @@ end'; SELECT pg_drop_replication_slot('regression_slot_t'); SELECT pg_drop_replication_slot('regression_slot_t2'); +-- monitoring functions for slot directories +SELECT count(*) >= 0 AS ok FROM pg_ls_logicalmapdir(); +SELECT count(*) >= 0 AS ok FROM pg_ls_logicalsnapdir(); +SELECT count(*) >= 0 AS ok FROM pg_ls_replslotdir('regression_slot_p'); +SELECT count(*) >= 0 AS ok FROM pg_ls_replslotdir('not_existing_slot'); -- fails + -- permanent slot has survived SELECT pg_drop_replication_slot('regression_slot_p'); diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 24447c00177..74d3087a723 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -27417,6 +27417,79 @@ SELECT convert_from(pg_read_binary_file('file_in_utf8.txt'), 'UTF8'); can be granted EXECUTE to run the function. </para></entry> </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm> + <primary>pg_ls_logicalsnapdir</primary> + </indexterm> + <function>pg_ls_logicalsnapdir</function> () + <returnvalue>setof record</returnvalue> + ( <parameter>name</parameter> <type>text</type>, + <parameter>size</parameter> <type>bigint</type>, + <parameter>modification</parameter> <type>timestamp with time zone</type> ) + </para> + <para> + Returns the name, size, and last modification time (mtime) of each + ordinary file in the server's <filename>pg_logical/snapshots</filename> + directory. Filenames beginning with a dot, directories, and other + special files are excluded. + </para> + <para> + This function is restricted to superusers and members of + the <literal>pg_monitor</literal> role by default, but other users can + be granted EXECUTE to run the function. + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm> + <primary>pg_ls_logicalmapdir</primary> + </indexterm> + <function>pg_ls_logicalmapdir</function> () + <returnvalue>setof record</returnvalue> + ( <parameter>name</parameter> <type>text</type>, + <parameter>size</parameter> <type>bigint</type>, + <parameter>modification</parameter> <type>timestamp with time zone</type> ) + </para> + <para> + Returns the name, size, and last modification time (mtime) of each + ordinary file in the server's <filename>pg_logical/mappings</filename> + directory. Filenames beginning with a dot, directories, and other + special files are excluded. + </para> + <para> + This function is restricted to superusers and members of + the <literal>pg_monitor</literal> role by default, but other users can + be granted EXECUTE to run the function. + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm> + <primary>pg_ls_replslotdir</primary> + </indexterm> + <function>pg_ls_replslotdir</function> ( <parameter>slot_name</parameter> <type>text</type> ) + <returnvalue>setof record</returnvalue> + ( <parameter>name</parameter> <type>text</type>, + <parameter>size</parameter> <type>bigint</type>, + <parameter>modification</parameter> <type>timestamp with time zone</type> ) + </para> + <para> + Returns the name, size, and last modification time (mtime) of each + ordinary file in the server's <filename>pg_replslot/slot_name</filename> + directory, where <parameter>slot_name</parameter> is the name of the + replication slot provided as input of the function. Filenames beginning + with a dot, directories, and other special files are excluded. + </para> + <para> + This function is restricted to superusers and members of + the <literal>pg_monitor</literal> role by default, but other users can + be granted EXECUTE to run the function. + </para></entry> + </row> </tbody> </tgroup> </table> diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql index 54c93b16c4c..f6789025a5f 100644 --- a/src/backend/catalog/system_functions.sql +++ b/src/backend/catalog/system_functions.sql @@ -701,6 +701,12 @@ REVOKE EXECUTE ON FUNCTION pg_ls_dir(text,boolean,boolean) FROM public; REVOKE EXECUTE ON FUNCTION pg_log_backend_memory_contexts(integer) FROM PUBLIC; +REVOKE EXECUTE ON FUNCTION pg_ls_logicalsnapdir() FROM PUBLIC; + +REVOKE EXECUTE ON FUNCTION pg_ls_logicalmapdir() FROM PUBLIC; + +REVOKE EXECUTE ON FUNCTION pg_ls_replslotdir(text) FROM PUBLIC; + -- -- We also set up some things as accessible to standard roles. -- @@ -715,6 +721,12 @@ GRANT EXECUTE ON FUNCTION pg_ls_tmpdir() TO pg_monitor; GRANT EXECUTE ON FUNCTION pg_ls_tmpdir(oid) TO pg_monitor; +GRANT EXECUTE ON FUNCTION pg_ls_logicalsnapdir() TO pg_monitor; + +GRANT EXECUTE ON FUNCTION pg_ls_logicalmapdir() TO pg_monitor; + +GRANT EXECUTE ON FUNCTION pg_ls_replslotdir(text) TO pg_monitor; + GRANT pg_read_all_settings TO pg_monitor; GRANT pg_read_all_stats TO pg_monitor; diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index c436d9318b6..027ed864001 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -29,6 +29,7 @@ #include "mb/pg_wchar.h" #include "miscadmin.h" #include "postmaster/syslogger.h" +#include "replication/slot.h" #include "storage/fd.h" #include "utils/acl.h" #include "utils/builtins.h" @@ -720,3 +721,46 @@ pg_ls_archive_statusdir(PG_FUNCTION_ARGS) { return pg_ls_dir_files(fcinfo, XLOGDIR "/archive_status", true); } + +/* + * Function to return the list of files in the pg_logical/snapshots directory. + */ +Datum +pg_ls_logicalsnapdir(PG_FUNCTION_ARGS) +{ + return pg_ls_dir_files(fcinfo, "pg_logical/snapshots", false); +} + +/* + * Function to return the list of files in the pg_logical/mappings directory. + */ +Datum +pg_ls_logicalmapdir(PG_FUNCTION_ARGS) +{ + return pg_ls_dir_files(fcinfo, "pg_logical/mappings", false); +} + +/* + * Function to return the list of files in the pg_replslot/<replication_slot> + * directory. + */ +Datum +pg_ls_replslotdir(PG_FUNCTION_ARGS) +{ + text *slotname_t; + char path[MAXPGPATH]; + char *slotname; + + slotname_t = PG_GETARG_TEXT_PP(0); + + slotname = text_to_cstring(slotname_t); + + if (!SearchNamedReplicationSlot(slotname, true)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("replication slot \"%s\" does not exist", + slotname))); + + snprintf(path, sizeof(path), "pg_replslot/%s", slotname); + return pg_ls_dir_files(fcinfo, path, false); +} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index cb7117df3ea..920390b8b2a 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202111171 +#define CATALOG_VERSION_NO 202111231 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 6412f369f18..e934361dc32 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -11623,6 +11623,28 @@ proallargtypes => '{oid,text,int8,timestamptz}', proargmodes => '{i,o,o,o}', proargnames => '{tablespace,name,size,modification}', prosrc => 'pg_ls_tmpdir_1arg' }, +{ oid => '9858', + descr => 'list of files in the pg_logical/snapshots directory', + proname => 'pg_ls_logicalsnapdir', procost => '10', prorows => '20', + proretset => 't', provolatile => 'v', prorettype => 'record', + proargtypes => '', proallargtypes => '{text,int8,timestamptz}', + proargmodes => '{o,o,o}', proargnames => '{name,size,modification}', + prosrc => 'pg_ls_logicalsnapdir' }, +{ oid => '9859', + descr => 'list of files in the pg_logical/mappings directory', + proname => 'pg_ls_logicalmapdir', procost => '10', prorows => '20', + proretset => 't', provolatile => 'v', prorettype => 'record', + proargtypes => '', proallargtypes => '{text,int8,timestamptz}', + proargmodes => '{o,o,o}', proargnames => '{name,size,modification}', + prosrc => 'pg_ls_logicalmapdir' }, +{ oid => '9860', + descr => 'list of files in the pg_replslot/slot_name directory', + proname => 'pg_ls_replslotdir', procost => '10', prorows => '20', + proretset => 't', provolatile => 'v', prorettype => 'record', + proargtypes => 'text', proallargtypes => '{text,text,int8,timestamptz}', + proargmodes => '{i,o,o,o}', + proargnames => '{slot_name,name,size,modification}', + prosrc => 'pg_ls_replslotdir' }, # hash partitioning constraint function { oid => '5028', descr => 'hash partition CHECK constraint', diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out index 71d316cad3e..1013d17f87d 100644 --- a/src/test/regress/expected/misc_functions.out +++ b/src/test/regress/expected/misc_functions.out @@ -244,6 +244,56 @@ select count(*) > 0 from (1 row) -- +-- Test replication slot directory functions +-- +CREATE ROLE regress_slot_dir_funcs; +-- Not available by default. +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_logicalsnapdir()', 'EXECUTE'); + has_function_privilege +------------------------ + f +(1 row) + +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_logicalmapdir()', 'EXECUTE'); + has_function_privilege +------------------------ + f +(1 row) + +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_replslotdir(text)', 'EXECUTE'); + has_function_privilege +------------------------ + f +(1 row) + +GRANT pg_monitor TO regress_slot_dir_funcs; +-- Role is now part of pg_monitor, so these are available. +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_logicalsnapdir()', 'EXECUTE'); + has_function_privilege +------------------------ + t +(1 row) + +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_logicalmapdir()', 'EXECUTE'); + has_function_privilege +------------------------ + t +(1 row) + +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_replslotdir(text)', 'EXECUTE'); + has_function_privilege +------------------------ + t +(1 row) + +DROP ROLE regress_slot_dir_funcs; +-- -- Test adding a support function to a subject function -- CREATE FUNCTION my_int_eq(int, int) RETURNS bool diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql index 8c23874b3f5..7ab9b2a1509 100644 --- a/src/test/regress/sql/misc_functions.sql +++ b/src/test/regress/sql/misc_functions.sql @@ -92,6 +92,27 @@ select count(*) > 0 from join pg_database db on pts.pts = db.oid; -- +-- Test replication slot directory functions +-- +CREATE ROLE regress_slot_dir_funcs; +-- Not available by default. +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_logicalsnapdir()', 'EXECUTE'); +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_logicalmapdir()', 'EXECUTE'); +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_replslotdir(text)', 'EXECUTE'); +GRANT pg_monitor TO regress_slot_dir_funcs; +-- Role is now part of pg_monitor, so these are available. +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_logicalsnapdir()', 'EXECUTE'); +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_logicalmapdir()', 'EXECUTE'); +SELECT has_function_privilege('regress_slot_dir_funcs', + 'pg_ls_replslotdir(text)', 'EXECUTE'); +DROP ROLE regress_slot_dir_funcs; + +-- -- Test adding a support function to a subject function -- |