Обсуждение: Reorganize GUC structs

Поиск
Список
Период
Сортировка

Reorganize GUC structs

От
Peter Eisentraut
Дата:
This patch series does some reorganizing of the GUC table structs 
(config_generic, config_bool, etc.) to modernize and simplify things.  I 
suspect that some changes like these would have been desirable as the 
GUC code has evolved over time, but were avoided because of the burden 
of having to adjust all the static GUC tables at the same time.  Since 
these are now generated, this is no longer a problem.

The main change is that instead of having five separate structs, one for 
each type, with the generic part contained in each of them, flip it 
around and have one common struct, with the type-specific part has a 
subfield.

The very original GUC design had type-specific structs and
type-specific lists, and the membership in one of the lists defined
the type.  But now the structs themselves know the type (from the
.vartype field), and they are all loaded into a common hash table at
run time, this original separation no longer makes sense.  It creates
a bunch of inconsistencies in the code about whether the type-specific
or the generic struct is the primary struct, and a lot of casting in
between, which makes certain assumptions about the struct layouts.

After the change, all these casts are gone and all the data is
accessed via normal field references.  Also, various code is
simplified because only one kind of struct needs to be processed.

Additionally, I have sorted guc_parameters.dat alphabetically by name, 
and have added code to enforce the sort order going forward.  (Note: The 
order is actually checked after lower-casing, to handle the likes of 
"DateStyle".)

The order in these lists was previously pretty random and had grown
organically over time.  This made it unnecessarily cumbersome to
maintain these lists, as there was no clear guidelines about where to
put new entries.  Also, after the merger of the type-specific GUC
structs, the list still reflected the previous type-specific
super-order.

By enforcing alphabetical order, the place for new entries becomes 
clear, and often related entries will be listed close together.

The patches in the series are arranged so that they can be considered 
and applied incrementally.

Вложения

Re: Reorganize GUC structs

От
Chao Li
Дата:

On Oct 3, 2025, at 14:55, Peter Eisentraut <peter@eisentraut.org> wrote:


The patches in the series are arranged so that they can be considered and applied incrementally.
<v1-0001-Modernize-some-for-loops.patch><v1-0002-Add-some-const-qualifiers.patch><v1-0003-Change-reset_extra-into-a-config_generic-common-f.patch><v1-0004-Use-designated-initializers-for-guc_tables.patch><v1-0005-Change-config_generic.vartype-to-be-initialized-a.patch><v1-0006-Reorganize-GUC-structs.patch><v1-0007-Sort-guc_parameters.dat-alphabetically-by-name.patch><v1-0008-Enforce-alphabetical-order-in-guc_parameters.dat.patch>


0001 - looks good to me. Basically it only moves for loop’s loop variable type definition into for(), it isn’t tied to rest commits, I guess it can be pushed independently.

0002 - also looks good. It just add “const” where possible. I think it can be pushed together with 0001.

0003 - also looks good. It moves “reset_extra” from individual typed config structure to “config_generic”, which dramatically eliminates unnecessary switch-cases. Just a small comment:

```
@@ -6244,29 +6217,11 @@ RestoreGUCState(void *gucstate)
  switch (gconf->vartype)
  {
  case PGC_BOOL:
- {
- struct config_bool *conf = (struct config_bool *) gconf;
-
- if (conf->reset_extra && conf->reset_extra != gconf->extra)
- guc_free(conf->reset_extra);
- break;
- }
  case PGC_INT:
- {
- struct config_int *conf = (struct config_int *) gconf;
-
- if (conf->reset_extra && conf->reset_extra != gconf->extra)
- guc_free(conf->reset_extra);
- break;
- }
  case PGC_REAL:
- {
- struct config_real *conf = (struct config_real *) gconf;
-
- if (conf->reset_extra && conf->reset_extra != gconf->extra)
- guc_free(conf->reset_extra);
- break;
- }
+ case PGC_ENUM:
+ /* no need to do anything */
+ break;
  case PGC_STRING:
  {
  struct config_string *conf = (struct config_string *) gconf;
@@ -6274,19 +6229,11 @@ RestoreGUCState(void *gucstate)
  guc_free(*conf->variable);
  if (conf->reset_val && conf->reset_val != *conf->variable)
  guc_free(conf->reset_val);
- if (conf->reset_extra && conf->reset_extra != gconf->extra)
- guc_free(conf->reset_extra);
- break;
- }
- case PGC_ENUM:
- {
- struct config_enum *conf = (struct config_enum *) gconf;
-
- if (conf->reset_extra && conf->reset_extra != gconf->extra)
- guc_free(conf->reset_extra);
  break;
  }
  }
```

