Re: GUC assign hooks (was Re: wal_buffers = -1 and SIGHUP) - Mailing list pgsql-hackers

From Tom Lane
Subject Re: GUC assign hooks (was Re: wal_buffers = -1 and SIGHUP)
Date
Msg-id 5291.1301950665@sss.pgh.pa.us
Whole thread Raw
In response to Re: GUC assign hooks (was Re: wal_buffers = -1 and SIGHUP)  (Robert Haas <robertmhaas@gmail.com>)
Responses Re: GUC assign hooks (was Re: wal_buffers = -1 and SIGHUP)
Re: GUC assign hooks (was Re: wal_buffers = -1 and SIGHUP)
List pgsql-hackers
Robert Haas <robertmhaas@gmail.com> writes:
> OK.  Please comment the crap out of whatever you do, or maybe even add
> a README.  This stuff is just a bit arcane, and guideposts help a lot.

We already have a README for that ;-).  PFA, a patch to
src/backend/utils/misc/README describing the proposed revised API.
If nobody has any objections, I'll get on with making this happen.

            regards, tom lane

diff --git a/src/backend/utils/misc/README b/src/backend/utils/misc/README
index 881862a30b182a94cd71c6ed1a98dd6e6d5e51e0..221f595f8b72eb1cf48d318beb4aa8d3cb2b3411 100644
*** a/src/backend/utils/misc/README
--- b/src/backend/utils/misc/README
*************** determining which setting is used.
*** 12,68 ****
  Per-Variable Hooks
  ------------------

! Each variable known to GUC can optionally have an assign_hook and/or
! a show_hook to provide customized behavior.  Assign hooks are used to
! perform validity checking on variable values (above and beyond what
! GUC can do).  They are also used to update any derived state that needs
! to change when a GUC variable is set.  Show hooks are used to modify
! the default SHOW display for a variable.

  If an assign_hook is provided, it points to a function of the signature
!     bool assign_hook(newvalue, bool doit, GucSource source)
! where the type of "newvalue" matches the kind of variable.  This function
! is called immediately before actually setting the variable's value (so it
! can look at the actual variable to determine the old value).  If the
! function returns "true" then the assignment is completed; if it returns
! "false" then newvalue is considered invalid and the assignment is not
! performed.  If "doit" is false then the function should simply check
! validity of newvalue and not change any derived state.  The "source" parameter
! indicates where the new value came from.  If it is >= PGC_S_INTERACTIVE,
! then we are performing an interactive assignment (e.g., a SET command), and
! ereport(ERROR) is safe to do.  But when source < PGC_S_INTERACTIVE, we are
! reading a non-interactive option source, such as postgresql.conf.  In this
! case the assign_hook should *not* ereport but should just return false if it
! doesn't like the newvalue.

! If an assign_hook returns false then guc.c will report a generic "invalid
! value for option FOO" error message.  If you feel the need to provide a more
! specific error message, ereport() it using "GUC_complaint_elevel(source)"
! as the error level.  Note that this might return either ERROR or a lower level
! such as LOG, so the ereport call might or might not return.  If it does
! return, return false out of the assign_hook.

! For string variables, the signature for assign hooks is a bit different:
!     const char *assign_hook(const char *newvalue,
!                 bool doit,
!                 GucSource source)
! The meanings of the parameters are the same as for the other types of GUC
! variables, but the return value is handled differently:
!     NULL --- assignment fails (like returning false for other datatypes)
!     newvalue --- assignment succeeds, assign the newvalue as-is
!     malloc'd (not palloc'd!!!) string --- assign that value instead
! The third choice is allowed in case the assign_hook wants to return a
! "canonical" version of the new value.  For example, the assign_hook for
! datestyle always returns a string that includes both output and input
! datestyle options, although the input might have specified only one.

- Note that a string variable's assign_hook will NEVER be called with a NULL
- value for newvalue, since there would be no way to distinguish success
- and failure returns.  If the boot_val or reset_val for a string variable
- is NULL, it will just be assigned without calling the assign_hook.
- Therefore, a NULL boot_val should never be used in combination with an
- assign_hook that has side-effects, as the side-effects wouldn't happen
- during a RESET that re-institutes the boot-time setting.

  If a show_hook is provided, it points to a function of the signature
      const char *show_hook(void)
--- 12,108 ----
  Per-Variable Hooks
  ------------------

