On 8/6/19 11:16 AM, Stephen Frost wrote: > Greetings, > > * Ian Barwick (ian.barw...@2ndquadrant.com) wrote: >> On 8/6/19 9:52 AM, Stephen Frost wrote:> Greetings, >>> * Tom Lane (t...@sss.pgh.pa.us) wrote: >>>> >>>> + <para> >>>> + External tools might also >>>> + modify <filename>postgresql.auto.conf</filename>, typically by appending >>>> + new settings to the end. It is not recommended to do this while the >>>> + server is running, since a concurrent <command>ALTER SYSTEM</command> >>>> + command could overwrite such changes. >>>> </para> >>> >>> Alternatively, or maybe also here, we could say "note that appending to >>> the file as a mechanism for setting a new value by an external tool is >>> acceptable even though it will cause duplicates- PostgreSQL will always >>> use the last value set and other tools should as well. Duplicates and >>> comments may be removed when rewriting the file >> >> FWIW, as the file is rewritten each time, *all* comments are removed >> anyway (the first two comment lines in the file with the warning >> are added when the new version of the file is written(). > > Whoah- the file is *not* rewritten each time. It's only rewritten each > time by *ALTER SYSTEM*, but that it not the only thing that's modifying > the file. That mistaken assumption is part of what got us into this > mess...
Ah, got it, I thought you were talking about the ALTER SYSTEM behaviour. >>> and parameters may be >>> lower-cased." (istr that last bit being true too but I haven't checked >>> lately). >> >> Ho-hum, they won't be lower-cased, instead currently they just won't be >> overwritten if they're present in pg.auto.conf, which is a slight >> eccentricity, but not actually a problem with the current code as the new value >> will be written last. E.g.: >> >> $ cat postgresql.auto.conf >> # Do not edit this file manually! >> # It will be overwritten by the ALTER SYSTEM command. >> DEFAULT_TABLESPACE = 'space_1' >> >> postgres=# ALTER SYSTEM SET default_tablespace ='pg_default'; >> ALTER SYSTEM >> >> $ cat postgresql.auto.conf >> # Do not edit this file manually! >> # It will be overwritten by the ALTER SYSTEM command. >> DEFAULT_TABLESPACE = 'space_1' >> default_tablespace = 'pg_default' >> >> I don't think that's worth worrying about now. > > Erm, those are duplicates though and we're saying that ALTER SYSTEM > removes those... Seems like we should be normalizing the file to be > consistent in this regard too. True. (Switches brain on)... Ah yes, with the patch previously provided by Tom, it seems to be just a case of replacing "strcmp" with "guc_name_compare" to match the existing string; the name will be rewritten with the value provided to ALTER SYSTEM, which will be normalized to lower case anyway. Tweaked version attached. >> My suggestion for the paragaph in question: >> >> <para> >> External tools which need to write configuration settings (e.g. for replication) >> where it's essential to ensure these are read last (to override versions >> of these settings present in other configuration files), may append settings to >> <filename>postgresql.auto.conf</filename>. It is not recommended to do this while >> the server is running, since a concurrent <command>ALTER SYSTEM</command> >> command could overwrite such changes. Note that a subsequent >> <command>ALTER SYSTEM</command> will cause <filename>postgresql.auto.conf</filename>, >> to be rewritten, removing any duplicate versions of the setting altered, and also >> any comment lines present. >> </para> > > I dislike the special-casing of ALTER SYSTEM here, where we're basically > saying that only ALTER SYSTEM is allowed to do this cleanup and that if > such cleanup is wanted then ALTER SYSTEM must be run. This is just saying what ALTER SYSTEM will do, which IMHO we should describe somewhere. Initially when I stated working with pg.auto.conf I had my application append a comment line to show where the entries came from, but not having any idea how pg.auto.conf was modified at that point, I was wondering why the comment subsequently disappeared. Perusing the source code has explained that for me, but would be mighty useful to document that. > What I was trying to get at is a definition of what transformations are > allowed and to make it clear that anything using/modifying the file > needs to be prepared for and work with those transformations. I don't > think we want people assuming that if they don't run ALTER SYSTEM then > they can depend on duplicates being preserved and such.. OK, then we should be saying something like: - pg.auto.conf may be rewritten at any point and duplicates/comments removed - the rewrite will occur whenever ALTER SYSTEM is run, removing duplicates of the parameter being modified and any comments - external utilities may also rewrite it; they may, if they wish, remove duplicates and comments > and, yes, I > know that's a stretch, but if we ever want anything other than ALTER > SYSTEM to be able to make such changes (and I feel pretty confident that > we will...) then we shouldn't document things specifically about when > that command runs. But at this point ALTER SYSTEM is the only thing which is known to modify the file, with known effects. If in a future release something else is added, the documentation can be updated as appropriate. Regards Ian Barwick -- Ian Barwick https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 3051c9cf8e..0093e9096a 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -7281,40 +7281,37 @@ replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p, const char *name, const char *value) { ConfigVariable *item, + *next, *prev = NULL; - /* Search the list for an existing match (we assume there's only one) */ - for (item = *head_p; item != NULL; item = item->next) + /* + * Remove any existing match(es) for "name". Normally there'd be at most + * one, but if external tools have modified the config file, there could + * be more. + */ + for (item = *head_p; item != NULL; item = next) { - if (strcmp(item->name, name) == 0) + next = item->next; + if (guc_name_compare(item->name, name) == 0) { - /* found a match, replace it */ - pfree(item->value); - if (value != NULL) - { - /* update the parameter value */ - item->value = pstrdup(value); - } + /* found a match, delete it */ + if (prev) + prev->next = next; else - { - /* delete the configuration parameter from list */ - if (*head_p == item) - *head_p = item->next; - else - prev->next = item->next; - if (*tail_p == item) - *tail_p = prev; + *head_p = next; + if (next == NULL) + *tail_p = prev; - pfree(item->name); - pfree(item->filename); - pfree(item); - } - return; + pfree(item->value); + pfree(item->name); + pfree(item->filename); + pfree(item); } - prev = item; + else + prev = item; } - /* Not there; no work if we're trying to delete it */ + /* Done if we're trying to delete it */ if (value == NULL) return;