Do we still need this switch-case? As only PGC_STRING needs to do something, why not just do:

```
If (gconf-vartype == PGC_STRING)
{
    …
}
if (gconf->reset_extra && gconf->reset_extra != gconf->extra)
    guc_free(gconf->reset_extra);
```

0004 - Also looks good to me. But I am not an expert of perl programming, so I cannot comment much.

0005 - Also looks good to me. This is a small change. It updates the perl script to set vartype so that vartype gets set at compile time, which further simplifies the c code.

0006 - Comes to the most interesting part of this patch. It moves all typed config into “config_generic” as a unnamed union, then replaces typed config with config_generic everywhere. Though this commit touches a lot of lines of code, but all changes are straightforward. Also looks good to me.

0007 needs a rebase. I guess you may split 0007 and 0008 to a separate patch once 0001-0006 are pushed. As they only re-order GUC variables without real logic change, so they can be quickly reviewed and pushed, otherwise it would be painful where every commit the touches GUC would lead to a rebase.

0008 - I don’t review it as 0007 needs a rebase.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/




Re: Reorganize GUC structs

От
John Naylor
Дата:
On Fri, Oct 3, 2025 at 1:55 PM Peter Eisentraut <peter@eisentraut.org> wrote:
> Additionally, I have sorted guc_parameters.dat alphabetically by name,
> and have added code to enforce the sort order going forward.  (Note: The

That makes sense by default. Another possibility would be to keep them
in the same order as postgresql.conf.sample. You mentioned earlier it
may be possible to generate the latter, although it's not yet clear if
that could be done easily. If not, then keeping them in sync would be
extra work.

--
John Naylor
Amazon Web Services



Re: Reorganize GUC structs

От
Álvaro Herrera
Дата:
On 2025-Oct-13, John Naylor wrote:

> On Fri, Oct 3, 2025 at 1:55 PM Peter Eisentraut <peter@eisentraut.org> wrote:
> > Additionally, I have sorted guc_parameters.dat alphabetically by name,
> > and have added code to enforce the sort order going forward.
> 
> That makes sense by default. Another possibility would be to keep them
> in the same order as postgresql.conf.sample. You mentioned earlier it
> may be possible to generate the latter, although it's not yet clear if
> that could be done easily. If not, then keeping them in sync would be
> extra work.

I agree that keeping the guc_parameters.dat file alphabetically sorted
by default would keep the maintenance cost lowest, because we won't have
to make any subjective decisions for new entries.  However, automatically
generating the .sample file sounds impractical, considering the
free-form comments that we currently have there.  For instance

#max_prepared_transactions = 0      # zero disables the feature
                    # (change requires restart)
# Caution: it is not advisable to set max_prepared_transactions nonzero unless
# you actively intend to use prepared transactions.

We'd have to store the comments together in the guc_parameters.dat table
so that the sample file knows where and how to put them, and it would
IMO look worse.  

Also, the order of entries in postgresql.conf.sample was at some point
carefully considered.  Messing that up (by making the entries match
alphabetical order, even within each section) would also be worse IMO.
So we'd have to add values for the sorting to know where in the file
each section goes, what its opening comment is, and where each entry
goes within each section.

I think instead of that mess, maybe we can simply keep the sample file
as-is, cross-check that a line for each non-hidden GUC variable exists,
and perhaps that the commented-out default value matches the data file.

-- 
Álvaro Herrera               48°01'N 7°57'E  —  https://www.EnterpriseDB.com/
Al principio era UNIX, y UNIX habló y dijo: "Hello world\n".
No dijo "Hello New Jersey\n", ni "Hello USA\n".



Re: Reorganize GUC structs

От
Peter Eisentraut
Дата:
On 13.10.25 13:39, Álvaro Herrera wrote:
> I agree that keeping the guc_parameters.dat file alphabetically sorted
> by default would keep the maintenance cost lowest, because we won't have
> to make any subjective decisions for new entries.  However, automatically
> generating the .sample file sounds impractical, considering the
> free-form comments that we currently have there.

Yes, I'm not sure if it's practical in the fullest extent.  But there 
were at various points discussions about alternative layouts and 
contents for postgresql.conf.sample, with a lot of opinions.  With this 
new framework, I think it might be interesting to experiment.  Which is 
why I mentioned it.

> I think instead of that mess, maybe we can simply keep the sample file
> as-is, cross-check that a line for each non-hidden GUC variable exists,
> and perhaps that the commented-out default value matches the data file.

Those would certainly be reasonable near-term steps.



Re: Reorganize GUC structs

От
Peter Eisentraut
Дата:
On 09.10.25 09:15, Chao Li wrote:
> 0001 - looks good to me. Basically it only moves for loop’s loop 
> variable type definition into for(), it isn’t tied to rest commits, I 
> guess it can be pushed independently.
> 
> 0002 - also looks good. It just add “const” where possible. I think it 
> can be pushed together with 0001.
> 
> 0003 - also looks good. It moves “reset_extra” from individual typed 
> config structure to “config_generic”, which dramatically eliminates 
> unnecessary switch-cases.

I have committed these first three.  Attached is the rest of the patch 
series rebased.

It looks like we have consensus in principle on the remaining changes, 
but I'll leave them out here a while longer in case there are any 
further thoughts.

Regarding ...

> Just a small comment:
> 
> ```
> @@ -6244,29 +6217,11 @@ RestoreGUCState(void *gucstate)
> switch (gconf->vartype)
> {
> case PGC_BOOL:
> -{
> -struct config_bool *conf = (struct config_bool *) gconf;
> -
> -if (conf->reset_extra && conf->reset_extra != gconf->extra)
> -guc_free(conf->reset_extra);
> -break;
> -}
> case PGC_INT:
> -{
> -struct config_int *conf = (struct config_int *) gconf;
> -
> -if (conf->reset_extra && conf->reset_extra != gconf->extra)
> -guc_free(conf->reset_extra);
> -break;
> -}
> case PGC_REAL:
> -{
> -struct config_real *conf = (struct config_real *) gconf;
> -
> -if (conf->reset_extra && conf->reset_extra != gconf->extra)
> -guc_free(conf->reset_extra);
> -break;
> -}
> +case PGC_ENUM:
> +/* no need to do anything */
> +break;
> case PGC_STRING:
> {
> struct config_string *conf = (struct config_string *) gconf;
> @@ -6274,19 +6229,11 @@ RestoreGUCState(void *gucstate)
> guc_free(*conf->variable);
> if (conf->reset_val && conf->reset_val != *conf->variable)
> guc_free(conf->reset_val);
> -if (conf->reset_extra && conf->reset_extra != gconf->extra)
> -guc_free(conf->reset_extra);
> -break;
> -}
> -case PGC_ENUM:
> -{
> -struct config_enum *conf = (struct config_enum *) gconf;
> -
> -if (conf->reset_extra && conf->reset_extra != gconf->extra)
> -guc_free(conf->reset_extra);
> break;
> }
> }
> ```
> 
> Do we still need this switch-case? As only PGC_STRING needs to do 
> something, why not just do:
> 
> ```
> If (gconf-vartype == PGC_STRING)
> {
>      …
> }
> if (gconf->reset_extra && gconf->reset_extra != gconf->extra)
>      guc_free(gconf->reset_extra);
> ```

I initially had it like that, but there are a couple of other places in 
the existing code that have a switch with only actual code for 
PGC_STRING, so I ended up following that pattern.

Вложения

Re: Reorganize GUC structs

От
Heikki Linnakangas
Дата:
> @@ -261,15 +261,15 @@ static bool assignable_custom_variable_name(const char *name, bool skip_errors,
>                                              int elevel);
>  static void do_serialize(char **destptr, Size *maxbytes,
>                           const char *fmt,...) pg_attribute_printf(3, 4);
> -static bool call_bool_check_hook(const struct config_bool *conf, bool *newval,
> +static bool call_bool_check_hook(const struct config_generic *conf, bool *newval,
>                                   void **extra, GucSource source, int elevel);
> -static bool call_int_check_hook(const struct config_int *conf, int *newval,
> +static bool call_int_check_hook(const struct config_generic *conf, int *newval,
>                                  void **extra, GucSource source, int elevel);
> -static bool call_real_check_hook(const struct config_real *conf, double *newval,
> +static bool call_real_check_hook(const struct config_generic *conf, double *newval,
>                                   void **extra, GucSource source, int elevel);
> -static bool call_string_check_hook(const struct config_string *conf, char **newval,
> +static bool call_string_check_hook(const struct config_generic *conf, char **newval,
>                                     void **extra, GucSource source, int elevel);
> -static bool call_enum_check_hook(const struct config_enum *conf, int *newval,
> +static bool call_enum_check_hook(const struct config_generic *conf, int *newval,
>                                   void **extra, GucSource source, int elevel);

The new signatures for these function are less specific than before, 
making them a little worse IMO. Overall +1 on the patches, despite that 
little drawback.

- Heikki