Support "postgres -C" with runtime-computed GUCs

Until now, the -C option of postgres was handled before a small subset
of GUCs computed at runtime are initialized, leading to incorrect
results as GUC machinery would fall back to default values for such
parameters.

For example, data_checksums could report "off" for a cluster as the
control file is not loaded yet.  Or wal_segment_size would show a
segment size at 16MB even if initdb --wal-segsize used something else.
Worse, the command would fail to properly report the recently-introduced
shared_memory, that requires to load shared_preload_libraries as these
could ask for a chunk of shared memory.

Support for runtime GUCs comes with a limitation, as the operation is
now allowed on a running server.  One notable reason for this is that
_PG_init() functions of loadable libraries are called before all
runtime-computed GUCs are initialized, and this is not guaranteed to be
safe to do on running servers.  For the case of shared_memory_size,
where we want to know how much memory would be used without allocating
it, this limitation is fine.  Another case where this will help is for
huge pages, with the introduction of a different GUC to evaluate the
amount of huge pages required for a server before starting it, without
having to allocate large chunks of memory.

This feature is controlled with a new GUC flag, and four parameters are
classified as runtime-computed as of this change:
- data_checksums
- shared_memory_size
- data_directory_mode
- wal_segment_size

Some TAP tests are added to provide some coverage here, using
data_checksums in the tests of pg_checksums.

Per discussion with Andres Freund, Justin Pryzby, Magnus Hagander and
more.

Author: Nathan Bossart
Discussion: https://postgr.es/m/F2772387-CE0F-46BF-B5F1-CC55516EB885@amazon.com
This commit is contained in:
Michael Paquier 2021-09-16 10:59:26 +09:00
parent 2c7615f77b
commit 0c39c29207
5 changed files with 83 additions and 14 deletions

View File

@ -133,13 +133,20 @@ PostgreSQL documentation
<listitem>
<para>
Prints the value of the named run-time parameter, and exits.
(See the <option>-c</option> option above for details.) This can
be used on a running server, and returns values from
(See the <option>-c</option> option above for details.) This
returns values from
<filename>postgresql.conf</filename>, modified by any parameters
supplied in this invocation. It does not reflect parameters
supplied when the cluster was started.
</para>
<para>
This can be used on a running server for most parameters. However,
the server must be shut down for some runtime-computed parameters
(e.g., <xref linkend="guc-shared-memory-size"/> and
<xref linkend="guc-wal-segment-size"/>).
</para>
<para>
This option is meant for other programs that interact with a server
instance, such as <xref linkend="app-pg-ctl"/>, to query configuration

View File

@ -896,15 +896,31 @@ PostmasterMain(int argc, char *argv[])
if (output_config_variable != NULL)
{
/*
* "-C guc" was specified, so print GUC's value and exit. No extra
* permission check is needed because the user is reading inside the
* data dir.
* If this is a runtime-computed GUC, it hasn't yet been initialized,
* and the present value is not useful. However, this is a convenient
* place to print the value for most GUCs because it is safe to run
* postmaster startup to this point even if the server is already
* running. For the handful of runtime-computed GUCs that we cannot
* provide meaningful values for yet, we wait until later in
* postmaster startup to print the value. We won't be able to use -C
* on running servers for those GUCs, but using this option now would
* lead to incorrect results for them.
*/
const char *config_val = GetConfigOption(output_config_variable,
false, false);
int flags = GetConfigOptionFlags(output_config_variable, true);
puts(config_val ? config_val : "");
ExitPostmaster(0);
if ((flags & GUC_RUNTIME_COMPUTED) == 0)
{
/*
* "-C guc" was specified, so print GUC's value and exit. No
* extra permission check is needed because the user is reading
* inside the data dir.
*/
const char *config_val = GetConfigOption(output_config_variable,
false, false);
puts(config_val ? config_val : "");
ExitPostmaster(0);
}
}
/* Verify that DataDir looks reasonable */
@ -1033,6 +1049,26 @@ PostmasterMain(int argc, char *argv[])
*/
InitializeShmemGUCs();
/*
* If -C was specified with a runtime-computed GUC, we held off printing
* the value earlier, as the GUC was not yet initialized. We handle -C
* for most GUCs before we lock the data directory so that the option may
* be used on a running server. However, a handful of GUCs are runtime-
* computed and do not have meaningful values until after locking the data
* directory, and we cannot safely calculate their values earlier on a
* running server. At this point, such GUCs should be properly
* initialized, and we haven't yet set up shared memory, so this is a good
* time to handle the -C option for these special GUCs.
*/
if (output_config_variable != NULL)
{
const char *config_val = GetConfigOption(output_config_variable,
false, false);
puts(config_val ? config_val : "");
ExitPostmaster(0);
}
/*
* Set up shared memory and semaphores.
*/

