summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Paquier2021-11-23 10:29:42 +0000
committerMichael Paquier2021-11-23 10:29:42 +0000
commit1922d7c6e1a74178bd2f1d5aa5a6ab921b3fcd34 (patch)
treef50330db40f2049bf53b7f7f3801d46b20058d05
parentb55f2b6926556115155930c4b2d006c173f45e65 (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.out21
-rw-r--r--contrib/test_decoding/sql/slot.sql6
-rw-r--r--doc/src/sgml/func.sgml73
-rw-r--r--src/backend/catalog/system_functions.sql12
-rw-r--r--src/backend/utils/adt/genfile.c44
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_proc.dat22
-rw-r--r--src/test/regress/expected/misc_functions.out50
-rw-r--r--src/test/regress/sql/misc_functions.sql21
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
--