! Each variable known to GUC can optionally have a check_hook, an
! assign_hook, and/or a show_hook to provide customized behavior.
! Check hooks are used to perform validity checking on variable values
! (above and beyond what GUC can do), to compute derived settings when
! nontrivial work is needed to do that, and optionally to "canonicalize"
! user-supplied values.  Assign hooks are used to update any derived state
! that needs to change when a GUC variable is set.  Show hooks are used to
! modify the default SHOW display for a variable.
!
!
! If a check_hook is provided, it points to a function of the signature
!     bool check_hook(datatype *newvalue, void **extra, GucSource source)
! The "newvalue" argument is of type bool *, int *, double *, or char **
! for bool, int/enum, float, or string variables respectively.  The check
! function should validate the proposed new value, and return true if it is
! OK or false if not.  The function can optionally do a few other things:
!
! * When rejecting a bad proposed value, it may be useful to append some
! additional information to the generic "invalid value for option FOO"
! complaint that guc.c will emit.  To do that, call
!     void GUC_check_errdetail(const char *format, ...)
! where the format string and additional arguments follow the rules for
! errdetail() arguments.  The resulting string will be emitted as the
! DETAIL line of guc.c's error report, so it should follow the message style
! guidelines for DETAIL messages.  In general, check_hooks should avoid
! throwing errors directly if possible, though this may be difficult to
! avoid for some corner cases such as out-of-memory.
!
! * Since the newvalue is pass-by-reference, the function can modify it.
! This might be used for example to canonicalize the spelling of a string
! value, round off a buffer size to the nearest supported value, or replace
! a special value such as "-1" with a computed default value.  If the
! function wishes to replace a string value, it must malloc (not palloc)
! the replacement value, and be sure to free() the previous value.
!
! * Derived information, such as the role OID represented by a user name,
! can be stored for use by the assign hook.  To do this, malloc (not palloc)
! storage space for the information, and return its address at *extra.
! guc.c will automatically free() this space when the associated GUC setting
! is no longer of interest.  *extra is initialized to NULL before call, so
! it can be ignored if not needed.
!
! The "source" argument indicates the source of the proposed new value,
! If it is >= PGC_S_INTERACTIVE, then we are performing an interactive
! assignment (e.g., a SET command).  But when source < PGC_S_INTERACTIVE,
! we are reading a non-interactive option source, such as postgresql.conf.
! This is sometimes needed to determine whether a setting should be
! allowed.  The check_hook might also look at the current actual value of
! the variable to determine what is allowed.
!
! Note that check hooks are sometimes called just to validate a value,
! without any intention of actually changing the setting.  Therefore the
! check hook must *not* take any action based on the assumption that an
! assignment will occur.
!

  If an assign_hook is provided, it points to a function of the signature
!     bool assign_hook(datatype newvalue, void *extra)
! where the type of "newvalue" matches the kind of variable, and "extra"
! is the derived-information pointer returned by the check_hook (always
! NULL if there is no check_hook).  This function is called immediately
! before actually setting the variable's value (so it can look at the actual
! variable to determine the old value, for example to avoid doing work when
! the value isn't really changing).  If the function returns "true" then
! the assignment is completed; if it returns "false" then the assignment
! fails and the variable value is not changed.

! IMPORTANT: assign_hooks should never fail except under the most dire
! circumstances (such as out-of-memory), since a failure may for example
! result in a GUC setting not being rolled back during transaction abort.
! In general, try to do anything that could conceivably fail in a check_hook
! instead, and pass along the results in an "extra" struct, so that the
! assign hook has little to do beyond copying the data to someplace.  This
! applies particularly to catalog lookups: any required lookups should be
! done in the check_hook, since the assign_hook may be executed during
! transaction rollback when lookups will be unsafe.

! Note that check_hooks are sometimes called outside any transaction, too.
! This happens when processing the wired-in "bootstrap" value, values coming
! from the postmaster command line or environment, or values coming from
! postgresql.conf.  Therefore, any catalog lookups done in a check_hook
! should be guarded with an IsTransactionState() test, and there must be a
! fallback path to allow derived values to be computed during the first
! subsequent use of the GUC setting within a transaction.  Typically,
! catalog values computed by the check_hook and installed by the assign_hook
! are used only for the remainder of the transaction in which the new
! setting is made.  Each subsequent transaction looks up the values afresh
! on first use.  This arrangement is useful to prevent use of stale catalog
! values, independently of the problem of needing to check GUC values
! outside a transaction.


  If a show_hook is provided, it points to a function of the signature
      const char *show_hook(void)
*************** currently a different interactive value
*** 202,226 ****

  The assign_hook and show_hook routines work only with the actual variable,
  and are not directly aware of the additional values maintained by GUC.
- This is not a problem for normal usage, since we can assign first to the
- actual variable and then (if that succeeds) to the additional values as
- needed.  However, for SIGHUP rereads we may not want to assign to the
- actual variable.  Our procedure in that case is to call the assign_hook
- with doit = false so that the value is validated, but no derived state is
- changed.


! String Memory Handling
! ----------------------

! String option values are allocated with strdup, not with the
! pstrdup/palloc mechanisms.  We would need to keep them in a permanent
! context anyway, and strdup gives us more control over handling
  out-of-memory failures.

  We allow a string variable's actual value, reset_val, boot_val, and stacked
  values to point at the same storage.  This makes it slightly harder to free
  space (we must test whether a value to be freed isn't equal to any of the
  other pointers in the GUC entry or associated stack items).  The main
! advantage is that we never need to strdup during transaction commit/abort,
  so cannot cause an out-of-memory failure there.
--- 242,264 ----

  The assign_hook and show_hook routines work only with the actual variable,
  and are not directly aware of the additional values maintained by GUC.


! GUC Memory Handling
! -------------------

! String option values are allocated with malloc/strdup, not with the
! palloc/pstrdup mechanisms.  We would need to keep them in a permanent
! context anyway, and malloc gives us more control over handling
  out-of-memory failures.

  We allow a string variable's actual value, reset_val, boot_val, and stacked
  values to point at the same storage.  This makes it slightly harder to free
  space (we must test whether a value to be freed isn't equal to any of the
  other pointers in the GUC entry or associated stack items).  The main
! advantage is that we never need to malloc during transaction commit/abort,
  so cannot cause an out-of-memory failure there.
+
+ "Extra" structs returned by check_hook routines are managed in the same
+ way as string values.  Note that we support "extra" structs for all types
+ of GUC variables, although they are mainly useful with strings.

pgsql-hackers by date:

Previous
From: Gabriele Bartolini
Date:
Subject: Re: [DOCS] Uppercase SGML entity declarations
Next
From: Alexey Klyukin
Date:
Subject: Re: proposal: a validator for configuration files