View File

@ -1983,7 +1983,7 @@ static struct config_bool ConfigureNamesBool[] =
{"data_checksums", PGC_INTERNAL, PRESET_OPTIONS,
gettext_noop("Shows whether data checksums are turned on for this cluster."),
NULL,
GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED
},
&data_checksums,
false,
@ -2342,7 +2342,7 @@ static struct config_int ConfigureNamesInt[] =
{"shared_memory_size", PGC_INTERNAL, PRESET_OPTIONS,
gettext_noop("Shows the size of the server's main shared memory area (rounded up to the nearest MB)."),
NULL,
GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_UNIT_MB
GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_UNIT_MB | GUC_RUNTIME_COMPUTED
},
&shared_memory_size_mb,
0, 0, INT_MAX,
@ -2407,7 +2407,7 @@ static struct config_int ConfigureNamesInt[] =
"in the form accepted by the chmod and umask system "
"calls. (To use the customary octal format the number "
"must start with a 0 (zero).)"),
GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED
},
&data_directory_mode,
0700, 0000, 0777,
@ -3231,7 +3231,7 @@ static struct config_int ConfigureNamesInt[] =
{"wal_segment_size", PGC_INTERNAL, PRESET_OPTIONS,
gettext_noop("Shows the size of write ahead log segments."),
NULL,
GUC_UNIT_BYTE | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
GUC_UNIT_BYTE | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED
},
&wal_segment_size,
DEFAULT_XLOG_SEG_SIZE,

View File

@ -10,7 +10,7 @@ use PostgresNode;
use TestLib;
use Fcntl qw(:seek);
use Test::More tests => 63;
use Test::More tests => 69;
# Utility routine to create and check a table with corrupted checksums
@ -178,11 +178,31 @@ command_fails(
[ 'pg_checksums', '--enable', '--filenode', '1234', '-D', $pgdata ],
"fails when relfilenodes are requested and action is --enable");
# Test postgres -C for an offline cluster.
# Run-time GUCs are safe to query here. Note that a lock file is created,
# then unlinked, leading to an extra LOG entry showing in stderr.
command_checks_all(
[ 'postgres', '-D', $pgdata, '-C', 'data_checksums' ],
0,
[qr/^on$/],
# LOG entry when unlinking lock file.
[qr/database system is shut down/],
'data_checksums=on is reported on an offline cluster');
# Checks cannot happen with an online cluster
$node->start;
command_fails([ 'pg_checksums', '--check', '-D', $pgdata ],
"fails with online cluster");
# Test postgres -C on an online cluster.
command_fails_like(
[ 'postgres', '-D', $pgdata, '-C', 'data_checksums' ],
qr/lock file .* already exists/,
'data_checksums is not reported on an online cluster');
command_ok(
[ 'postgres', '-D', $pgdata, '-C', 'work_mem' ],
'non-runtime parameter is reported on an online cluster');
# Check corruption of table on default tablespace.
check_relation_corruption($node, 'corrupt1', 'pg_default');

View File

@ -229,6 +229,12 @@ typedef enum
#define GUC_EXPLAIN 0x100000 /* include in explain */
/*
* GUC_RUNTIME_COMPUTED is intended for runtime-computed GUCs that are only
* available via 'postgres -C' if the server is not running.
*/
#define GUC_RUNTIME_COMPUTED 0x200000
#define GUC_UNIT (GUC_UNIT_MEMORY | GUC_UNIT_TIME)