public inbox for [email protected]
help / color / mirror / Atom feed[PATCH v35 3/7] Add pg_ls_dir_metadata to list a dir with file metadata..
16+ messages / 4 participants
[nested] [flat]
* [PATCH v35 3/7] Add pg_ls_dir_metadata to list a dir with file metadata..
@ 2020-03-10 03:40 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 16+ messages in thread
From: Justin Pryzby @ 2020-03-10 03:40 UTC (permalink / raw)
Generalize pg_ls_dir_files and retire pg_ls_dir
Need catversion bumped?
---
doc/src/sgml/func.sgml | 21 ++
src/backend/catalog/system_functions.sql | 1 +
src/backend/utils/adt/genfile.c | 205 ++++++++++++-------
src/include/catalog/pg_proc.dat | 12 ++
src/test/regress/expected/misc_functions.out | 24 +++
src/test/regress/expected/tablespace.out | 8 +
src/test/regress/sql/misc_functions.sql | 11 +
src/test/regress/sql/tablespace.sql | 5 +
8 files changed, 217 insertions(+), 70 deletions(-)
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index d01aeec9f88..d2a455a3e27 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25987,6 +25987,27 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
</para></entry>
</row>
+ <row>
+ <entry role="func_table_entry"><para role="func_signature">
+ <indexterm>
+ <primary>pg_ls_dir_metadata</primary>
+ </indexterm>
+ <function>pg_ls_dir_metadata</function> ( <parameter>dirname</parameter> <type>text</type>
+ <optional>, <parameter>missing_ok</parameter> <type>boolean</type>,
+ <parameter>include_dot_dirs</parameter> <type>boolean</type> </optional> )
+ <returnvalue>setof record</returnvalue>
+ ( <parameter>filename</parameter> <type>text</type>,
+ <parameter>size</parameter> <type>bigint</type>,
+ <parameter>modification</parameter> <type>timestamp with time zone</type> )
+ </para>
+ <para>
+ For each file in the specified directory, list the file and its
+ metadata.
+ Restricted to superusers 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>
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f5812..b4d3609cce7 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -700,6 +700,7 @@ REVOKE EXECUTE ON FUNCTION pg_stat_file(text,boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_ls_dir(text) FROM public;
REVOKE EXECUTE ON FUNCTION pg_ls_dir(text,boolean,boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_ls_dir_metadata(text,boolean,boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_log_backend_memory_contexts(integer) FROM PUBLIC;
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 88f279d1b31..75b7bf99849 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -37,6 +37,21 @@
#include "utils/syscache.h"
#include "utils/timestamp.h"
+static Datum pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, int flags);
+
+#define LS_DIR_ISDIR (1<<0) /* Show column: isdir */
+#define LS_DIR_METADATA (1<<1) /* Show columns: mtime, size */
+#define LS_DIR_MISSING_OK (1<<2) /* Ignore ENOENT if the toplevel dir is missing */
+#define LS_DIR_SKIP_DOT_DIRS (1<<3) /* Do not show . or .. */
+#define LS_DIR_SKIP_HIDDEN (1<<4) /* Do not show anything beginning with . */
+#define LS_DIR_SKIP_DIRS (1<<5) /* Do not show directories */
+#define LS_DIR_SKIP_SPECIAL (1<<6) /* Do not show special file types */
+
+/*
+ * Shortcut for the historic behavior of the pg_ls_* functions (not including
+ * pg_ls_dir, which skips different files and doesn't show metadata).
+ */
+#define LS_DIR_HISTORIC (LS_DIR_SKIP_DIRS | LS_DIR_SKIP_HIDDEN | LS_DIR_SKIP_SPECIAL | LS_DIR_METADATA)
/*
* Convert a "text" filename argument to C string, and check it's allowable.
@@ -446,6 +461,11 @@ pg_stat_file(PG_FUNCTION_ARGS)
values[4] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime));
#endif
values[5] = BoolGetDatum(S_ISDIR(fst.st_mode));
+#ifdef WIN32
+ /* Links should have isdir=false */
+ if (pgwin32_is_junction(filename))
+ values[5] = BoolGetDatum(false);
+#endif
tuple = heap_form_tuple(tupdesc, values, isnull);
@@ -473,54 +493,9 @@ pg_stat_file_1arg(PG_FUNCTION_ARGS)
Datum
pg_ls_dir(PG_FUNCTION_ARGS)
{
- ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
- char *location;
- bool missing_ok = false;
- bool include_dot_dirs = false;
- DIR *dirdesc;
- struct dirent *de;
-
- location = convert_and_check_filename(PG_GETARG_TEXT_PP(0));
-
- /* check the optional arguments */
- if (PG_NARGS() == 3)
- {
- if (!PG_ARGISNULL(1))
- missing_ok = PG_GETARG_BOOL(1);
- if (!PG_ARGISNULL(2))
- include_dot_dirs = PG_GETARG_BOOL(2);
- }
-
- SetSingleFuncCall(fcinfo, SRF_SINGLE_USE_EXPECTED);
-
- dirdesc = AllocateDir(location);
- if (!dirdesc)
- {
- /* Return empty tuplestore if appropriate */
- if (missing_ok && errno == ENOENT)
- return (Datum) 0;
- /* Otherwise, we can let ReadDir() throw the error */
- }
-
- while ((de = ReadDir(dirdesc, location)) != NULL)
- {
- Datum values[1];
- bool nulls[1];
-
- if (!include_dot_dirs &&
- (strcmp(de->d_name, ".") == 0 ||
- strcmp(de->d_name, "..") == 0))
- continue;
-
- values[0] = CStringGetTextDatum(de->d_name);
- nulls[0] = false;
-
- tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
- values, nulls);
- }
-
- FreeDir(dirdesc);
- return (Datum) 0;
+ text *filename_t = PG_GETARG_TEXT_PP(0);
+ char *filename = convert_and_check_filename(filename_t);
+ return pg_ls_dir_files(fcinfo, filename, LS_DIR_SKIP_DOT_DIRS);
}
/*
@@ -533,23 +508,55 @@ pg_ls_dir(PG_FUNCTION_ARGS)
Datum
pg_ls_dir_1arg(PG_FUNCTION_ARGS)
{
- return pg_ls_dir(fcinfo);
+ text *filename_t = PG_GETARG_TEXT_PP(0);
+ char *filename = convert_and_check_filename(filename_t);
+ return pg_ls_dir_files(fcinfo, filename, LS_DIR_SKIP_DOT_DIRS);
}
/*
- * Generic function to return a directory listing of files.
+ * Generic function to return a directory listing of files (and optionally dirs).
*
- * If the directory isn't there, silently return an empty set if missing_ok.
+ * If the directory isn't there, silently return an empty set if MISSING_OK.
* Other unreadable-directory cases throw an error.
*/
static Datum
-pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok)
+pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, int flags)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
DIR *dirdesc;
struct dirent *de;
- SetSingleFuncCall(fcinfo, 0);
+ /* isdir depends on metadata */
+ Assert(!(flags & LS_DIR_ISDIR) || (flags & LS_DIR_METADATA));
+ /* Unreasonable to show isdir and skip dirs */
+ Assert(!(flags & LS_DIR_ISDIR) || !(flags & LS_DIR_SKIP_DIRS));
+
+ /* check the optional arguments */
+ if (PG_NARGS() == 3)
+ {
+ /* missing_ok */
+ if (!PG_ARGISNULL(1))
+ {
+ if (PG_GETARG_BOOL(1))
+ flags |= LS_DIR_MISSING_OK;
+ else
+ flags &= ~LS_DIR_MISSING_OK;
+ }
+
+ /* include_dot_dirs */
+ if (!PG_ARGISNULL(2))
+ {
+ if (PG_GETARG_BOOL(2))
+ flags &= ~LS_DIR_SKIP_DOT_DIRS;
+ else
+ flags |= LS_DIR_SKIP_DOT_DIRS;
+ }
+ }
+
+ if (flags & LS_DIR_METADATA)
+ SetSingleFuncCall(fcinfo, 0);
+ else
+ SetSingleFuncCall(fcinfo, SRF_SINGLE_USE_EXPECTED);
/*
* Now walk the directory. Note that we must do this within a single SRF
@@ -560,20 +567,27 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok)
if (!dirdesc)
{
/* Return empty tuplestore if appropriate */
- if (missing_ok && errno == ENOENT)
+ if (flags & LS_DIR_MISSING_OK && errno == ENOENT)
return (Datum) 0;
/* Otherwise, we can let ReadDir() throw the error */
}
while ((de = ReadDir(dirdesc, dir)) != NULL)
{
- Datum values[3];
- bool nulls[3];
+ Datum values[4];
+ bool nulls[4];
char path[MAXPGPATH * 2];
struct stat attrib;
- /* Skip hidden files */
- if (de->d_name[0] == '.')
+ /* Skip dot dirs? */
+ if (flags & LS_DIR_SKIP_DOT_DIRS &&
+ (strcmp(de->d_name, ".") == 0 ||
+ strcmp(de->d_name, "..") == 0))
+ continue;
+
+ /* Skip hidden files? */
+ if (flags & LS_DIR_SKIP_HIDDEN &&
+ de->d_name[0] == '.')
continue;
/* Get the file info */
@@ -588,13 +602,35 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok)
errmsg("could not stat file \"%s\": %m", path)));
}
- /* Ignore anything but regular files */
- if (!S_ISREG(attrib.st_mode))
- continue;
+ /* Skip dirs or special files? */
+ if (S_ISDIR(attrib.st_mode))
+ {
+ if (flags & LS_DIR_SKIP_DIRS)
+ continue;
+ }
+ else if (!S_ISREG(attrib.st_mode))
+ {
+ if (flags & LS_DIR_SKIP_SPECIAL)
+ continue;
+ }
values[0] = CStringGetTextDatum(de->d_name);
- values[1] = Int64GetDatum((int64) attrib.st_size);
- values[2] = TimestampTzGetDatum(time_t_to_timestamptz(attrib.st_mtime));
+ if (flags & LS_DIR_METADATA)
+ {
+ values[1] = Int64GetDatum((int64) attrib.st_size);
+ values[2] = TimestampTzGetDatum(time_t_to_timestamptz(attrib.st_mtime));
+ if (flags & LS_DIR_ISDIR)
+ {
+#ifdef WIN32
+ /* Links should have isdir=false */
+ if (pgwin32_is_junction(path))
+ values[3] = BoolGetDatum(false);
+ else
+#endif
+ values[3] = BoolGetDatum(S_ISDIR(attrib.st_mode));
+ }
+ }
+
memset(nulls, 0, sizeof(nulls));
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
@@ -608,14 +644,14 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok)
Datum
pg_ls_logdir(PG_FUNCTION_ARGS)
{
- return pg_ls_dir_files(fcinfo, Log_directory, false);
+ return pg_ls_dir_files(fcinfo, Log_directory, LS_DIR_HISTORIC);
}
/* Function to return the list of files in the WAL directory */
Datum
pg_ls_waldir(PG_FUNCTION_ARGS)
{
- return pg_ls_dir_files(fcinfo, XLOGDIR, false);
+ return pg_ls_dir_files(fcinfo, XLOGDIR, LS_DIR_HISTORIC);
}
/*
@@ -633,7 +669,8 @@ pg_ls_tmpdir(FunctionCallInfo fcinfo, Oid tblspc)
tblspc)));
TempTablespacePath(path, tblspc);
- return pg_ls_dir_files(fcinfo, path, true);
+ return pg_ls_dir_files(fcinfo, path,
+ LS_DIR_HISTORIC | LS_DIR_MISSING_OK);
}
/*
@@ -662,7 +699,35 @@ pg_ls_tmpdir_1arg(PG_FUNCTION_ARGS)
Datum
pg_ls_archive_statusdir(PG_FUNCTION_ARGS)
{
- return pg_ls_dir_files(fcinfo, XLOGDIR "/archive_status", true);
+ return pg_ls_dir_files(fcinfo, XLOGDIR "/archive_status",
+ LS_DIR_HISTORIC | LS_DIR_MISSING_OK);
+}
+
+/*
+ * Return the list of files and metadata in an arbitrary directory.
+ */
+Datum
+pg_ls_dir_metadata(PG_FUNCTION_ARGS)
+{
+ char *dirname = convert_and_check_filename(PG_GETARG_TEXT_PP(0));
+
+ return pg_ls_dir_files(fcinfo, dirname,
+ LS_DIR_METADATA | LS_DIR_SKIP_SPECIAL | LS_DIR_ISDIR);
+}
+
+/*
+ * Return the list of files and metadata in an arbitrary directory.
+ * note: this wrapper is necessary to pass the sanity check in opr_sanity,
+ * which checks that all built-in functions that share the implementing C
+ * function take the same number of arguments.
+ */
+Datum
+pg_ls_dir_metadata_1arg(PG_FUNCTION_ARGS)
+{
+ char *dirname = convert_and_check_filename(PG_GETARG_TEXT_PP(0));
+
+ return pg_ls_dir_files(fcinfo, dirname,
+ LS_DIR_METADATA | LS_DIR_SKIP_SPECIAL | LS_DIR_ISDIR);
}
/*
@@ -671,7 +736,7 @@ pg_ls_archive_statusdir(PG_FUNCTION_ARGS)
Datum
pg_ls_logicalsnapdir(PG_FUNCTION_ARGS)
{
- return pg_ls_dir_files(fcinfo, "pg_logical/snapshots", false);
+ return pg_ls_dir_files(fcinfo, "pg_logical/snapshots", LS_DIR_HISTORIC);
}
/*
@@ -680,7 +745,7 @@ pg_ls_logicalsnapdir(PG_FUNCTION_ARGS)
Datum
pg_ls_logicalmapdir(PG_FUNCTION_ARGS)
{
- return pg_ls_dir_files(fcinfo, "pg_logical/mappings", false);
+ return pg_ls_dir_files(fcinfo, "pg_logical/mappings", LS_DIR_HISTORIC);
}
/*
@@ -705,5 +770,5 @@ pg_ls_replslotdir(PG_FUNCTION_ARGS)
slotname)));
snprintf(path, sizeof(path), "pg_replslot/%s", slotname);
- return pg_ls_dir_files(fcinfo, path, false);
+ return pg_ls_dir_files(fcinfo, path, LS_DIR_HISTORIC);
}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 25304430f44..7307f44f371 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -11769,6 +11769,18 @@
proargmodes => '{i,o,o,o}',
proargnames => '{slot_name,name,size,modification}',
prosrc => 'pg_ls_replslotdir' },
+{ oid => '8450', descr => 'list directory with metadata',
+ proname => 'pg_ls_dir_metadata', procost => '10', prorows => '20', proretset => 't',
+ provolatile => 'v', prorettype => 'record', proargtypes => 'text bool bool',
+ proallargtypes => '{text,bool,bool,text,int8,timestamptz,bool}', proargmodes => '{i,i,i,o,o,o,o}',
+ proargnames => '{dirname,missing_ok,include_dot_dirs,filename,size,modification,isdir}',
+ prosrc => 'pg_ls_dir_metadata' },
+{ oid => '8451', descr => 'list directory with metadata',
+ proname => 'pg_ls_dir_metadata', procost => '10', prorows => '20', proretset => 't',
+ provolatile => 'v', prorettype => 'record', proargtypes => 'text',
+ proallargtypes => '{text,text,int8,timestamptz,bool}', proargmodes => '{i,o,o,o,o}',
+ proargnames => '{dirname,filename,size,modification,isdir}',
+ prosrc => 'pg_ls_dir_metadata_1arg' },
# 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 45544469af5..e54e38f54ad 100644
--- a/src/test/regress/expected/misc_functions.out
+++ b/src/test/regress/expected/misc_functions.out
@@ -475,6 +475,30 @@ select * from pg_stat_file('.') limit 0;
------+--------+--------------+--------+----------+-------
(0 rows)
+-- This tests the missing_ok parameter, which causes pg_ls_tmpdir to succeed even if the tmpdir doesn't exist yet
+-- The name='' condition is never true, so the function runs to completion but returns zero rows.
+select * from pg_ls_tmpdir() where name='Does not exist';
+ name | size | modification
+------+------+--------------
+(0 rows)
+
+select filename, isdir from pg_ls_dir_metadata('.') where filename='.';
+ filename | isdir
+----------+-------
+ . | t
+(1 row)
+
+select filename, isdir from pg_ls_dir_metadata('.', false, false) where filename='.'; -- include_dot_dirs=false
+ filename | isdir
+----------+-------
+(0 rows)
+
+-- Check that expected columns are present
+select * from pg_ls_dir_metadata('.') limit 0;
+ filename | size | modification | isdir
+----------+------+--------------+-------
+(0 rows)
+
--
-- Test replication slot directory functions
--
diff --git a/src/test/regress/expected/tablespace.out b/src/test/regress/expected/tablespace.out
index c52cf1cfcf9..8159c9f18f1 100644
--- a/src/test/regress/expected/tablespace.out
+++ b/src/test/regress/expected/tablespace.out
@@ -33,6 +33,14 @@ SELECT regexp_replace(pg_tablespace_location(oid), '(pg_tblspc)/(\d+)', '\1/NNN'
pg_tblspc/NNN
(1 row)
+-- This tests the missing_ok parameter, which causes pg_ls_tmpdir to succeed even if the tmpdir doesn't exist yet
+-- The name='' condition is never true, so the function runs to completion but returns zero rows.
+-- The query is written to ERROR if the tablespace doesn't exist, rather than silently failing to call pg_ls_tmpdir()
+SELECT c.* FROM (SELECT oid FROM pg_tablespace b WHERE b.spcname='regress_tblspace' UNION SELECT 0 ORDER BY 1 DESC LIMIT 1) AS b , pg_ls_tmpdir(oid) AS c WHERE c.name='Does not exist';
+ name | size | modification
+------+------+--------------
+(0 rows)
+
-- try setting and resetting some properties for the new tablespace
ALTER TABLESPACE regress_tblspace SET (random_page_cost = 1.0, seq_page_cost = 1.1);
ALTER TABLESPACE regress_tblspace SET (some_nonexistent_parameter = true); -- fail
diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql
index 59d6e517503..fcb456f434d 100644
--- a/src/test/regress/sql/misc_functions.sql
+++ b/src/test/regress/sql/misc_functions.sql
@@ -155,6 +155,17 @@ select * from pg_ls_tmpdir() limit 0;
select * from pg_ls_waldir() limit 0;
select * from pg_stat_file('.') limit 0;
+-- This tests the missing_ok parameter, which causes pg_ls_tmpdir to succeed even if the tmpdir doesn't exist yet
+-- The name='' condition is never true, so the function runs to completion but returns zero rows.
+select * from pg_ls_tmpdir() where name='Does not exist';
+
+select filename, isdir from pg_ls_dir_metadata('.') where filename='.';
+
+select filename, isdir from pg_ls_dir_metadata('.', false, false) where filename='.'; -- include_dot_dirs=false
+
+-- Check that expected columns are present
+select * from pg_ls_dir_metadata('.') limit 0;
+
--
-- Test replication slot directory functions
--
diff --git a/src/test/regress/sql/tablespace.sql b/src/test/regress/sql/tablespace.sql
index 21db433f2a8..cf683c3bf3a 100644
--- a/src/test/regress/sql/tablespace.sql
+++ b/src/test/regress/sql/tablespace.sql
@@ -27,6 +27,11 @@ CREATE TABLESPACE regress_tblspace LOCATION '';
SELECT regexp_replace(pg_tablespace_location(oid), '(pg_tblspc)/(\d+)', '\1/NNN')
FROM pg_tablespace WHERE spcname = 'regress_tblspace';
+-- This tests the missing_ok parameter, which causes pg_ls_tmpdir to succeed even if the tmpdir doesn't exist yet
+-- The name='' condition is never true, so the function runs to completion but returns zero rows.
+-- The query is written to ERROR if the tablespace doesn't exist, rather than silently failing to call pg_ls_tmpdir()
+SELECT c.* FROM (SELECT oid FROM pg_tablespace b WHERE b.spcname='regress_tblspace' UNION SELECT 0 ORDER BY 1 DESC LIMIT 1) AS b , pg_ls_tmpdir(oid) AS c WHERE c.name='Does not exist';
+
-- try setting and resetting some properties for the new tablespace
ALTER TABLESPACE regress_tblspace SET (random_page_cost = 1.0, seq_page_cost = 1.1);
ALTER TABLESPACE regress_tblspace SET (some_nonexistent_parameter = true); -- fail
--
2.17.1
--olLTNZSltDMg5Vbm
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v35-0004-pg_ls_tmpdir-to-show-directories-and-isdir-argum.patch"
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
@ 2022-01-27 00:56 Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Michael Paquier @ 2022-01-27 00:56 UTC (permalink / raw)
To: Bossart, Nathan <[email protected]>; +Cc: Robert Haas <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Tue, Jan 25, 2022 at 07:30:33PM +0000, Bossart, Nathan wrote:
> I think the patch is in decent shape. There may be a few remaining
> places where GetMaxBackends() is called repeatedly in the same
> function, but IIRC v4 already clears up the obvious ones. I don't
> know if this is worth worrying about too much, but I can create a new
> version if you think it is important.
There are such cases in FindLockCycleRecurse(), GetLockConflicts(),
GetLockStatusData() and InitProcGlobal(), as far as I can see.
Hmm. I have been looking at this patch, and the lack of centralized
solution that could be used for other GUCs worries me like Fujii-san,
even if this would prevent an incorrect use of MaxBackends in contexts
where it should not be used because it is not initialized yet. I
don't think it is a good idea in the long-term to apply this as-is.
--
Michael
Attachments:
[application/pgp-signature] signature.asc (833B, ../../[email protected]/2-signature.asc)
download
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
@ 2022-01-27 18:18 ` Nathan Bossart <[email protected]>
2022-01-28 04:22 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
0 siblings, 2 replies; 16+ messages in thread
From: Nathan Bossart @ 2022-01-27 18:18 UTC (permalink / raw)
To: Michael Paquier <[email protected]>; +Cc: Bossart, Nathan <[email protected]>; Robert Haas <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Thu, Jan 27, 2022 at 09:56:04AM +0900, Michael Paquier wrote:
> Hmm. I have been looking at this patch, and the lack of centralized
> solution that could be used for other GUCs worries me like Fujii-san,
> even if this would prevent an incorrect use of MaxBackends in contexts
> where it should not be used because it is not initialized yet. I
> don't think it is a good idea in the long-term to apply this as-is.
Alright. I think the comment adjustments still apply, so I split those out
to a new patch.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com/
Attachments:
[text/x-diff] v7-0001-Adjust-comments-about-registering-background-work.patch (2.6K, ../../20220127181815.GA551692@nathanxps13/2-v7-0001-Adjust-comments-about-registering-background-work.patch)
download | inline diff:
From 4bc21dc199616824b8f5790e8112ebf149f45207 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <[email protected]>
Date: Mon, 2 Aug 2021 17:42:25 +0000
Subject: [PATCH v7 1/1] Adjust comments about registering background workers
before initializing MaxBackends.
Since 6bc8ef0b, InitializeMaxBackends() has used
max_worker_processes instead of tallying up the number of
registered background workers, so background worker registration is
no longer a prerequisite. The ordering of this logic is still
useful for allowing libraries to adjust GUCs, so the comments have
been updated to mention that use-case.
---
src/backend/postmaster/postmaster.c | 10 ++++------
src/backend/utils/init/postinit.c | 5 ++---
2 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index dc4afdd75a..ac0ec0986a 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -1014,10 +1014,8 @@ PostmasterMain(int argc, char *argv[])
LocalProcessControlFile(false);
/*
- * Register the apply launcher. Since it registers a background worker,
- * it needs to be called before InitializeMaxBackends(), and it's probably
- * a good idea to call it before any modules had chance to take the
- * background worker slots.
+ * Register the apply launcher. It's probably a good idea to call this
+ * before any modules had a chance to take the background worker slots.
*/
ApplyLauncherRegister();
@@ -1038,8 +1036,8 @@ PostmasterMain(int argc, char *argv[])
#endif
/*
- * Now that loadable modules have had their chance to register background
- * workers, calculate MaxBackends.
+ * Now that loadable modules have had their chance to alter any GUCs,
+ * calculate MaxBackends.
*/
InitializeMaxBackends();
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index d046caabd7..cd7c829ff5 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -483,9 +483,8 @@ pg_split_opts(char **argv, int *argcp, const char *optstr)
/*
* Initialize MaxBackends value from config options.
*
- * This must be called after modules have had the chance to register background
- * workers in shared_preload_libraries, and before shared memory size is
- * determined.
+ * This must be called after modules have had the chance to alter GUCs in
+ * shared_preload_libraries and before shared memory size is determined.
*
* Note that in EXEC_BACKEND environment, the value is passed down from
* postmaster to subprocesses via BackendParameters in SubPostmasterMain; only
--
2.25.1
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
@ 2022-01-28 04:22 ` Michael Paquier <[email protected]>
1 sibling, 0 replies; 16+ messages in thread
From: Michael Paquier @ 2022-01-28 04:22 UTC (permalink / raw)
To: Nathan Bossart <[email protected]>; +Cc: Bossart, Nathan <[email protected]>; Robert Haas <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Thu, Jan 27, 2022 at 10:18:15AM -0800, Nathan Bossart wrote:
> On Thu, Jan 27, 2022 at 09:56:04AM +0900, Michael Paquier wrote:
>> Hmm. I have been looking at this patch, and the lack of centralized
>> solution that could be used for other GUCs worries me like Fujii-san,
>> even if this would prevent an incorrect use of MaxBackends in contexts
>> where it should not be used because it is not initialized yet. I
>> don't think it is a good idea in the long-term to apply this as-is.
>
> Alright. I think the comment adjustments still apply, so I split those out
> to a new patch.
No objections to this part from here, though I have not checked if
there are other areas that may require such an adjustment.
--
Michael
Attachments:
[application/pgp-signature] signature.asc (833B, ../../[email protected]/2-signature.asc)
download
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
@ 2022-01-29 02:19 ` Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
1 sibling, 1 reply; 16+ messages in thread
From: Michael Paquier @ 2022-01-29 02:19 UTC (permalink / raw)
To: Nathan Bossart <[email protected]>; +Cc: Bossart, Nathan <[email protected]>; Robert Haas <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Thu, Jan 27, 2022 at 10:18:15AM -0800, Nathan Bossart wrote:
> Alright. I think the comment adjustments still apply, so I split those out
> to a new patch.
Looks fine after a second look, so applied.
As of the issues of this thread, we really have two things to think
about:
1) How do we want to control the access of some parameters in a
context or another? One idea would be more control through GUCs, say
with a set of context-related flags that prevent the read of some
variables until they are set. We could encourage the use of
GetConfigOption() for that. For MaxBackends, we could add a read-only
GUC for this purpose. That's what Andres hinted at upthread, I
guess.
2) How do we deal with unwanted access of shared parameters? This one
is not really controllable, is it? And we are talking about much more
than MaxBackends. This could perhaps be addressed with more
documentation in the headers for the concerned variables, as a first
step.
--
Michael
Attachments:
[application/pgp-signature] signature.asc (833B, ../../[email protected]/2-signature.asc)
download
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
@ 2022-01-31 14:32 ` Robert Haas <[email protected]>
2022-02-01 22:36 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Robert Haas @ 2022-01-31 14:32 UTC (permalink / raw)
To: Michael Paquier <[email protected]>; +Cc: Nathan Bossart <[email protected]>; Bossart, Nathan <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Fri, Jan 28, 2022 at 9:19 PM Michael Paquier <[email protected]> wrote:
> As of the issues of this thread, we really have two things to think
> about:
> 1) How do we want to control the access of some parameters in a
> context or another? One idea would be more control through GUCs, say
> with a set of context-related flags that prevent the read of some
> variables until they are set. We could encourage the use of
> GetConfigOption() for that. For MaxBackends, we could add a read-only
> GUC for this purpose. That's what Andres hinted at upthread, I
> guess.
> 2) How do we deal with unwanted access of shared parameters? This one
> is not really controllable, is it? And we are talking about much more
> than MaxBackends. This could perhaps be addressed with more
> documentation in the headers for the concerned variables, as a first
> step.
I think you are mischaracterizing the problem. MaxBackends is not
max_connections. It is a value which is computed based on the value of
max_connections and various other GUCs. And that's the problem. If you
have a C variable whose value should depend on a single GUC, the GUC
system will generally do what you want automatically. If it doesn't,
you can use the GUC check hook/assign hook machinery to update as many
global variables as you like whenever the GUC itself is updated.
Moreover, a GUC always has some legal and thus halfway reasonable
value. We read postgresql.conf super-early in the startup sequence,
because we know GUCs are super-important, and even before that
settings have bootstrap values which are not usually totally insane.
The bottom line is that if you have a global variable whose value
depends on one GUC, you can probably just read that global variable
and call it good.
The main reason why this doesn't work for MaxBackends is that
MaxBackends depends on the values of multiple GUCs. There is a further
wrinkle too, which is that none of those GUCs can change, and
therefore code does things with the resulting value on the assumption
that they won't change, like size shared-memory data structures.
Therefore, if you read the wrong value, you've got a big problem. So
the real issues here IMHO are about the difficulty of making sure that
(1) when a GUC changes, we update all of the things that depend on it
including things which may also depend on other GUCs and (2) making
sure that values which can't ever change are computed before they are
used.
I don't know what the solution to problem #1 is, but the solution to
problem #2 is simple: make people call a function to get the value
rather than just reading a bare variable. GetConfigOption() is not a
good solution for people aiming to write C code that does useful
things, because it delivers the value as a string, and that is not
what you want. But an accessor function like GetMaxBackends() for a
quantity of this type is wonderful. Depending on the situation, you
might choose to have the accessor function [a] fail an assertion if
the value is not available yet or [b] compute the value if they value
has not yet been computed or [c] do the latter if possible, otherwise
the former. But the fact that you are making code call a function
rather than just read a variable gives you a very strong tool to make
sure that someone can't blindly read a 0 or whatever instead of the
real value.
Therefore, it is my opinion that the proposed patch was pretty much
right on the money and that we ought to get it committed.
--
Robert Haas
EDB: http://www.enterprisedb.com
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
@ 2022-02-01 22:36 ` Nathan Bossart <[email protected]>
2022-02-02 13:15 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Nathan Bossart @ 2022-02-01 22:36 UTC (permalink / raw)
To: Robert Haas <[email protected]>; +Cc: Michael Paquier <[email protected]>; Bossart, Nathan <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Mon, Jan 31, 2022 at 09:32:21AM -0500, Robert Haas wrote:
> The main reason why this doesn't work for MaxBackends is that
> MaxBackends depends on the values of multiple GUCs. There is a further
> wrinkle too, which is that none of those GUCs can change, and
> therefore code does things with the resulting value on the assumption
> that they won't change, like size shared-memory data structures.
> Therefore, if you read the wrong value, you've got a big problem. So
> the real issues here IMHO are about the difficulty of making sure that
> (1) when a GUC changes, we update all of the things that depend on it
> including things which may also depend on other GUCs and (2) making
> sure that values which can't ever change are computed before they are
> used.
>
> I don't know what the solution to problem #1 is, but the solution to
> problem #2 is simple: make people call a function to get the value
> rather than just reading a bare variable. GetConfigOption() is not a
> good solution for people aiming to write C code that does useful
> things, because it delivers the value as a string, and that is not
> what you want. But an accessor function like GetMaxBackends() for a
> quantity of this type is wonderful. Depending on the situation, you
> might choose to have the accessor function [a] fail an assertion if
> the value is not available yet or [b] compute the value if they value
> has not yet been computed or [c] do the latter if possible, otherwise
> the former. But the fact that you are making code call a function
> rather than just read a variable gives you a very strong tool to make
> sure that someone can't blindly read a 0 or whatever instead of the
> real value.
+1
I can work on a new patch if this is the direction we want to go. There
were a couple of functions that called GetMaxBackends() repetitively that I
should probably fix before the patch should be seriously considered.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-01 22:36 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
@ 2022-02-02 13:15 ` Robert Haas <[email protected]>
2022-02-04 05:54 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Robert Haas @ 2022-02-02 13:15 UTC (permalink / raw)
To: Nathan Bossart <[email protected]>; +Cc: Michael Paquier <[email protected]>; Bossart, Nathan <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Tue, Feb 1, 2022 at 5:36 PM Nathan Bossart <[email protected]> wrote:
> I can work on a new patch if this is the direction we want to go. There
> were a couple of functions that called GetMaxBackends() repetitively that I
> should probably fix before the patch should be seriously considered.
Sure, that sort of thing should be tidied up. It's unlikely to make
any real difference, but as a fairly prominent PostgreSQL hacker once
said, a cycle saved is a cycle earned.
--
Robert Haas
EDB: http://www.enterprisedb.com
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-01 22:36 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-02 13:15 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
@ 2022-02-04 05:54 ` Nathan Bossart <[email protected]>
2022-02-04 13:46 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Nathan Bossart @ 2022-02-04 05:54 UTC (permalink / raw)
To: Robert Haas <[email protected]>; +Cc: Michael Paquier <[email protected]>; Bossart, Nathan <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Wed, Feb 02, 2022 at 08:15:02AM -0500, Robert Haas wrote:
> On Tue, Feb 1, 2022 at 5:36 PM Nathan Bossart <[email protected]> wrote:
>> I can work on a new patch if this is the direction we want to go. There
>> were a couple of functions that called GetMaxBackends() repetitively that I
>> should probably fix before the patch should be seriously considered.
>
> Sure, that sort of thing should be tidied up. It's unlikely to make
> any real difference, but as a fairly prominent PostgreSQL hacker once
> said, a cycle saved is a cycle earned.
Here is a new patch with fewer calls to GetMaxBackends().
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
[text/x-diff] v8-0001-Disallow-external-access-to-MaxBackends.patch (39.7K, ../../20220204055457.GA1335041@nathanxps13/2-v8-0001-Disallow-external-access-to-MaxBackends.patch)
download | inline diff:
From 2d0ad3b35b0b0d537599f0bbf8b1d6d8ec297156 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <[email protected]>
Date: Mon, 16 Aug 2021 02:59:32 +0000
Subject: [PATCH v8 1/1] Disallow external access to MaxBackends.
Presently, MaxBackends is externally visible, but it may still be
uninitialized in places where it would be convenient to use (e.g.,
_PG_init()). This change makes MaxBackends static to postinit.c to
disallow such direct access. Instead, MaxBackends should now be
accessed via GetMaxBackends().
---
src/backend/access/nbtree/nbtutils.c | 4 +-
src/backend/access/transam/multixact.c | 8 ++-
src/backend/access/transam/twophase.c | 3 +-
src/backend/commands/async.c | 11 ++--
src/backend/libpq/pqcomm.c | 3 +-
src/backend/postmaster/auxprocess.c | 2 +-
src/backend/postmaster/postmaster.c | 4 +-
src/backend/storage/ipc/dsm.c | 2 +-
src/backend/storage/ipc/procarray.c | 2 +-
src/backend/storage/ipc/procsignal.c | 17 ++++--
src/backend/storage/ipc/sinvaladt.c | 4 +-
src/backend/storage/lmgr/deadlock.c | 31 +++++-----
src/backend/storage/lmgr/lock.c | 23 ++++----
src/backend/storage/lmgr/predicate.c | 10 ++--
src/backend/storage/lmgr/proc.c | 17 +++---
src/backend/utils/activity/backend_status.c | 63 +++++++++++----------
src/backend/utils/adt/lockfuncs.c | 5 +-
src/backend/utils/init/postinit.c | 50 ++++++++++++++--
src/include/miscadmin.h | 3 +-
19 files changed, 161 insertions(+), 101 deletions(-)
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 6a651d8397..84164748b3 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -2072,7 +2072,7 @@ BTreeShmemSize(void)
Size size;
size = offsetof(BTVacInfo, vacuums);
- size = add_size(size, mul_size(MaxBackends, sizeof(BTOneVacInfo)));
+ size = add_size(size, mul_size(GetMaxBackends(), sizeof(BTOneVacInfo)));
return size;
}
@@ -2101,7 +2101,7 @@ BTreeShmemInit(void)
btvacinfo->cycle_ctr = (BTCycleId) time(NULL);
btvacinfo->num_vacuums = 0;
- btvacinfo->max_vacuums = MaxBackends;
+ btvacinfo->max_vacuums = GetMaxBackends();
}
else
Assert(found);
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 806f2e43ba..9ee805078c 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -285,7 +285,7 @@ typedef struct MultiXactStateData
* Last element of OldestMemberMXactId and OldestVisibleMXactId arrays.
* Valid elements are (1..MaxOldestSlot); element 0 is never used.
*/
-#define MaxOldestSlot (MaxBackends + max_prepared_xacts)
+#define MaxOldestSlot (GetMaxBackends() + max_prepared_xacts)
/* Pointers to the state data in shared memory */
static MultiXactStateData *MultiXactState;
@@ -684,6 +684,7 @@ MultiXactIdSetOldestVisible(void)
if (!MultiXactIdIsValid(OldestVisibleMXactId[MyBackendId]))
{
MultiXactId oldestMXact;
+ int maxOldestSlot = MaxOldestSlot;
int i;
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
@@ -697,7 +698,7 @@ MultiXactIdSetOldestVisible(void)
if (oldestMXact < FirstMultiXactId)
oldestMXact = FirstMultiXactId;
- for (i = 1; i <= MaxOldestSlot; i++)
+ for (i = 1; i <= maxOldestSlot; i++)
{
MultiXactId thisoldest = OldestMemberMXactId[i];
@@ -2507,6 +2508,7 @@ GetOldestMultiXactId(void)
{
MultiXactId oldestMXact;
MultiXactId nextMXact;
+ int maxOldestSlot = MaxOldestSlot;
int i;
/*
@@ -2525,7 +2527,7 @@ GetOldestMultiXactId(void)
nextMXact = FirstMultiXactId;
oldestMXact = nextMXact;
- for (i = 1; i <= MaxOldestSlot; i++)
+ for (i = 1; i <= maxOldestSlot; i++)
{
MultiXactId thisoldest;
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 271a3146db..608c5149e5 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -260,6 +260,7 @@ TwoPhaseShmemInit(void)
{
GlobalTransaction gxacts;
int i;
+ int max_backends = GetMaxBackends();
Assert(!found);
TwoPhaseState->freeGXacts = NULL;
@@ -293,7 +294,7 @@ TwoPhaseShmemInit(void)
* prepared transaction. Currently multixact.c uses that
* technique.
*/
- gxacts[i].dummyBackendId = MaxBackends + 1 + i;
+ gxacts[i].dummyBackendId = max_backends + 1 + i;
}
}
else
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 3e1b92df03..d44001a49f 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -518,7 +518,7 @@ AsyncShmemSize(void)
Size size;
/* This had better match AsyncShmemInit */
- size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
+ size = mul_size(GetMaxBackends() + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
@@ -534,6 +534,7 @@ AsyncShmemInit(void)
{
bool found;
Size size;
+ int max_backends = GetMaxBackends();
/*
* Create or attach to the AsyncQueueControl structure.
@@ -541,7 +542,7 @@ AsyncShmemInit(void)
* The used entries in the backend[] array run from 1 to MaxBackends; the
* zero'th entry is unused but must be allocated.
*/
- size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
+ size = mul_size(max_backends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
asyncQueueControl = (AsyncQueueControl *)
@@ -556,7 +557,7 @@ AsyncShmemInit(void)
QUEUE_FIRST_LISTENER = InvalidBackendId;
asyncQueueControl->lastQueueFillWarn = 0;
/* zero'th entry won't be used, but let's initialize it anyway */
- for (int i = 0; i <= MaxBackends; i++)
+ for (int i = 0; i <= max_backends; i++)
{
QUEUE_BACKEND_PID(i) = InvalidPid;
QUEUE_BACKEND_DBOID(i) = InvalidOid;
@@ -1641,8 +1642,8 @@ SignalBackends(void)
* XXX in principle these pallocs could fail, which would be bad. Maybe
* preallocate the arrays? They're not that large, though.
*/
- pids = (int32 *) palloc(MaxBackends * sizeof(int32));
- ids = (BackendId *) palloc(MaxBackends * sizeof(BackendId));
+ pids = (int32 *) palloc(GetMaxBackends() * sizeof(int32));
+ ids = (BackendId *) palloc(GetMaxBackends() * sizeof(BackendId));
count = 0;
LWLockAcquire(NotifyQueueLock, LW_EXCLUSIVE);
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index f05723dc92..22eb04948e 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -349,6 +349,7 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
struct addrinfo hint;
int listen_index = 0;
int added = 0;
+ int max_backends = GetMaxBackends();
#ifdef HAVE_UNIX_SOCKETS
char unixSocketPath[MAXPGPATH];
@@ -571,7 +572,7 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
* intended to provide a clamp on the request on platforms where an
* overly large request provokes a kernel error (are there any?).
*/
- maxconn = MaxBackends * 2;
+ maxconn = max_backends * 2;
if (maxconn > PG_SOMAXCONN)
maxconn = PG_SOMAXCONN;
diff --git a/src/backend/postmaster/auxprocess.c b/src/backend/postmaster/auxprocess.c
index 39ac4490db..0587e45920 100644
--- a/src/backend/postmaster/auxprocess.c
+++ b/src/backend/postmaster/auxprocess.c
@@ -116,7 +116,7 @@ AuxiliaryProcessMain(AuxProcType auxtype)
* This will need rethinking if we ever want more than one of a particular
* auxiliary process type.
*/
- ProcSignalInit(MaxBackends + MyAuxProcType + 1);
+ ProcSignalInit(GetMaxBackends() + MyAuxProcType + 1);
/*
* Auxiliary processes don't run transactions, but they may need a
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index ac0ec0986a..ce90877154 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -6260,7 +6260,7 @@ save_backend_variables(BackendParameters *param, Port *port,
param->query_id_enabled = query_id_enabled;
param->max_safe_fds = max_safe_fds;
- param->MaxBackends = MaxBackends;
+ param->MaxBackends = GetMaxBackends();
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
@@ -6494,7 +6494,7 @@ restore_backend_variables(BackendParameters *param, Port *port)
query_id_enabled = param->query_id_enabled;
max_safe_fds = param->max_safe_fds;
- MaxBackends = param->MaxBackends;
+ SetMaxBackends(param->MaxBackends);
#ifdef WIN32
PostmasterHandle = param->PostmasterHandle;
diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index ae75141592..e9e9fae3eb 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -166,7 +166,7 @@ dsm_postmaster_startup(PGShmemHeader *shim)
/* Determine size for new control segment. */
maxitems = PG_DYNSHMEM_FIXED_SLOTS
- + PG_DYNSHMEM_SLOTS_PER_BACKEND * MaxBackends;
+ + PG_DYNSHMEM_SLOTS_PER_BACKEND * GetMaxBackends();
elog(DEBUG2, "dynamic shared memory system will support %u segments",
maxitems);
segsize = dsm_control_bytes_needed(maxitems);
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 9d3efb7d80..3e5dca78f4 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -365,7 +365,7 @@ ProcArrayShmemSize(void)
Size size;
/* Size of the ProcArray structure itself */
-#define PROCARRAY_MAXPROCS (MaxBackends + max_prepared_xacts)
+#define PROCARRAY_MAXPROCS (GetMaxBackends() + max_prepared_xacts)
size = offsetof(ProcArrayStruct, pgprocnos);
size = add_size(size, mul_size(sizeof(int), PROCARRAY_MAXPROCS));
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index f1c8ff8f9e..0fbb05bc3e 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -85,7 +85,7 @@ typedef struct
* possible auxiliary process type. (This scheme assumes there is not
* more than one of any auxiliary process type at a time.)
*/
-#define NumProcSignalSlots (MaxBackends + NUM_AUXPROCTYPES)
+#define NumProcSignalSlots (GetMaxBackends() + NUM_AUXPROCTYPES)
/* Check whether the relevant type bit is set in the flags. */
#define BARRIER_SHOULD_CHECK(flags, type) \
@@ -126,6 +126,7 @@ ProcSignalShmemInit(void)
{
Size size = ProcSignalShmemSize();
bool found;
+ int numProcSignalSlots = NumProcSignalSlots;
ProcSignal = (ProcSignalHeader *)
ShmemInitStruct("ProcSignal", size, &found);
@@ -137,7 +138,7 @@ ProcSignalShmemInit(void)
pg_atomic_init_u64(&ProcSignal->psh_barrierGeneration, 0);
- for (i = 0; i < NumProcSignalSlots; ++i)
+ for (i = 0; i < numProcSignalSlots; ++i)
{
ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
@@ -291,8 +292,9 @@ SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
* process, which will have a slot near the end of the array.
*/
int i;
+ int numProcSignalSlots = NumProcSignalSlots;
- for (i = NumProcSignalSlots - 1; i >= 0; i--)
+ for (i = numProcSignalSlots - 1; i >= 0; i--)
{
slot = &ProcSignal->psh_slot[i];
@@ -333,6 +335,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
{
uint32 flagbit = 1 << (uint32) type;
uint64 generation;
+ int numProcSignalSlots = NumProcSignalSlots;
/*
* Set all the flags.
@@ -342,7 +345,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
* anything that we do afterwards. (This is also true of the later call to
* pg_atomic_add_fetch_u64.)
*/
- for (int i = 0; i < NumProcSignalSlots; i++)
+ for (int i = 0; i < numProcSignalSlots; i++)
{
volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
@@ -368,7 +371,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
* backends that need to update state - but they won't actually need to
* change any state.
*/
- for (int i = NumProcSignalSlots - 1; i >= 0; i--)
+ for (int i = numProcSignalSlots - 1; i >= 0; i--)
{
volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
pid_t pid = slot->pss_pid;
@@ -391,9 +394,11 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
void
WaitForProcSignalBarrier(uint64 generation)
{
+ int numProcSignalSlots = NumProcSignalSlots;
+
Assert(generation <= pg_atomic_read_u64(&ProcSignal->psh_barrierGeneration));
- for (int i = NumProcSignalSlots - 1; i >= 0; i--)
+ for (int i = numProcSignalSlots - 1; i >= 0; i--)
{
ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
uint64 oldval;
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index cb3ee82046..68e7160b30 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -205,7 +205,7 @@ SInvalShmemSize(void)
Size size;
size = offsetof(SISeg, procState);
- size = add_size(size, mul_size(sizeof(ProcState), MaxBackends));
+ size = add_size(size, mul_size(sizeof(ProcState), GetMaxBackends()));
return size;
}
@@ -231,7 +231,7 @@ CreateSharedInvalidationState(void)
shmInvalBuffer->maxMsgNum = 0;
shmInvalBuffer->nextThreshold = CLEANUP_MIN;
shmInvalBuffer->lastBackend = 0;
- shmInvalBuffer->maxBackends = MaxBackends;
+ shmInvalBuffer->maxBackends = GetMaxBackends();
SpinLockInit(&shmInvalBuffer->msgnumLock);
/* The buffer[] array is initially all unused, so we need not fill it */
diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c
index cd9c0418ec..b5d539ba5d 100644
--- a/src/backend/storage/lmgr/deadlock.c
+++ b/src/backend/storage/lmgr/deadlock.c
@@ -143,6 +143,7 @@ void
InitDeadLockChecking(void)
{
MemoryContext oldcxt;
+ int max_backends = GetMaxBackends();
/* Make sure allocations are permanent */
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
@@ -151,16 +152,16 @@ InitDeadLockChecking(void)
* FindLockCycle needs at most MaxBackends entries in visitedProcs[] and
* deadlockDetails[].
*/
- visitedProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
- deadlockDetails = (DEADLOCK_INFO *) palloc(MaxBackends * sizeof(DEADLOCK_INFO));
+ visitedProcs = (PGPROC **) palloc(max_backends * sizeof(PGPROC *));
+ deadlockDetails = (DEADLOCK_INFO *) palloc(max_backends * sizeof(DEADLOCK_INFO));
/*
* TopoSort needs to consider at most MaxBackends wait-queue entries, and
* it needn't run concurrently with FindLockCycle.
*/
topoProcs = visitedProcs; /* re-use this space */
- beforeConstraints = (int *) palloc(MaxBackends * sizeof(int));
- afterConstraints = (int *) palloc(MaxBackends * sizeof(int));
+ beforeConstraints = (int *) palloc(max_backends * sizeof(int));
+ afterConstraints = (int *) palloc(max_backends * sizeof(int));
/*
* We need to consider rearranging at most MaxBackends/2 wait queues
@@ -169,8 +170,8 @@ InitDeadLockChecking(void)
* MaxBackends total waiters.
*/
waitOrders = (WAIT_ORDER *)
- palloc((MaxBackends / 2) * sizeof(WAIT_ORDER));
- waitOrderProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
+ palloc((max_backends / 2) * sizeof(WAIT_ORDER));
+ waitOrderProcs = (PGPROC **) palloc(max_backends * sizeof(PGPROC *));
/*
* Allow at most MaxBackends distinct constraints in a configuration. (Is
@@ -180,7 +181,7 @@ InitDeadLockChecking(void)
* limits the maximum recursion depth of DeadLockCheckRecurse. Making it
* really big might potentially allow a stack-overflow problem.
*/
- maxCurConstraints = MaxBackends;
+ maxCurConstraints = max_backends;
curConstraints = (EDGE *) palloc(maxCurConstraints * sizeof(EDGE));
/*
@@ -191,7 +192,7 @@ InitDeadLockChecking(void)
* last MaxBackends entries in possibleConstraints[] are reserved as
* output workspace for FindLockCycle.
*/
- maxPossibleConstraints = MaxBackends * 4;
+ maxPossibleConstraints = max_backends * 4;
possibleConstraints =
(EDGE *) palloc(maxPossibleConstraints * sizeof(EDGE));
@@ -327,7 +328,7 @@ DeadLockCheckRecurse(PGPROC *proc)
if (nCurConstraints >= maxCurConstraints)
return true; /* out of room for active constraints? */
oldPossibleConstraints = nPossibleConstraints;
- if (nPossibleConstraints + nEdges + MaxBackends <= maxPossibleConstraints)
+ if (nPossibleConstraints + nEdges + GetMaxBackends() <= maxPossibleConstraints)
{
/* We can save the edge list in possibleConstraints[] */
nPossibleConstraints += nEdges;
@@ -388,7 +389,7 @@ TestConfiguration(PGPROC *startProc)
/*
* Make sure we have room for FindLockCycle's output.
*/
- if (nPossibleConstraints + MaxBackends > maxPossibleConstraints)
+ if (nPossibleConstraints + GetMaxBackends() > maxPossibleConstraints)
return -1;
/*
@@ -486,7 +487,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
* record total length of cycle --- outer levels will now fill
* deadlockDetails[]
*/
- Assert(depth <= MaxBackends);
+ Assert(depth <= GetMaxBackends());
nDeadlockDetails = depth;
return true;
@@ -500,7 +501,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
}
}
/* Mark proc as seen */
- Assert(nVisitedProcs < MaxBackends);
+ Assert(nVisitedProcs < GetMaxBackends());
visitedProcs[nVisitedProcs++] = checkProc;
/*
@@ -698,7 +699,7 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
/*
* Add this edge to the list of soft edges in the cycle
*/
- Assert(*nSoftEdges < MaxBackends);
+ Assert(*nSoftEdges < GetMaxBackends());
softEdges[*nSoftEdges].waiter = checkProcLeader;
softEdges[*nSoftEdges].blocker = leader;
softEdges[*nSoftEdges].lock = lock;
@@ -771,7 +772,7 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
/*
* Add this edge to the list of soft edges in the cycle
*/
- Assert(*nSoftEdges < MaxBackends);
+ Assert(*nSoftEdges < GetMaxBackends());
softEdges[*nSoftEdges].waiter = checkProcLeader;
softEdges[*nSoftEdges].blocker = leader;
softEdges[*nSoftEdges].lock = lock;
@@ -834,7 +835,7 @@ ExpandConstraints(EDGE *constraints,
waitOrders[nWaitOrders].procs = waitOrderProcs + nWaitOrderProcs;
waitOrders[nWaitOrders].nProcs = lock->waitProcs.size;
nWaitOrderProcs += lock->waitProcs.size;
- Assert(nWaitOrderProcs <= MaxBackends);
+ Assert(nWaitOrderProcs <= GetMaxBackends());
/*
* Do the topo sort. TopoSort need not examine constraints after this
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 5f5803f681..ee2e15c17e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -55,7 +55,7 @@
int max_locks_per_xact; /* set by guc.c */
#define NLOCKENTS() \
- mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
+ mul_size(max_locks_per_xact, add_size(GetMaxBackends(), max_prepared_xacts))
/*
@@ -2924,6 +2924,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
LWLock *partitionLock;
int count = 0;
int fast_count = 0;
+ int max_backends = GetMaxBackends();
if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
elog(ERROR, "unrecognized lock method: %d", lockmethodid);
@@ -2942,12 +2943,12 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
vxids = (VirtualTransactionId *)
MemoryContextAlloc(TopMemoryContext,
sizeof(VirtualTransactionId) *
- (MaxBackends + max_prepared_xacts + 1));
+ (max_backends + max_prepared_xacts + 1));
}
else
vxids = (VirtualTransactionId *)
palloc0(sizeof(VirtualTransactionId) *
- (MaxBackends + max_prepared_xacts + 1));
+ (max_backends + max_prepared_xacts + 1));
/* Compute hash code and partition lock, and look up conflicting modes. */
hashcode = LockTagHashCode(locktag);
@@ -3104,7 +3105,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
LWLockRelease(partitionLock);
- if (count > MaxBackends + max_prepared_xacts) /* should never happen */
+ if (count > max_backends + max_prepared_xacts) /* should never happen */
elog(PANIC, "too many conflicting locks found");
vxids[count].backendId = InvalidBackendId;
@@ -3651,11 +3652,12 @@ GetLockStatusData(void)
int els;
int el;
int i;
+ int max_backends = GetMaxBackends();
data = (LockData *) palloc(sizeof(LockData));
/* Guess how much space we'll need. */
- els = MaxBackends;
+ els = max_backends;
el = 0;
data->locks = (LockInstanceData *) palloc(sizeof(LockInstanceData) * els);
@@ -3689,7 +3691,7 @@ GetLockStatusData(void)
if (el >= els)
{
- els += MaxBackends;
+ els += max_backends;
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * els);
}
@@ -3721,7 +3723,7 @@ GetLockStatusData(void)
if (el >= els)
{
- els += MaxBackends;
+ els += max_backends;
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * els);
}
@@ -3850,7 +3852,7 @@ GetBlockerStatusData(int blocked_pid)
* for the procs[] array; the other two could need enlargement, though.)
*/
data->nprocs = data->nlocks = data->npids = 0;
- data->maxprocs = data->maxlocks = data->maxpids = MaxBackends;
+ data->maxprocs = data->maxlocks = data->maxpids = GetMaxBackends();
data->procs = (BlockedProcData *) palloc(sizeof(BlockedProcData) * data->maxprocs);
data->locks = (LockInstanceData *) palloc(sizeof(LockInstanceData) * data->maxlocks);
data->waiter_pids = (int *) palloc(sizeof(int) * data->maxpids);
@@ -3925,6 +3927,7 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
PGPROC *proc;
int queue_size;
int i;
+ int max_backends = GetMaxBackends();
/* Nothing to do if this proc is not blocked */
if (theLock == NULL)
@@ -3953,7 +3956,7 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
if (data->nlocks >= data->maxlocks)
{
- data->maxlocks += MaxBackends;
+ data->maxlocks += max_backends;
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * data->maxlocks);
}
@@ -3982,7 +3985,7 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
if (queue_size > data->maxpids - data->npids)
{
- data->maxpids = Max(data->maxpids + MaxBackends,
+ data->maxpids = Max(data->maxpids + max_backends,
data->npids + queue_size);
data->waiter_pids = (int *) repalloc(data->waiter_pids,
sizeof(int) * data->maxpids);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 25e7e4e37b..e337aad5b2 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -257,7 +257,7 @@
(&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
#define NPREDICATELOCKTARGETENTS() \
- mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
+ mul_size(max_predicate_locks_per_xact, add_size(GetMaxBackends(), max_prepared_xacts))
#define SxactIsOnFinishedList(sxact) (!SHMQueueIsDetached(&((sxact)->finishedLink)))
@@ -1222,7 +1222,7 @@ InitPredicateLocks(void)
* Compute size for serializable transaction hashtable. Note these
* calculations must agree with PredicateLockShmemSize!
*/
- max_table_size = (MaxBackends + max_prepared_xacts);
+ max_table_size = (GetMaxBackends() + max_prepared_xacts);
/*
* Allocate a list to hold information on transactions participating in
@@ -1375,7 +1375,7 @@ PredicateLockShmemSize(void)
size = add_size(size, size / 10);
/* transaction list */
- max_table_size = MaxBackends + max_prepared_xacts;
+ max_table_size = GetMaxBackends() + max_prepared_xacts;
max_table_size *= 10;
size = add_size(size, PredXactListDataSize);
size = add_size(size, mul_size((Size) max_table_size,
@@ -1907,7 +1907,7 @@ GetSerializableTransactionSnapshotInt(Snapshot snapshot,
{
++(PredXact->WritableSxactCount);
Assert(PredXact->WritableSxactCount <=
- (MaxBackends + max_prepared_xacts));
+ (GetMaxBackends() + max_prepared_xacts));
}
MySerializableXact = sxact;
@@ -5111,7 +5111,7 @@ predicatelock_twophase_recover(TransactionId xid, uint16 info,
{
++(PredXact->WritableSxactCount);
Assert(PredXact->WritableSxactCount <=
- (MaxBackends + max_prepared_xacts));
+ (GetMaxBackends() + max_prepared_xacts));
}
/*
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index e306b04738..37f032e7b9 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -103,7 +103,7 @@ ProcGlobalShmemSize(void)
{
Size size = 0;
Size TotalProcs =
- add_size(MaxBackends, add_size(NUM_AUXILIARY_PROCS, max_prepared_xacts));
+ add_size(GetMaxBackends(), add_size(NUM_AUXILIARY_PROCS, max_prepared_xacts));
/* ProcGlobal */
size = add_size(size, sizeof(PROC_HDR));
@@ -127,7 +127,7 @@ ProcGlobalSemas(void)
* We need a sema per backend (including autovacuum), plus one for each
* auxiliary process.
*/
- return MaxBackends + NUM_AUXILIARY_PROCS;
+ return GetMaxBackends() + NUM_AUXILIARY_PROCS;
}
/*
@@ -162,7 +162,8 @@ InitProcGlobal(void)
int i,
j;
bool found;
- uint32 TotalProcs = MaxBackends + NUM_AUXILIARY_PROCS + max_prepared_xacts;
+ int max_backends = GetMaxBackends();
+ uint32 TotalProcs = max_backends + NUM_AUXILIARY_PROCS + max_prepared_xacts;
/* Create the ProcGlobal shared structure */
ProcGlobal = (PROC_HDR *)
@@ -195,7 +196,7 @@ InitProcGlobal(void)
MemSet(procs, 0, TotalProcs * sizeof(PGPROC));
ProcGlobal->allProcs = procs;
/* XXX allProcCount isn't really all of them; it excludes prepared xacts */
- ProcGlobal->allProcCount = MaxBackends + NUM_AUXILIARY_PROCS;
+ ProcGlobal->allProcCount = max_backends + NUM_AUXILIARY_PROCS;
/*
* Allocate arrays mirroring PGPROC fields in a dense manner. See
@@ -221,7 +222,7 @@ InitProcGlobal(void)
* dummy PGPROCs don't need these though - they're never associated
* with a real process
*/
- if (i < MaxBackends + NUM_AUXILIARY_PROCS)
+ if (i < max_backends + NUM_AUXILIARY_PROCS)
{
procs[i].sem = PGSemaphoreCreate();
InitSharedLatch(&(procs[i].procLatch));
@@ -258,7 +259,7 @@ InitProcGlobal(void)
ProcGlobal->bgworkerFreeProcs = &procs[i];
procs[i].procgloballist = &ProcGlobal->bgworkerFreeProcs;
}
- else if (i < MaxBackends)
+ else if (i < max_backends)
{
/* PGPROC for walsender, add to walsenderFreeProcs list */
procs[i].links.next = (SHM_QUEUE *) ProcGlobal->walsenderFreeProcs;
@@ -286,8 +287,8 @@ InitProcGlobal(void)
* Save pointers to the blocks of PGPROC structures reserved for auxiliary
* processes and prepared transactions.
*/
- AuxiliaryProcs = &procs[MaxBackends];
- PreparedXactProcs = &procs[MaxBackends + NUM_AUXILIARY_PROCS];
+ AuxiliaryProcs = &procs[max_backends];
+ PreparedXactProcs = &procs[max_backends + NUM_AUXILIARY_PROCS];
/* Create ProcStructLock spinlock, too */
ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index c7ed1e6d7a..fc6dcd191b 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -35,7 +35,7 @@
* includes autovacuum workers and background workers as well.
* ----------
*/
-#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
+#define NumBackendStatSlots (GetMaxBackends() + NUM_AUXPROCTYPES)
/* ----------
@@ -84,27 +84,28 @@ Size
BackendStatusShmemSize(void)
{
Size size;
+ int numBackendStatSlots = NumBackendStatSlots;
/* BackendStatusArray: */
- size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendStatus), numBackendStatSlots);
/* BackendAppnameBuffer: */
size = add_size(size,
- mul_size(NAMEDATALEN, NumBackendStatSlots));
+ mul_size(NAMEDATALEN, numBackendStatSlots));
/* BackendClientHostnameBuffer: */
size = add_size(size,
- mul_size(NAMEDATALEN, NumBackendStatSlots));
+ mul_size(NAMEDATALEN, numBackendStatSlots));
/* BackendActivityBuffer: */
size = add_size(size,
- mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
+ mul_size(pgstat_track_activity_query_size, numBackendStatSlots));
#ifdef USE_SSL
/* BackendSslStatusBuffer: */
size = add_size(size,
- mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
+ mul_size(sizeof(PgBackendSSLStatus), numBackendStatSlots));
#endif
#ifdef ENABLE_GSS
/* BackendGssStatusBuffer: */
size = add_size(size,
- mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots));
+ mul_size(sizeof(PgBackendGSSStatus), numBackendStatSlots));
#endif
return size;
}
@@ -120,9 +121,10 @@ CreateSharedBackendStatus(void)
bool found;
int i;
char *buffer;
+ int numBackendStatSlots = NumBackendStatSlots;
/* Create or attach to the shared array */
- size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendStatus), numBackendStatSlots);
BackendStatusArray = (PgBackendStatus *)
ShmemInitStruct("Backend Status Array", size, &found);
@@ -135,7 +137,7 @@ CreateSharedBackendStatus(void)
}
/* Create or attach to the shared appname buffer */
- size = mul_size(NAMEDATALEN, NumBackendStatSlots);
+ size = mul_size(NAMEDATALEN, numBackendStatSlots);
BackendAppnameBuffer = (char *)
ShmemInitStruct("Backend Application Name Buffer", size, &found);
@@ -145,7 +147,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_appname pointers. */
buffer = BackendAppnameBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_appname = buffer;
buffer += NAMEDATALEN;
@@ -153,7 +155,7 @@ CreateSharedBackendStatus(void)
}
/* Create or attach to the shared client hostname buffer */
- size = mul_size(NAMEDATALEN, NumBackendStatSlots);
+ size = mul_size(NAMEDATALEN, numBackendStatSlots);
BackendClientHostnameBuffer = (char *)
ShmemInitStruct("Backend Client Host Name Buffer", size, &found);
@@ -163,7 +165,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_clienthostname pointers. */
buffer = BackendClientHostnameBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_clienthostname = buffer;
buffer += NAMEDATALEN;
@@ -172,7 +174,7 @@ CreateSharedBackendStatus(void)
/* Create or attach to the shared activity buffer */
BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
- NumBackendStatSlots);
+ numBackendStatSlots);
BackendActivityBuffer = (char *)
ShmemInitStruct("Backend Activity Buffer",
BackendActivityBufferSize,
@@ -184,7 +186,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_activity pointers. */
buffer = BackendActivityBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_activity_raw = buffer;
buffer += pgstat_track_activity_query_size;
@@ -193,7 +195,7 @@ CreateSharedBackendStatus(void)
#ifdef USE_SSL
/* Create or attach to the shared SSL status buffer */
- size = mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendSSLStatus), numBackendStatSlots);
BackendSslStatusBuffer = (PgBackendSSLStatus *)
ShmemInitStruct("Backend SSL Status Buffer", size, &found);
@@ -205,7 +207,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_sslstatus pointers. */
ptr = BackendSslStatusBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_sslstatus = ptr;
ptr++;
@@ -215,7 +217,7 @@ CreateSharedBackendStatus(void)
#ifdef ENABLE_GSS
/* Create or attach to the shared GSSAPI status buffer */
- size = mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendGSSStatus), numBackendStatSlots);
BackendGssStatusBuffer = (PgBackendGSSStatus *)
ShmemInitStruct("Backend GSS Status Buffer", size, &found);
@@ -227,7 +229,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_gssstatus pointers. */
ptr = BackendGssStatusBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_gssstatus = ptr;
ptr++;
@@ -251,7 +253,7 @@ pgstat_beinit(void)
/* Initialize MyBEEntry */
if (MyBackendId != InvalidBackendId)
{
- Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+ Assert(MyBackendId >= 1 && MyBackendId <= GetMaxBackends());
MyBEEntry = &BackendStatusArray[MyBackendId - 1];
}
else
@@ -267,7 +269,7 @@ pgstat_beinit(void)
* MaxBackends + AuxBackendType + 1 as the index of the slot for an
* auxiliary process.
*/
- MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
+ MyBEEntry = &BackendStatusArray[GetMaxBackends() + MyAuxProcType];
}
/* Set up a process-exit hook to clean up */
@@ -739,6 +741,7 @@ pgstat_read_current_status(void)
PgBackendGSSStatus *localgssstatus;
#endif
int i;
+ int numBackendStatSlots = NumBackendStatSlots;
if (localBackendStatusTable)
return; /* already done */
@@ -755,32 +758,32 @@ pgstat_read_current_status(void)
*/
localtable = (LocalPgBackendStatus *)
MemoryContextAlloc(backendStatusSnapContext,
- sizeof(LocalPgBackendStatus) * NumBackendStatSlots);
+ sizeof(LocalPgBackendStatus) * numBackendStatSlots);
localappname = (char *)
MemoryContextAlloc(backendStatusSnapContext,
- NAMEDATALEN * NumBackendStatSlots);
+ NAMEDATALEN * numBackendStatSlots);
localclienthostname = (char *)
MemoryContextAlloc(backendStatusSnapContext,
- NAMEDATALEN * NumBackendStatSlots);
+ NAMEDATALEN * numBackendStatSlots);
localactivity = (char *)
MemoryContextAllocHuge(backendStatusSnapContext,
- pgstat_track_activity_query_size * NumBackendStatSlots);
+ pgstat_track_activity_query_size * numBackendStatSlots);
#ifdef USE_SSL
localsslstatus = (PgBackendSSLStatus *)
MemoryContextAlloc(backendStatusSnapContext,
- sizeof(PgBackendSSLStatus) * NumBackendStatSlots);
+ sizeof(PgBackendSSLStatus) * numBackendStatSlots);
#endif
#ifdef ENABLE_GSS
localgssstatus = (PgBackendGSSStatus *)
MemoryContextAlloc(backendStatusSnapContext,
- sizeof(PgBackendGSSStatus) * NumBackendStatSlots);
+ sizeof(PgBackendGSSStatus) * numBackendStatSlots);
#endif
localNumBackends = 0;
beentry = BackendStatusArray;
localentry = localtable;
- for (i = 1; i <= NumBackendStatSlots; i++)
+ for (i = 1; i <= numBackendStatSlots; i++)
{
/*
* Follow the protocol of retrying if st_changecount changes while we
@@ -893,9 +896,10 @@ pgstat_get_backend_current_activity(int pid, bool checkUser)
{
PgBackendStatus *beentry;
int i;
+ int max_backends = GetMaxBackends();
beentry = BackendStatusArray;
- for (i = 1; i <= MaxBackends; i++)
+ for (i = 1; i <= max_backends; i++)
{
/*
* Although we expect the target backend's entry to be stable, that
@@ -971,6 +975,7 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
{
volatile PgBackendStatus *beentry;
int i;
+ int max_backends = GetMaxBackends();
beentry = BackendStatusArray;
@@ -981,7 +986,7 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
if (beentry == NULL || BackendActivityBuffer == NULL)
return NULL;
- for (i = 1; i <= MaxBackends; i++)
+ for (i = 1; i <= max_backends; i++)
{
if (beentry->st_procpid == pid)
{
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 023a004ac8..944cd6df03 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -559,13 +559,14 @@ pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
int *blockers;
int num_blockers;
Datum *blocker_datums;
+ int max_backends = GetMaxBackends();
/* A buffer big enough for any possible blocker list without truncation */
- blockers = (int *) palloc(MaxBackends * sizeof(int));
+ blockers = (int *) palloc(max_backends * sizeof(int));
/* Collect a snapshot of processes waited for by GetSafeSnapshot */
num_blockers =
- GetSafeSnapshotBlockingPids(blocked_pid, blockers, MaxBackends);
+ GetSafeSnapshotBlockingPids(blocked_pid, blockers, max_backends);
/* Convert int array to Datum array */
if (num_blockers > 0)
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 5b9ed2f6f5..ca53912f15 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -25,6 +25,7 @@
#include "access/session.h"
#include "access/sysattr.h"
#include "access/tableam.h"
+#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
@@ -65,6 +66,9 @@
#include "utils/syscache.h"
#include "utils/timeout.h"
+static int MaxBackends = 0;
+static int MaxBackendsInitialized = false;
+
static HeapTuple GetDatabaseTuple(const char *dbname);
static HeapTuple GetDatabaseTupleByOid(Oid dboid);
static void PerformAuthentication(Port *port);
@@ -495,15 +499,49 @@ pg_split_opts(char **argv, int *argcp, const char *optstr)
void
InitializeMaxBackends(void)
{
- Assert(MaxBackends == 0);
-
/* the extra unit accounts for the autovacuum launcher */
- MaxBackends = MaxConnections + autovacuum_max_workers + 1 +
- max_worker_processes + max_wal_senders;
+ SetMaxBackends(MaxConnections + autovacuum_max_workers + 1 +
+ max_worker_processes + max_wal_senders);
+}
+
+/*
+ * Safely retrieve the value of MaxBackends.
+ *
+ * Previously, MaxBackends was externally visible, but it was often used before
+ * it was initialized (e.g., in preloaded libraries' _PG_init() functions).
+ * Unfortunately, we cannot initialize MaxBackends before processing
+ * shared_preload_libraries because the libraries sometimes alter GUCs that are
+ * used to calculate its value. Instead, we provide this function for accessing
+ * MaxBackends, and we ERROR if someone calls it before it is initialized.
+ */
+int
+GetMaxBackends(void)
+{
+ if (unlikely(!MaxBackendsInitialized))
+ elog(ERROR, "MaxBackends not yet initialized");
+
+ return MaxBackends;
+}
+
+/*
+ * Set the value of MaxBackends.
+ *
+ * This should only be used by InitializeMaxBackends() and
+ * restore_backend_variables(). If MaxBackends is already initialized or the
+ * specified value is greater than the maximum, this will ERROR.
+ */
+void
+SetMaxBackends(int max_backends)
+{
+ if (MaxBackendsInitialized)
+ elog(ERROR, "MaxBackends already initialized");
/* internal error because the values were all checked previously */
- if (MaxBackends > MAX_BACKENDS)
+ if (max_backends > MAX_BACKENDS)
elog(ERROR, "too many backends configured");
+
+ MaxBackends = max_backends;
+ MaxBackendsInitialized = true;
}
/*
@@ -609,7 +647,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
SharedInvalBackendInit(false);
- if (MyBackendId > MaxBackends || MyBackendId <= 0)
+ if (MyBackendId > GetMaxBackends() || MyBackendId <= 0)
elog(FATAL, "bad backend ID: %d", MyBackendId);
/* Now that we have a BackendId, we can participate in ProcSignal */
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 02276d3edd..0abc3ad540 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -172,7 +172,6 @@ extern PGDLLIMPORT char *DataDir;
extern PGDLLIMPORT int data_directory_mode;
extern PGDLLIMPORT int NBuffers;
-extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
@@ -457,6 +456,8 @@ extern AuxProcType MyAuxProcType;
/* in utils/init/postinit.c */
extern void pg_split_opts(char **argv, int *argcp, const char *optstr);
extern void InitializeMaxBackends(void);
+extern int GetMaxBackends(void);
+extern void SetMaxBackends(int max_backends);
extern void InitPostgres(const char *in_dbname, Oid dboid, const char *username,
Oid useroid, char *out_dbname, bool override_allow_connections);
extern void BaseInit(void);
--
2.25.1
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-01 22:36 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-02 13:15 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 05:54 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
@ 2022-02-04 13:46 ` Robert Haas <[email protected]>
2022-02-04 20:13 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Robert Haas @ 2022-02-04 13:46 UTC (permalink / raw)
To: Nathan Bossart <[email protected]>; +Cc: Michael Paquier <[email protected]>; Bossart, Nathan <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Fri, Feb 4, 2022 at 12:55 AM Nathan Bossart <[email protected]> wrote:
> Here is a new patch with fewer calls to GetMaxBackends().
For multixact.c, I think you should invent GetMaxOldestSlot() to avoid
confusion. Maybe it could be a static inline rather than a macro.
Likewise, I think PROCARRAY_MAXPROCS, NumProcSignalSlots, and
NumBackendStatSlots should be replaced with things that look more like
function calls.
Apart from that, I think this looks pretty good.
--
Robert Haas
EDB: http://www.enterprisedb.com
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-01 22:36 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-02 13:15 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 05:54 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 13:46 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
@ 2022-02-04 20:13 ` Nathan Bossart <[email protected]>
2022-02-04 20:27 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Nathan Bossart @ 2022-02-04 20:13 UTC (permalink / raw)
To: Robert Haas <[email protected]>; +Cc: Michael Paquier <[email protected]>; Bossart, Nathan <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Fri, Feb 04, 2022 at 08:46:39AM -0500, Robert Haas wrote:
> For multixact.c, I think you should invent GetMaxOldestSlot() to avoid
> confusion. Maybe it could be a static inline rather than a macro.
>
> Likewise, I think PROCARRAY_MAXPROCS, NumProcSignalSlots, and
> NumBackendStatSlots should be replaced with things that look more like
> function calls.
Sorry, I did notice that it looked odd, and I should've done this in v8 and
saved a round trip. Here's a new revision with those macros converted to
inline functions. I've also dialed things back a little in some places
where a new variable felt excessive.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
[text/x-diff] v9-0001-Disallow-external-access-to-MaxBackends.patch (45.5K, ../../20220204201349.GA1534137@nathanxps13/2-v9-0001-Disallow-external-access-to-MaxBackends.patch)
download | inline diff:
From 38c21e3cf36c591c524a65668594990a0472139c Mon Sep 17 00:00:00 2001
From: Nathan Bossart <[email protected]>
Date: Mon, 16 Aug 2021 02:59:32 +0000
Subject: [PATCH v9 1/1] Disallow external access to MaxBackends.
Presently, MaxBackends is externally visible, but it may still be
uninitialized in places where it would be convenient to use (e.g.,
_PG_init()). This change makes MaxBackends static to postinit.c to
disallow such direct access. Instead, MaxBackends should now be
accessed via GetMaxBackends().
---
src/backend/access/nbtree/nbtutils.c | 4 +-
src/backend/access/transam/multixact.c | 31 +++++---
src/backend/access/transam/twophase.c | 3 +-
src/backend/commands/async.c | 11 +--
src/backend/libpq/pqcomm.c | 3 +-
src/backend/postmaster/auxprocess.c | 2 +-
src/backend/postmaster/postmaster.c | 4 +-
src/backend/storage/ipc/dsm.c | 2 +-
src/backend/storage/ipc/procarray.c | 25 ++++--
src/backend/storage/ipc/procsignal.c | 37 +++++----
src/backend/storage/ipc/sinvaladt.c | 4 +-
src/backend/storage/lmgr/deadlock.c | 31 ++++----
src/backend/storage/lmgr/lock.c | 22 +++---
src/backend/storage/lmgr/predicate.c | 10 +--
src/backend/storage/lmgr/proc.c | 17 ++--
src/backend/utils/activity/backend_status.c | 88 +++++++++++----------
src/backend/utils/adt/lockfuncs.c | 4 +-
src/backend/utils/init/postinit.c | 50 ++++++++++--
src/include/miscadmin.h | 3 +-
19 files changed, 218 insertions(+), 133 deletions(-)
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 6a651d8397..84164748b3 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -2072,7 +2072,7 @@ BTreeShmemSize(void)
Size size;
size = offsetof(BTVacInfo, vacuums);
- size = add_size(size, mul_size(MaxBackends, sizeof(BTOneVacInfo)));
+ size = add_size(size, mul_size(GetMaxBackends(), sizeof(BTOneVacInfo)));
return size;
}
@@ -2101,7 +2101,7 @@ BTreeShmemInit(void)
btvacinfo->cycle_ctr = (BTCycleId) time(NULL);
btvacinfo->num_vacuums = 0;
- btvacinfo->max_vacuums = MaxBackends;
+ btvacinfo->max_vacuums = GetMaxBackends();
}
else
Assert(found);
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 806f2e43ba..f00c272521 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -282,12 +282,11 @@ typedef struct MultiXactStateData
} MultiXactStateData;
/*
- * Last element of OldestMemberMXactId and OldestVisibleMXactId arrays.
- * Valid elements are (1..MaxOldestSlot); element 0 is never used.
+ * Pointers to the state data in shared memory
+ *
+ * The index of the last element of the OldestMemberMXactId and
+ * OldestVisibleMXacId arrays can be obtained with GetMaxOldestSlot().
*/
-#define MaxOldestSlot (MaxBackends + max_prepared_xacts)
-
-/* Pointers to the state data in shared memory */
static MultiXactStateData *MultiXactState;
static MultiXactId *OldestMemberMXactId;
static MultiXactId *OldestVisibleMXactId;
@@ -342,6 +341,7 @@ static void MultiXactIdSetOldestVisible(void);
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
int nmembers, MultiXactMember *members);
static MultiXactId GetNewMultiXactId(int nmembers, MultiXactOffset *offset);
+static inline int GetMaxOldestSlot(void);
/* MultiXact cache management */
static int mxactMemberComparator(const void *arg1, const void *arg2);
@@ -662,6 +662,17 @@ MultiXactIdSetOldestMember(void)
}
}
+/*
+ * Retrieve the index of the last element of the OldestMemberMXactId and
+ * OldestVisibleMXactId arrays. Valid elements are (1..MaxOldestSlot); element
+ * 0 is never used.
+ */
+static inline int
+GetMaxOldestSlot(void)
+{
+ return GetMaxBackends() + max_prepared_xacts;
+}
+
/*
* MultiXactIdSetOldestVisible
* Save the oldest MultiXactId this transaction considers possibly live.
@@ -684,6 +695,7 @@ MultiXactIdSetOldestVisible(void)
if (!MultiXactIdIsValid(OldestVisibleMXactId[MyBackendId]))
{
MultiXactId oldestMXact;
+ int maxOldestSlot = GetMaxOldestSlot();
int i;
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
@@ -697,7 +709,7 @@ MultiXactIdSetOldestVisible(void)
if (oldestMXact < FirstMultiXactId)
oldestMXact = FirstMultiXactId;
- for (i = 1; i <= MaxOldestSlot; i++)
+ for (i = 1; i <= maxOldestSlot; i++)
{
MultiXactId thisoldest = OldestMemberMXactId[i];
@@ -1831,7 +1843,7 @@ MultiXactShmemSize(void)
/* We need 2*MaxOldestSlot + 1 perBackendXactIds[] entries */
#define SHARED_MULTIXACT_STATE_SIZE \
add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
- mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
+ mul_size(sizeof(MultiXactId) * 2, GetMaxOldestSlot()))
size = SHARED_MULTIXACT_STATE_SIZE;
size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
@@ -1882,7 +1894,7 @@ MultiXactShmemInit(void)
* since we only use indexes 1..MaxOldestSlot in each array.
*/
OldestMemberMXactId = MultiXactState->perBackendXactIds;
- OldestVisibleMXactId = OldestMemberMXactId + MaxOldestSlot;
+ OldestVisibleMXactId = OldestMemberMXactId + GetMaxOldestSlot();
}
/*
@@ -2507,6 +2519,7 @@ GetOldestMultiXactId(void)
{
MultiXactId oldestMXact;
MultiXactId nextMXact;
+ int maxOldestSlot = GetMaxOldestSlot();
int i;
/*
@@ -2525,7 +2538,7 @@ GetOldestMultiXactId(void)
nextMXact = FirstMultiXactId;
oldestMXact = nextMXact;
- for (i = 1; i <= MaxOldestSlot; i++)
+ for (i = 1; i <= maxOldestSlot; i++)
{
MultiXactId thisoldest;
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 271a3146db..608c5149e5 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -260,6 +260,7 @@ TwoPhaseShmemInit(void)
{
GlobalTransaction gxacts;
int i;
+ int max_backends = GetMaxBackends();
Assert(!found);
TwoPhaseState->freeGXacts = NULL;
@@ -293,7 +294,7 @@ TwoPhaseShmemInit(void)
* prepared transaction. Currently multixact.c uses that
* technique.
*/
- gxacts[i].dummyBackendId = MaxBackends + 1 + i;
+ gxacts[i].dummyBackendId = max_backends + 1 + i;
}
}
else
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 3e1b92df03..d44001a49f 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -518,7 +518,7 @@ AsyncShmemSize(void)
Size size;
/* This had better match AsyncShmemInit */
- size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
+ size = mul_size(GetMaxBackends() + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
@@ -534,6 +534,7 @@ AsyncShmemInit(void)
{
bool found;
Size size;
+ int max_backends = GetMaxBackends();
/*
* Create or attach to the AsyncQueueControl structure.
@@ -541,7 +542,7 @@ AsyncShmemInit(void)
* The used entries in the backend[] array run from 1 to MaxBackends; the
* zero'th entry is unused but must be allocated.
*/
- size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
+ size = mul_size(max_backends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
asyncQueueControl = (AsyncQueueControl *)
@@ -556,7 +557,7 @@ AsyncShmemInit(void)
QUEUE_FIRST_LISTENER = InvalidBackendId;
asyncQueueControl->lastQueueFillWarn = 0;
/* zero'th entry won't be used, but let's initialize it anyway */
- for (int i = 0; i <= MaxBackends; i++)
+ for (int i = 0; i <= max_backends; i++)
{
QUEUE_BACKEND_PID(i) = InvalidPid;
QUEUE_BACKEND_DBOID(i) = InvalidOid;
@@ -1641,8 +1642,8 @@ SignalBackends(void)
* XXX in principle these pallocs could fail, which would be bad. Maybe
* preallocate the arrays? They're not that large, though.
*/
- pids = (int32 *) palloc(MaxBackends * sizeof(int32));
- ids = (BackendId *) palloc(MaxBackends * sizeof(BackendId));
+ pids = (int32 *) palloc(GetMaxBackends() * sizeof(int32));
+ ids = (BackendId *) palloc(GetMaxBackends() * sizeof(BackendId));
count = 0;
LWLockAcquire(NotifyQueueLock, LW_EXCLUSIVE);
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index f05723dc92..22eb04948e 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -349,6 +349,7 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
struct addrinfo hint;
int listen_index = 0;
int added = 0;
+ int max_backends = GetMaxBackends();
#ifdef HAVE_UNIX_SOCKETS
char unixSocketPath[MAXPGPATH];
@@ -571,7 +572,7 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
* intended to provide a clamp on the request on platforms where an
* overly large request provokes a kernel error (are there any?).
*/
- maxconn = MaxBackends * 2;
+ maxconn = max_backends * 2;
if (maxconn > PG_SOMAXCONN)
maxconn = PG_SOMAXCONN;
diff --git a/src/backend/postmaster/auxprocess.c b/src/backend/postmaster/auxprocess.c
index 39ac4490db..0587e45920 100644
--- a/src/backend/postmaster/auxprocess.c
+++ b/src/backend/postmaster/auxprocess.c
@@ -116,7 +116,7 @@ AuxiliaryProcessMain(AuxProcType auxtype)
* This will need rethinking if we ever want more than one of a particular
* auxiliary process type.
*/
- ProcSignalInit(MaxBackends + MyAuxProcType + 1);
+ ProcSignalInit(GetMaxBackends() + MyAuxProcType + 1);
/*
* Auxiliary processes don't run transactions, but they may need a
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index ac0ec0986a..ce90877154 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -6260,7 +6260,7 @@ save_backend_variables(BackendParameters *param, Port *port,
param->query_id_enabled = query_id_enabled;
param->max_safe_fds = max_safe_fds;
- param->MaxBackends = MaxBackends;
+ param->MaxBackends = GetMaxBackends();
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
@@ -6494,7 +6494,7 @@ restore_backend_variables(BackendParameters *param, Port *port)
query_id_enabled = param->query_id_enabled;
max_safe_fds = param->max_safe_fds;
- MaxBackends = param->MaxBackends;
+ SetMaxBackends(param->MaxBackends);
#ifdef WIN32
PostmasterHandle = param->PostmasterHandle;
diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index ae75141592..e9e9fae3eb 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -166,7 +166,7 @@ dsm_postmaster_startup(PGShmemHeader *shim)
/* Determine size for new control segment. */
maxitems = PG_DYNSHMEM_FIXED_SLOTS
- + PG_DYNSHMEM_SLOTS_PER_BACKEND * MaxBackends;
+ + PG_DYNSHMEM_SLOTS_PER_BACKEND * GetMaxBackends();
elog(DEBUG2, "dynamic shared memory system will support %u segments",
maxitems);
segsize = dsm_control_bytes_needed(maxitems);
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 9d3efb7d80..13d192ec2b 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -97,7 +97,7 @@ typedef struct ProcArrayStruct
/* oldest catalog xmin of any replication slot */
TransactionId replication_slot_catalog_xmin;
- /* indexes into allProcs[], has PROCARRAY_MAXPROCS entries */
+ /* indexes into allProcs[], has ProcArrayMaxProcs entries */
int pgprocnos[FLEXIBLE_ARRAY_MEMBER];
} ProcArrayStruct;
@@ -355,6 +355,17 @@ static void MaintainLatestCompletedXidRecovery(TransactionId latestXid);
static inline FullTransactionId FullXidRelativeTo(FullTransactionId rel,
TransactionId xid);
static void GlobalVisUpdateApply(ComputeXidHorizonsResult *horizons);
+static inline int GetProcArrayMaxProcs(void);
+
+
+/*
+ * Retrieve the number of slots in the ProcArray structure.
+ */
+static inline int
+GetProcArrayMaxProcs(void)
+{
+ return GetMaxBackends() + max_prepared_xacts;
+}
/*
* Report shared-memory space needed by CreateSharedProcArray.
@@ -365,10 +376,8 @@ ProcArrayShmemSize(void)
Size size;
/* Size of the ProcArray structure itself */
-#define PROCARRAY_MAXPROCS (MaxBackends + max_prepared_xacts)
-
size = offsetof(ProcArrayStruct, pgprocnos);
- size = add_size(size, mul_size(sizeof(int), PROCARRAY_MAXPROCS));
+ size = add_size(size, mul_size(sizeof(int), GetProcArrayMaxProcs()));
/*
* During Hot Standby processing we have a data structure called
@@ -384,7 +393,7 @@ ProcArrayShmemSize(void)
* shared memory is being set up.
*/
#define TOTAL_MAX_CACHED_SUBXIDS \
- ((PGPROC_MAX_CACHED_SUBXIDS + 1) * PROCARRAY_MAXPROCS)
+ ((PGPROC_MAX_CACHED_SUBXIDS + 1) * GetProcArrayMaxProcs())
if (EnableHotStandby)
{
@@ -411,7 +420,7 @@ CreateSharedProcArray(void)
ShmemInitStruct("Proc Array",
add_size(offsetof(ProcArrayStruct, pgprocnos),
mul_size(sizeof(int),
- PROCARRAY_MAXPROCS)),
+ GetProcArrayMaxProcs())),
&found);
if (!found)
@@ -420,7 +429,7 @@ CreateSharedProcArray(void)
* We're the first - initialize.
*/
procArray->numProcs = 0;
- procArray->maxProcs = PROCARRAY_MAXPROCS;
+ procArray->maxProcs = GetProcArrayMaxProcs();
procArray->maxKnownAssignedXids = TOTAL_MAX_CACHED_SUBXIDS;
procArray->numKnownAssignedXids = 0;
procArray->tailKnownAssignedXids = 0;
@@ -4623,7 +4632,7 @@ KnownAssignedXidsCompress(bool force)
*/
int nelements = head - tail;
- if (nelements < 4 * PROCARRAY_MAXPROCS ||
+ if (nelements < 4 * GetProcArrayMaxProcs() ||
nelements < 2 * pArray->numKnownAssignedXids)
return;
}
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index f1c8ff8f9e..d158bb7a19 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -80,13 +80,6 @@ typedef struct
ProcSignalSlot psh_slot[FLEXIBLE_ARRAY_MEMBER];
} ProcSignalHeader;
-/*
- * We reserve a slot for each possible BackendId, plus one for each
- * possible auxiliary process type. (This scheme assumes there is not
- * more than one of any auxiliary process type at a time.)
- */
-#define NumProcSignalSlots (MaxBackends + NUM_AUXPROCTYPES)
-
/* Check whether the relevant type bit is set in the flags. */
#define BARRIER_SHOULD_CHECK(flags, type) \
(((flags) & (((uint32) 1) << (uint32) (type))) != 0)
@@ -102,6 +95,20 @@ static bool CheckProcSignal(ProcSignalReason reason);
static void CleanupProcSignalState(int status, Datum arg);
static void ResetProcSignalBarrierBits(uint32 flags);
static bool ProcessBarrierPlaceholder(void);
+static inline int GetNumProcSignalSlots(void);
+
+/*
+ * GetNumProcSignalSlots
+ *
+ * We reserve a slot for each possible BackendId, plus one for each possible
+ * auxiliary process type. (This scheme assume there is not more than one of
+ * any auxiliary process type at a time.)
+ */
+static inline int
+GetNumProcSignalSlots(void)
+{
+ return GetMaxBackends() + NUM_AUXPROCTYPES;
+}
/*
* ProcSignalShmemSize
@@ -112,7 +119,7 @@ ProcSignalShmemSize(void)
{
Size size;
- size = mul_size(NumProcSignalSlots, sizeof(ProcSignalSlot));
+ size = mul_size(GetNumProcSignalSlots(), sizeof(ProcSignalSlot));
size = add_size(size, offsetof(ProcSignalHeader, psh_slot));
return size;
}
@@ -126,6 +133,7 @@ ProcSignalShmemInit(void)
{
Size size = ProcSignalShmemSize();
bool found;
+ int numProcSignalSlots = GetNumProcSignalSlots();
ProcSignal = (ProcSignalHeader *)
ShmemInitStruct("ProcSignal", size, &found);
@@ -137,7 +145,7 @@ ProcSignalShmemInit(void)
pg_atomic_init_u64(&ProcSignal->psh_barrierGeneration, 0);
- for (i = 0; i < NumProcSignalSlots; ++i)
+ for (i = 0; i < numProcSignalSlots; ++i)
{
ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
@@ -163,7 +171,7 @@ ProcSignalInit(int pss_idx)
ProcSignalSlot *slot;
uint64 barrier_generation;
- Assert(pss_idx >= 1 && pss_idx <= NumProcSignalSlots);
+ Assert(pss_idx >= 1 && pss_idx <= GetNumProcSignalSlots());
slot = &ProcSignal->psh_slot[pss_idx - 1];
@@ -292,7 +300,7 @@ SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
*/
int i;
- for (i = NumProcSignalSlots - 1; i >= 0; i--)
+ for (i = GetNumProcSignalSlots() - 1; i >= 0; i--)
{
slot = &ProcSignal->psh_slot[i];
@@ -333,6 +341,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
{
uint32 flagbit = 1 << (uint32) type;
uint64 generation;
+ int numProcSignalSlots = GetNumProcSignalSlots();
/*
* Set all the flags.
@@ -342,7 +351,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
* anything that we do afterwards. (This is also true of the later call to
* pg_atomic_add_fetch_u64.)
*/
- for (int i = 0; i < NumProcSignalSlots; i++)
+ for (int i = 0; i < numProcSignalSlots; i++)
{
volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
@@ -368,7 +377,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
* backends that need to update state - but they won't actually need to
* change any state.
*/
- for (int i = NumProcSignalSlots - 1; i >= 0; i--)
+ for (int i = numProcSignalSlots - 1; i >= 0; i--)
{
volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
pid_t pid = slot->pss_pid;
@@ -393,7 +402,7 @@ WaitForProcSignalBarrier(uint64 generation)
{
Assert(generation <= pg_atomic_read_u64(&ProcSignal->psh_barrierGeneration));
- for (int i = NumProcSignalSlots - 1; i >= 0; i--)
+ for (int i = GetNumProcSignalSlots() - 1; i >= 0; i--)
{
ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
uint64 oldval;
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index cb3ee82046..68e7160b30 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -205,7 +205,7 @@ SInvalShmemSize(void)
Size size;
size = offsetof(SISeg, procState);
- size = add_size(size, mul_size(sizeof(ProcState), MaxBackends));
+ size = add_size(size, mul_size(sizeof(ProcState), GetMaxBackends()));
return size;
}
@@ -231,7 +231,7 @@ CreateSharedInvalidationState(void)
shmInvalBuffer->maxMsgNum = 0;
shmInvalBuffer->nextThreshold = CLEANUP_MIN;
shmInvalBuffer->lastBackend = 0;
- shmInvalBuffer->maxBackends = MaxBackends;
+ shmInvalBuffer->maxBackends = GetMaxBackends();
SpinLockInit(&shmInvalBuffer->msgnumLock);
/* The buffer[] array is initially all unused, so we need not fill it */
diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c
index cd9c0418ec..b5d539ba5d 100644
--- a/src/backend/storage/lmgr/deadlock.c
+++ b/src/backend/storage/lmgr/deadlock.c
@@ -143,6 +143,7 @@ void
InitDeadLockChecking(void)
{
MemoryContext oldcxt;
+ int max_backends = GetMaxBackends();
/* Make sure allocations are permanent */
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
@@ -151,16 +152,16 @@ InitDeadLockChecking(void)
* FindLockCycle needs at most MaxBackends entries in visitedProcs[] and
* deadlockDetails[].
*/
- visitedProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
- deadlockDetails = (DEADLOCK_INFO *) palloc(MaxBackends * sizeof(DEADLOCK_INFO));
+ visitedProcs = (PGPROC **) palloc(max_backends * sizeof(PGPROC *));
+ deadlockDetails = (DEADLOCK_INFO *) palloc(max_backends * sizeof(DEADLOCK_INFO));
/*
* TopoSort needs to consider at most MaxBackends wait-queue entries, and
* it needn't run concurrently with FindLockCycle.
*/
topoProcs = visitedProcs; /* re-use this space */
- beforeConstraints = (int *) palloc(MaxBackends * sizeof(int));
- afterConstraints = (int *) palloc(MaxBackends * sizeof(int));
+ beforeConstraints = (int *) palloc(max_backends * sizeof(int));
+ afterConstraints = (int *) palloc(max_backends * sizeof(int));
/*
* We need to consider rearranging at most MaxBackends/2 wait queues
@@ -169,8 +170,8 @@ InitDeadLockChecking(void)
* MaxBackends total waiters.
*/
waitOrders = (WAIT_ORDER *)
- palloc((MaxBackends / 2) * sizeof(WAIT_ORDER));
- waitOrderProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
+ palloc((max_backends / 2) * sizeof(WAIT_ORDER));
+ waitOrderProcs = (PGPROC **) palloc(max_backends * sizeof(PGPROC *));
/*
* Allow at most MaxBackends distinct constraints in a configuration. (Is
@@ -180,7 +181,7 @@ InitDeadLockChecking(void)
* limits the maximum recursion depth of DeadLockCheckRecurse. Making it
* really big might potentially allow a stack-overflow problem.
*/
- maxCurConstraints = MaxBackends;
+ maxCurConstraints = max_backends;
curConstraints = (EDGE *) palloc(maxCurConstraints * sizeof(EDGE));
/*
@@ -191,7 +192,7 @@ InitDeadLockChecking(void)
* last MaxBackends entries in possibleConstraints[] are reserved as
* output workspace for FindLockCycle.
*/
- maxPossibleConstraints = MaxBackends * 4;
+ maxPossibleConstraints = max_backends * 4;
possibleConstraints =
(EDGE *) palloc(maxPossibleConstraints * sizeof(EDGE));
@@ -327,7 +328,7 @@ DeadLockCheckRecurse(PGPROC *proc)
if (nCurConstraints >= maxCurConstraints)
return true; /* out of room for active constraints? */
oldPossibleConstraints = nPossibleConstraints;
- if (nPossibleConstraints + nEdges + MaxBackends <= maxPossibleConstraints)
+ if (nPossibleConstraints + nEdges + GetMaxBackends() <= maxPossibleConstraints)
{
/* We can save the edge list in possibleConstraints[] */
nPossibleConstraints += nEdges;
@@ -388,7 +389,7 @@ TestConfiguration(PGPROC *startProc)
/*
* Make sure we have room for FindLockCycle's output.
*/
- if (nPossibleConstraints + MaxBackends > maxPossibleConstraints)
+ if (nPossibleConstraints + GetMaxBackends() > maxPossibleConstraints)
return -1;
/*
@@ -486,7 +487,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
* record total length of cycle --- outer levels will now fill
* deadlockDetails[]
*/
- Assert(depth <= MaxBackends);
+ Assert(depth <= GetMaxBackends());
nDeadlockDetails = depth;
return true;
@@ -500,7 +501,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
}
}
/* Mark proc as seen */
- Assert(nVisitedProcs < MaxBackends);
+ Assert(nVisitedProcs < GetMaxBackends());
visitedProcs[nVisitedProcs++] = checkProc;
/*
@@ -698,7 +699,7 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
/*
* Add this edge to the list of soft edges in the cycle
*/
- Assert(*nSoftEdges < MaxBackends);
+ Assert(*nSoftEdges < GetMaxBackends());
softEdges[*nSoftEdges].waiter = checkProcLeader;
softEdges[*nSoftEdges].blocker = leader;
softEdges[*nSoftEdges].lock = lock;
@@ -771,7 +772,7 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
/*
* Add this edge to the list of soft edges in the cycle
*/
- Assert(*nSoftEdges < MaxBackends);
+ Assert(*nSoftEdges < GetMaxBackends());
softEdges[*nSoftEdges].waiter = checkProcLeader;
softEdges[*nSoftEdges].blocker = leader;
softEdges[*nSoftEdges].lock = lock;
@@ -834,7 +835,7 @@ ExpandConstraints(EDGE *constraints,
waitOrders[nWaitOrders].procs = waitOrderProcs + nWaitOrderProcs;
waitOrders[nWaitOrders].nProcs = lock->waitProcs.size;
nWaitOrderProcs += lock->waitProcs.size;
- Assert(nWaitOrderProcs <= MaxBackends);
+ Assert(nWaitOrderProcs <= GetMaxBackends());
/*
* Do the topo sort. TopoSort need not examine constraints after this
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 5f5803f681..1528d788d0 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -55,7 +55,7 @@
int max_locks_per_xact; /* set by guc.c */
#define NLOCKENTS() \
- mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
+ mul_size(max_locks_per_xact, add_size(GetMaxBackends(), max_prepared_xacts))
/*
@@ -2942,12 +2942,12 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
vxids = (VirtualTransactionId *)
MemoryContextAlloc(TopMemoryContext,
sizeof(VirtualTransactionId) *
- (MaxBackends + max_prepared_xacts + 1));
+ (GetMaxBackends() + max_prepared_xacts + 1));
}
else
vxids = (VirtualTransactionId *)
palloc0(sizeof(VirtualTransactionId) *
- (MaxBackends + max_prepared_xacts + 1));
+ (GetMaxBackends() + max_prepared_xacts + 1));
/* Compute hash code and partition lock, and look up conflicting modes. */
hashcode = LockTagHashCode(locktag);
@@ -3104,7 +3104,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
LWLockRelease(partitionLock);
- if (count > MaxBackends + max_prepared_xacts) /* should never happen */
+ if (count > GetMaxBackends() + max_prepared_xacts) /* should never happen */
elog(PANIC, "too many conflicting locks found");
vxids[count].backendId = InvalidBackendId;
@@ -3651,11 +3651,12 @@ GetLockStatusData(void)
int els;
int el;
int i;
+ int max_backends = GetMaxBackends();
data = (LockData *) palloc(sizeof(LockData));
/* Guess how much space we'll need. */
- els = MaxBackends;
+ els = max_backends;
el = 0;
data->locks = (LockInstanceData *) palloc(sizeof(LockInstanceData) * els);
@@ -3689,7 +3690,7 @@ GetLockStatusData(void)
if (el >= els)
{
- els += MaxBackends;
+ els += max_backends;
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * els);
}
@@ -3721,7 +3722,7 @@ GetLockStatusData(void)
if (el >= els)
{
- els += MaxBackends;
+ els += max_backends;
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * els);
}
@@ -3850,7 +3851,7 @@ GetBlockerStatusData(int blocked_pid)
* for the procs[] array; the other two could need enlargement, though.)
*/
data->nprocs = data->nlocks = data->npids = 0;
- data->maxprocs = data->maxlocks = data->maxpids = MaxBackends;
+ data->maxprocs = data->maxlocks = data->maxpids = GetMaxBackends();
data->procs = (BlockedProcData *) palloc(sizeof(BlockedProcData) * data->maxprocs);
data->locks = (LockInstanceData *) palloc(sizeof(LockInstanceData) * data->maxlocks);
data->waiter_pids = (int *) palloc(sizeof(int) * data->maxpids);
@@ -3925,6 +3926,7 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
PGPROC *proc;
int queue_size;
int i;
+ int max_backends = GetMaxBackends();
/* Nothing to do if this proc is not blocked */
if (theLock == NULL)
@@ -3953,7 +3955,7 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
if (data->nlocks >= data->maxlocks)
{
- data->maxlocks += MaxBackends;
+ data->maxlocks += max_backends;
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * data->maxlocks);
}
@@ -3982,7 +3984,7 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
if (queue_size > data->maxpids - data->npids)
{
- data->maxpids = Max(data->maxpids + MaxBackends,
+ data->maxpids = Max(data->maxpids + max_backends,
data->npids + queue_size);
data->waiter_pids = (int *) repalloc(data->waiter_pids,
sizeof(int) * data->maxpids);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 25e7e4e37b..e337aad5b2 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -257,7 +257,7 @@
(&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
#define NPREDICATELOCKTARGETENTS() \
- mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
+ mul_size(max_predicate_locks_per_xact, add_size(GetMaxBackends(), max_prepared_xacts))
#define SxactIsOnFinishedList(sxact) (!SHMQueueIsDetached(&((sxact)->finishedLink)))
@@ -1222,7 +1222,7 @@ InitPredicateLocks(void)
* Compute size for serializable transaction hashtable. Note these
* calculations must agree with PredicateLockShmemSize!
*/
- max_table_size = (MaxBackends + max_prepared_xacts);
+ max_table_size = (GetMaxBackends() + max_prepared_xacts);
/*
* Allocate a list to hold information on transactions participating in
@@ -1375,7 +1375,7 @@ PredicateLockShmemSize(void)
size = add_size(size, size / 10);
/* transaction list */
- max_table_size = MaxBackends + max_prepared_xacts;
+ max_table_size = GetMaxBackends() + max_prepared_xacts;
max_table_size *= 10;
size = add_size(size, PredXactListDataSize);
size = add_size(size, mul_size((Size) max_table_size,
@@ -1907,7 +1907,7 @@ GetSerializableTransactionSnapshotInt(Snapshot snapshot,
{
++(PredXact->WritableSxactCount);
Assert(PredXact->WritableSxactCount <=
- (MaxBackends + max_prepared_xacts));
+ (GetMaxBackends() + max_prepared_xacts));
}
MySerializableXact = sxact;
@@ -5111,7 +5111,7 @@ predicatelock_twophase_recover(TransactionId xid, uint16 info,
{
++(PredXact->WritableSxactCount);
Assert(PredXact->WritableSxactCount <=
- (MaxBackends + max_prepared_xacts));
+ (GetMaxBackends() + max_prepared_xacts));
}
/*
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index e306b04738..37f032e7b9 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -103,7 +103,7 @@ ProcGlobalShmemSize(void)
{
Size size = 0;
Size TotalProcs =
- add_size(MaxBackends, add_size(NUM_AUXILIARY_PROCS, max_prepared_xacts));
+ add_size(GetMaxBackends(), add_size(NUM_AUXILIARY_PROCS, max_prepared_xacts));
/* ProcGlobal */
size = add_size(size, sizeof(PROC_HDR));
@@ -127,7 +127,7 @@ ProcGlobalSemas(void)
* We need a sema per backend (including autovacuum), plus one for each
* auxiliary process.
*/
- return MaxBackends + NUM_AUXILIARY_PROCS;
+ return GetMaxBackends() + NUM_AUXILIARY_PROCS;
}
/*
@@ -162,7 +162,8 @@ InitProcGlobal(void)
int i,
j;
bool found;
- uint32 TotalProcs = MaxBackends + NUM_AUXILIARY_PROCS + max_prepared_xacts;
+ int max_backends = GetMaxBackends();
+ uint32 TotalProcs = max_backends + NUM_AUXILIARY_PROCS + max_prepared_xacts;
/* Create the ProcGlobal shared structure */
ProcGlobal = (PROC_HDR *)
@@ -195,7 +196,7 @@ InitProcGlobal(void)
MemSet(procs, 0, TotalProcs * sizeof(PGPROC));
ProcGlobal->allProcs = procs;
/* XXX allProcCount isn't really all of them; it excludes prepared xacts */
- ProcGlobal->allProcCount = MaxBackends + NUM_AUXILIARY_PROCS;
+ ProcGlobal->allProcCount = max_backends + NUM_AUXILIARY_PROCS;
/*
* Allocate arrays mirroring PGPROC fields in a dense manner. See
@@ -221,7 +222,7 @@ InitProcGlobal(void)
* dummy PGPROCs don't need these though - they're never associated
* with a real process
*/
- if (i < MaxBackends + NUM_AUXILIARY_PROCS)
+ if (i < max_backends + NUM_AUXILIARY_PROCS)
{
procs[i].sem = PGSemaphoreCreate();
InitSharedLatch(&(procs[i].procLatch));
@@ -258,7 +259,7 @@ InitProcGlobal(void)
ProcGlobal->bgworkerFreeProcs = &procs[i];
procs[i].procgloballist = &ProcGlobal->bgworkerFreeProcs;
}
- else if (i < MaxBackends)
+ else if (i < max_backends)
{
/* PGPROC for walsender, add to walsenderFreeProcs list */
procs[i].links.next = (SHM_QUEUE *) ProcGlobal->walsenderFreeProcs;
@@ -286,8 +287,8 @@ InitProcGlobal(void)
* Save pointers to the blocks of PGPROC structures reserved for auxiliary
* processes and prepared transactions.
*/
- AuxiliaryProcs = &procs[MaxBackends];
- PreparedXactProcs = &procs[MaxBackends + NUM_AUXILIARY_PROCS];
+ AuxiliaryProcs = &procs[max_backends];
+ PreparedXactProcs = &procs[max_backends + NUM_AUXILIARY_PROCS];
/* Create ProcStructLock spinlock, too */
ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index c7ed1e6d7a..079321599d 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -26,18 +26,6 @@
#include "utils/memutils.h"
-/* ----------
- * Total number of backends including auxiliary
- *
- * We reserve a slot for each possible BackendId, plus one for each
- * possible auxiliary process type. (This scheme assumes there is not
- * more than one of any auxiliary process type at a time.) MaxBackends
- * includes autovacuum workers and background workers as well.
- * ----------
- */
-#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
-
-
/* ----------
* GUC parameters
* ----------
@@ -75,8 +63,23 @@ static MemoryContext backendStatusSnapContext;
static void pgstat_beshutdown_hook(int code, Datum arg);
static void pgstat_read_current_status(void);
static void pgstat_setup_backend_status_context(void);
+static inline int GetNumBackendStatSlots(void);
+/*
+ * Retrieve the total number of backends including auxiliary
+ *
+ * We reserve a slot for each possible BackendId, plus one for each possible
+ * auxiliary process type. (This scheme assumes there is not more than one of
+ * any auxiliary process type at a time.) MaxBackends includes autovacuum
+ * workers and background workers as well.
+ */
+static inline int
+GetNumBackendStatSlots(void)
+{
+ return GetMaxBackends() + NUM_AUXPROCTYPES;
+}
+
/*
* Report shared-memory space needed by CreateSharedBackendStatus.
*/
@@ -84,27 +87,28 @@ Size
BackendStatusShmemSize(void)
{
Size size;
+ int numBackendStatSlots = GetNumBackendStatSlots();
/* BackendStatusArray: */
- size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendStatus), numBackendStatSlots);
/* BackendAppnameBuffer: */
size = add_size(size,
- mul_size(NAMEDATALEN, NumBackendStatSlots));
+ mul_size(NAMEDATALEN, numBackendStatSlots));
/* BackendClientHostnameBuffer: */
size = add_size(size,
- mul_size(NAMEDATALEN, NumBackendStatSlots));
+ mul_size(NAMEDATALEN, numBackendStatSlots));
/* BackendActivityBuffer: */
size = add_size(size,
- mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
+ mul_size(pgstat_track_activity_query_size, numBackendStatSlots));
#ifdef USE_SSL
/* BackendSslStatusBuffer: */
size = add_size(size,
- mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
+ mul_size(sizeof(PgBackendSSLStatus), numBackendStatSlots));
#endif
#ifdef ENABLE_GSS
/* BackendGssStatusBuffer: */
size = add_size(size,
- mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots));
+ mul_size(sizeof(PgBackendGSSStatus), numBackendStatSlots));
#endif
return size;
}
@@ -120,9 +124,10 @@ CreateSharedBackendStatus(void)
bool found;
int i;
char *buffer;
+ int numBackendStatSlots = GetNumBackendStatSlots();
/* Create or attach to the shared array */
- size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendStatus), numBackendStatSlots);
BackendStatusArray = (PgBackendStatus *)
ShmemInitStruct("Backend Status Array", size, &found);
@@ -135,7 +140,7 @@ CreateSharedBackendStatus(void)
}
/* Create or attach to the shared appname buffer */
- size = mul_size(NAMEDATALEN, NumBackendStatSlots);
+ size = mul_size(NAMEDATALEN, numBackendStatSlots);
BackendAppnameBuffer = (char *)
ShmemInitStruct("Backend Application Name Buffer", size, &found);
@@ -145,7 +150,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_appname pointers. */
buffer = BackendAppnameBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_appname = buffer;
buffer += NAMEDATALEN;
@@ -153,7 +158,7 @@ CreateSharedBackendStatus(void)
}
/* Create or attach to the shared client hostname buffer */
- size = mul_size(NAMEDATALEN, NumBackendStatSlots);
+ size = mul_size(NAMEDATALEN, numBackendStatSlots);
BackendClientHostnameBuffer = (char *)
ShmemInitStruct("Backend Client Host Name Buffer", size, &found);
@@ -163,7 +168,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_clienthostname pointers. */
buffer = BackendClientHostnameBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_clienthostname = buffer;
buffer += NAMEDATALEN;
@@ -172,7 +177,7 @@ CreateSharedBackendStatus(void)
/* Create or attach to the shared activity buffer */
BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
- NumBackendStatSlots);
+ numBackendStatSlots);
BackendActivityBuffer = (char *)
ShmemInitStruct("Backend Activity Buffer",
BackendActivityBufferSize,
@@ -184,7 +189,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_activity pointers. */
buffer = BackendActivityBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_activity_raw = buffer;
buffer += pgstat_track_activity_query_size;
@@ -193,7 +198,7 @@ CreateSharedBackendStatus(void)
#ifdef USE_SSL
/* Create or attach to the shared SSL status buffer */
- size = mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendSSLStatus), numBackendStatSlots);
BackendSslStatusBuffer = (PgBackendSSLStatus *)
ShmemInitStruct("Backend SSL Status Buffer", size, &found);
@@ -205,7 +210,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_sslstatus pointers. */
ptr = BackendSslStatusBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_sslstatus = ptr;
ptr++;
@@ -215,7 +220,7 @@ CreateSharedBackendStatus(void)
#ifdef ENABLE_GSS
/* Create or attach to the shared GSSAPI status buffer */
- size = mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendGSSStatus), numBackendStatSlots);
BackendGssStatusBuffer = (PgBackendGSSStatus *)
ShmemInitStruct("Backend GSS Status Buffer", size, &found);
@@ -227,7 +232,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_gssstatus pointers. */
ptr = BackendGssStatusBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_gssstatus = ptr;
ptr++;
@@ -251,7 +256,7 @@ pgstat_beinit(void)
/* Initialize MyBEEntry */
if (MyBackendId != InvalidBackendId)
{
- Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+ Assert(MyBackendId >= 1 && MyBackendId <= GetMaxBackends());
MyBEEntry = &BackendStatusArray[MyBackendId - 1];
}
else
@@ -267,7 +272,7 @@ pgstat_beinit(void)
* MaxBackends + AuxBackendType + 1 as the index of the slot for an
* auxiliary process.
*/
- MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
+ MyBEEntry = &BackendStatusArray[GetMaxBackends() + MyAuxProcType];
}
/* Set up a process-exit hook to clean up */
@@ -739,6 +744,7 @@ pgstat_read_current_status(void)
PgBackendGSSStatus *localgssstatus;
#endif
int i;
+ int numBackendStatSlots = GetNumBackendStatSlots();
if (localBackendStatusTable)
return; /* already done */
@@ -755,32 +761,32 @@ pgstat_read_current_status(void)
*/
localtable = (LocalPgBackendStatus *)
MemoryContextAlloc(backendStatusSnapContext,
- sizeof(LocalPgBackendStatus) * NumBackendStatSlots);
+ sizeof(LocalPgBackendStatus) * numBackendStatSlots);
localappname = (char *)
MemoryContextAlloc(backendStatusSnapContext,
- NAMEDATALEN * NumBackendStatSlots);
+ NAMEDATALEN * numBackendStatSlots);
localclienthostname = (char *)
MemoryContextAlloc(backendStatusSnapContext,
- NAMEDATALEN * NumBackendStatSlots);
+ NAMEDATALEN * numBackendStatSlots);
localactivity = (char *)
MemoryContextAllocHuge(backendStatusSnapContext,
- pgstat_track_activity_query_size * NumBackendStatSlots);
+ pgstat_track_activity_query_size * numBackendStatSlots);
#ifdef USE_SSL
localsslstatus = (PgBackendSSLStatus *)
MemoryContextAlloc(backendStatusSnapContext,
- sizeof(PgBackendSSLStatus) * NumBackendStatSlots);
+ sizeof(PgBackendSSLStatus) * numBackendStatSlots);
#endif
#ifdef ENABLE_GSS
localgssstatus = (PgBackendGSSStatus *)
MemoryContextAlloc(backendStatusSnapContext,
- sizeof(PgBackendGSSStatus) * NumBackendStatSlots);
+ sizeof(PgBackendGSSStatus) * numBackendStatSlots);
#endif
localNumBackends = 0;
beentry = BackendStatusArray;
localentry = localtable;
- for (i = 1; i <= NumBackendStatSlots; i++)
+ for (i = 1; i <= numBackendStatSlots; i++)
{
/*
* Follow the protocol of retrying if st_changecount changes while we
@@ -893,9 +899,10 @@ pgstat_get_backend_current_activity(int pid, bool checkUser)
{
PgBackendStatus *beentry;
int i;
+ int max_backends = GetMaxBackends();
beentry = BackendStatusArray;
- for (i = 1; i <= MaxBackends; i++)
+ for (i = 1; i <= max_backends; i++)
{
/*
* Although we expect the target backend's entry to be stable, that
@@ -971,6 +978,7 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
{
volatile PgBackendStatus *beentry;
int i;
+ int max_backends = GetMaxBackends();
beentry = BackendStatusArray;
@@ -981,7 +989,7 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
if (beentry == NULL || BackendActivityBuffer == NULL)
return NULL;
- for (i = 1; i <= MaxBackends; i++)
+ for (i = 1; i <= max_backends; i++)
{
if (beentry->st_procpid == pid)
{
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 023a004ac8..4e517b28e1 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -561,11 +561,11 @@ pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
Datum *blocker_datums;
/* A buffer big enough for any possible blocker list without truncation */
- blockers = (int *) palloc(MaxBackends * sizeof(int));
+ blockers = (int *) palloc(GetMaxBackends() * sizeof(int));
/* Collect a snapshot of processes waited for by GetSafeSnapshot */
num_blockers =
- GetSafeSnapshotBlockingPids(blocked_pid, blockers, MaxBackends);
+ GetSafeSnapshotBlockingPids(blocked_pid, blockers, GetMaxBackends());
/* Convert int array to Datum array */
if (num_blockers > 0)
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 5b9ed2f6f5..ca53912f15 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -25,6 +25,7 @@
#include "access/session.h"
#include "access/sysattr.h"
#include "access/tableam.h"
+#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
@@ -65,6 +66,9 @@
#include "utils/syscache.h"
#include "utils/timeout.h"
+static int MaxBackends = 0;
+static int MaxBackendsInitialized = false;
+
static HeapTuple GetDatabaseTuple(const char *dbname);
static HeapTuple GetDatabaseTupleByOid(Oid dboid);
static void PerformAuthentication(Port *port);
@@ -495,15 +499,49 @@ pg_split_opts(char **argv, int *argcp, const char *optstr)
void
InitializeMaxBackends(void)
{
- Assert(MaxBackends == 0);
-
/* the extra unit accounts for the autovacuum launcher */
- MaxBackends = MaxConnections + autovacuum_max_workers + 1 +
- max_worker_processes + max_wal_senders;
+ SetMaxBackends(MaxConnections + autovacuum_max_workers + 1 +
+ max_worker_processes + max_wal_senders);
+}
+
+/*
+ * Safely retrieve the value of MaxBackends.
+ *
+ * Previously, MaxBackends was externally visible, but it was often used before
+ * it was initialized (e.g., in preloaded libraries' _PG_init() functions).
+ * Unfortunately, we cannot initialize MaxBackends before processing
+ * shared_preload_libraries because the libraries sometimes alter GUCs that are
+ * used to calculate its value. Instead, we provide this function for accessing
+ * MaxBackends, and we ERROR if someone calls it before it is initialized.
+ */
+int
+GetMaxBackends(void)
+{
+ if (unlikely(!MaxBackendsInitialized))
+ elog(ERROR, "MaxBackends not yet initialized");
+
+ return MaxBackends;
+}
+
+/*
+ * Set the value of MaxBackends.
+ *
+ * This should only be used by InitializeMaxBackends() and
+ * restore_backend_variables(). If MaxBackends is already initialized or the
+ * specified value is greater than the maximum, this will ERROR.
+ */
+void
+SetMaxBackends(int max_backends)
+{
+ if (MaxBackendsInitialized)
+ elog(ERROR, "MaxBackends already initialized");
/* internal error because the values were all checked previously */
- if (MaxBackends > MAX_BACKENDS)
+ if (max_backends > MAX_BACKENDS)
elog(ERROR, "too many backends configured");
+
+ MaxBackends = max_backends;
+ MaxBackendsInitialized = true;
}
/*
@@ -609,7 +647,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
SharedInvalBackendInit(false);
- if (MyBackendId > MaxBackends || MyBackendId <= 0)
+ if (MyBackendId > GetMaxBackends() || MyBackendId <= 0)
elog(FATAL, "bad backend ID: %d", MyBackendId);
/* Now that we have a BackendId, we can participate in ProcSignal */
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 02276d3edd..0abc3ad540 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -172,7 +172,6 @@ extern PGDLLIMPORT char *DataDir;
extern PGDLLIMPORT int data_directory_mode;
extern PGDLLIMPORT int NBuffers;
-extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
@@ -457,6 +456,8 @@ extern AuxProcType MyAuxProcType;
/* in utils/init/postinit.c */
extern void pg_split_opts(char **argv, int *argcp, const char *optstr);
extern void InitializeMaxBackends(void);
+extern int GetMaxBackends(void);
+extern void SetMaxBackends(int max_backends);
extern void InitPostgres(const char *in_dbname, Oid dboid, const char *username,
Oid useroid, char *out_dbname, bool override_allow_connections);
extern void BaseInit(void);
--
2.25.1
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-01 22:36 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-02 13:15 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 05:54 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 13:46 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 20:13 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
@ 2022-02-04 20:27 ` Robert Haas <[email protected]>
2022-02-08 21:12 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
0 siblings, 1 reply; 16+ messages in thread
From: Robert Haas @ 2022-02-04 20:27 UTC (permalink / raw)
To: Nathan Bossart <[email protected]>; +Cc: Michael Paquier <[email protected]>; Bossart, Nathan <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Fri, Feb 4, 2022 at 3:13 PM Nathan Bossart <[email protected]> wrote:
> On Fri, Feb 04, 2022 at 08:46:39AM -0500, Robert Haas wrote:
> > For multixact.c, I think you should invent GetMaxOldestSlot() to avoid
> > confusion. Maybe it could be a static inline rather than a macro.
> >
> > Likewise, I think PROCARRAY_MAXPROCS, NumProcSignalSlots, and
> > NumBackendStatSlots should be replaced with things that look more like
> > function calls.
>
> Sorry, I did notice that it looked odd, and I should've done this in v8 and
> saved a round trip. Here's a new revision with those macros converted to
> inline functions. I've also dialed things back a little in some places
> where a new variable felt excessive.
Great. I'll take a look at this next week, but not right now, mostly
because it's Friday afternoon and if I commit it and anything breaks I
don't want to end up having to fix it on the weekend if I can avoid
it.
--
Robert Haas
EDB: http://www.enterprisedb.com
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-01 22:36 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-02 13:15 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 05:54 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 13:46 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 20:13 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 20:27 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
@ 2022-02-08 21:12 ` Robert Haas <[email protected]>
2022-02-09 02:38 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-02-09 17:45 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
0 siblings, 2 replies; 16+ messages in thread
From: Robert Haas @ 2022-02-08 21:12 UTC (permalink / raw)
To: Nathan Bossart <[email protected]>; +Cc: Michael Paquier <[email protected]>; Bossart, Nathan <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Fri, Feb 4, 2022 at 3:27 PM Robert Haas <[email protected]> wrote:
> Great. I'll take a look at this next week, but not right now, mostly
> because it's Friday afternoon and if I commit it and anything breaks I
> don't want to end up having to fix it on the weekend if I can avoid
> it.
After some investigation I've determined that it's no longer Friday
afternoon. I also spent time investigating whether the patch had
problems that would make me uncomfortable with the idea of committing
it, and I did not find any. So, I committed it.
--
Robert Haas
EDB: http://www.enterprisedb.com
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-01 22:36 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-02 13:15 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 05:54 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 13:46 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 20:13 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 20:27 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-08 21:12 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
@ 2022-02-09 02:38 ` Michael Paquier <[email protected]>
2022-02-09 03:57 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
1 sibling, 1 reply; 16+ messages in thread
From: Michael Paquier @ 2022-02-09 02:38 UTC (permalink / raw)
To: Robert Haas <[email protected]>; +Cc: Nathan Bossart <[email protected]>; Bossart, Nathan <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Tue, Feb 08, 2022 at 04:12:26PM -0500, Robert Haas wrote:
> After some investigation I've determined that it's no longer Friday
> afternoon. I also spent time investigating whether the patch had
> problems that would make me uncomfortable with the idea of committing
> it, and I did not find any. So, I committed it.
@@ -1641,8 +1642,8 @@ SignalBackends(void)
* XXX in principle these pallocs could fail, which would be bad. Maybe
* preallocate the arrays? They're not that large, though.
*/
- pids = (int32 *) palloc(MaxBackends * sizeof(int32));
- ids = (BackendId *) palloc(MaxBackends * sizeof(BackendId));
+ pids = (int32 *) palloc(GetMaxBackends() * sizeof(int32));
+ ids = (BackendId *) palloc(GetMaxBackends() * sizeof(BackendId));
You could have optimized this one, while on it, as well as the ones in
pgstat_beinit() and pg_safe_snapshot_blocking_pids(). It is not hot,
but you did that for all the other callers of GetMaxBackends(). Just
saying..
--
Michael
Attachments:
[application/pgp-signature] signature.asc (833B, ../../[email protected]/2-signature.asc)
download
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-01 22:36 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-02 13:15 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 05:54 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 13:46 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 20:13 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 20:27 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-08 21:12 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-09 02:38 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
@ 2022-02-09 03:57 ` Robert Haas <[email protected]>
0 siblings, 0 replies; 16+ messages in thread
From: Robert Haas @ 2022-02-09 03:57 UTC (permalink / raw)
To: Michael Paquier <[email protected]>; +Cc: Nathan Bossart <[email protected]>; Bossart, Nathan <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Tue, Feb 8, 2022 at 9:38 PM Michael Paquier <[email protected]> wrote:
> On Tue, Feb 08, 2022 at 04:12:26PM -0500, Robert Haas wrote:
> > After some investigation I've determined that it's no longer Friday
> > afternoon. I also spent time investigating whether the patch had
> > problems that would make me uncomfortable with the idea of committing
> > it, and I did not find any. So, I committed it.
>
> @@ -1641,8 +1642,8 @@ SignalBackends(void)
> * XXX in principle these pallocs could fail, which would be bad. Maybe
> * preallocate the arrays? They're not that large, though.
> */
> - pids = (int32 *) palloc(MaxBackends * sizeof(int32));
> - ids = (BackendId *) palloc(MaxBackends * sizeof(BackendId));
> + pids = (int32 *) palloc(GetMaxBackends() * sizeof(int32));
> + ids = (BackendId *) palloc(GetMaxBackends() * sizeof(BackendId));
>
> You could have optimized this one, while on it, as well as the ones in
> pgstat_beinit() and pg_safe_snapshot_blocking_pids(). It is not hot,
> but you did that for all the other callers of GetMaxBackends(). Just
> saying..
Well I didn't do anything myself except review and commit Nathan's
patch, so I suppose you mean he could have done that, but fair enough.
I don't mind if you want to change it around.
--
Robert Haas
EDB: http://www.enterprisedb.com
^ permalink raw reply [nested|flat] 16+ messages in thread
* Re: make MaxBackends available in _PG_init
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-01 22:36 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-02 13:15 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 05:54 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 13:46 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 20:13 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 20:27 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-08 21:12 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
@ 2022-02-09 17:45 ` Nathan Bossart <[email protected]>
1 sibling, 0 replies; 16+ messages in thread
From: Nathan Bossart @ 2022-02-09 17:45 UTC (permalink / raw)
To: Robert Haas <[email protected]>; +Cc: Michael Paquier <[email protected]>; Bossart, Nathan <[email protected]>; Fujii Masao <[email protected]>; [email protected] <[email protected]>; Andres Freund <[email protected]>; Bharath Rupireddy <[email protected]>; Greg Sabino Mullane <[email protected]>; Tom Lane <[email protected]>; [email protected] <[email protected]>
On Tue, Feb 08, 2022 at 04:12:26PM -0500, Robert Haas wrote:
> After some investigation I've determined that it's no longer Friday
> afternoon.
This matches my analysis.
> I also spent time investigating whether the patch had
> problems that would make me uncomfortable with the idea of committing
> it, and I did not find any. So, I committed it.
Thanks!
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
^ permalink raw reply [nested|flat] 16+ messages in thread
end of thread, other threads:[~2022-02-09 17:45 UTC | newest]
Thread overview: 16+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2020-03-10 03:40 [PATCH v35 3/7] Add pg_ls_dir_metadata to list a dir with file metadata.. Justin Pryzby <[email protected]>
2022-01-27 00:56 Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-27 18:18 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-01-28 04:22 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-29 02:19 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-01-31 14:32 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-01 22:36 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-02 13:15 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 05:54 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 13:46 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-04 20:13 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
2022-02-04 20:27 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-08 21:12 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-09 02:38 ` Re: make MaxBackends available in _PG_init Michael Paquier <[email protected]>
2022-02-09 03:57 ` Re: make MaxBackends available in _PG_init Robert Haas <[email protected]>
2022-02-09 17:45 ` Re: make MaxBackends available in _PG_init Nathan Bossart <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox