agora inbox for pgsql-hackers@postgresql.orghelp / color / mirror / Atom feed
[PATCH v2 4/6] Introduce pending flag for GUC assign hooks 319+ messages / 2 participants [nested] [flat]
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v2 4/6] Introduce pending flag for GUC assign hooks @ 2025-02-19 16:45 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-02-19 16:45 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 16 ++++---- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f9bf5ba7509..ff82ba0a53d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2188,7 +2188,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 4ad6e236d69..f24c2a0d252 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { #ifdef USE_PREFETCH /* diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 61ea3722ae2..cdf21847d7e 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1949,7 +1949,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1982,7 +1982,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2005,7 +2005,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2028,7 +2028,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 1149d89d7a1..13fb8c31702 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3555,7 +3555,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 12192445218..bab1c5d08f6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..ce9f258100d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..3e380f29e5a 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,12 +81,12 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); -extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -141,13 +141,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -163,7 +163,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --q7xzg7duksj2kgko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v2-0005-Allow-to-resize-shared-memory-without-restart.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v4 4/8] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ec40c0b7c42..9aa426992a2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index a9f2a3a3062..e715a6f01c2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,13 +1161,13 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_max_combine_limit = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit_guc = newval; io_combine_limit = Min(io_max_combine_limit, io_combine_limit_guc); diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6ae9f38f0c8..b1fba850f02 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3593,7 +3593,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.45.1 --vninua6xybvzgrci Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v4-0005-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v5 02/10] Introduce pending flag for GUC assign hooks @ 2025-04-06 14:40 Dmitrii Dolgov <9erthalion6@gmail.com> 0 siblings, 0 replies; 319+ messages in thread From: Dmitrii Dolgov @ 2025-04-06 14:40 UTC (permalink / raw) Currently an assing hook can perform some preprocessing of a new value, but it cannot change the behavior, which dictates that the new value will be applied immediately after the hook. Certain GUC options (like shared_buffers, coming in subsequent patches) may need coordinating work between backends to change, meaning we cannot apply it right away. Add a new flag "pending" for an assign hook to allow the hook indicate exactly that. If the pending flag is set after the hook, the new value will not be applied and it's handling becomes the hook's implementation responsibility. Note, that this also requires changes in the way how GUCs are getting reported, but the patch does not cover that yet. --- src/backend/access/transam/xlog.c | 2 +- src/backend/commands/variable.c | 6 +-- src/backend/libpq/pqcomm.c | 8 ++-- src/backend/tcop/postgres.c | 2 +- src/backend/utils/misc/guc.c | 59 +++++++++++++++++++--------- src/backend/utils/misc/stack_depth.c | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_hooks.h | 20 +++++----- 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 47ffc0a2307..d1be780683b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2321,7 +2321,7 @@ CalculateCheckpointSegments(void) } void -assign_max_wal_size(int newval, void *extra) +assign_max_wal_size(int newval, void *extra, bool *pending) { max_wal_size_mb = newval; CalculateCheckpointSegments(); diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..e40dae2ddf2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1143,7 +1143,7 @@ check_cluster_name(char **newval, void **extra, GucSource source) * GUC assign_hook for maintenance_io_concurrency */ void -assign_maintenance_io_concurrency(int newval, void *extra) +assign_maintenance_io_concurrency(int newval, void *extra, bool *pending) { /* * Reconfigure recovery prefetching, because a setting it depends on @@ -1161,12 +1161,12 @@ assign_maintenance_io_concurrency(int newval, void *extra) * they may be assigned in either order. */ void -assign_io_max_combine_limit(int newval, void *extra) +assign_io_max_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(newval, io_combine_limit_guc); } void -assign_io_combine_limit(int newval, void *extra) +assign_io_combine_limit(int newval, void *extra, bool *pending) { io_combine_limit = Min(io_max_combine_limit, newval); } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index e5171467de1..2a6a587ef76 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -1952,7 +1952,7 @@ pq_settcpusertimeout(int timeout, Port *port) * GUC assign_hook for tcp_keepalives_idle */ void -assign_tcp_keepalives_idle(int newval, void *extra) +assign_tcp_keepalives_idle(int newval, void *extra, bool *pending) { /* * The kernel API provides no way to test a value without setting it; and @@ -1985,7 +1985,7 @@ show_tcp_keepalives_idle(void) * GUC assign_hook for tcp_keepalives_interval */ void -assign_tcp_keepalives_interval(int newval, void *extra) +assign_tcp_keepalives_interval(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivesinterval(newval, MyProcPort); @@ -2008,7 +2008,7 @@ show_tcp_keepalives_interval(void) * GUC assign_hook for tcp_keepalives_count */ void -assign_tcp_keepalives_count(int newval, void *extra) +assign_tcp_keepalives_count(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_setkeepalivescount(newval, MyProcPort); @@ -2031,7 +2031,7 @@ show_tcp_keepalives_count(void) * GUC assign_hook for tcp_user_timeout */ void -assign_tcp_user_timeout(int newval, void *extra) +assign_tcp_user_timeout(int newval, void *extra, bool *pending) { /* See comments in assign_tcp_keepalives_idle */ (void) pq_settcpusertimeout(newval, MyProcPort); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2f8c3d5f918..0d1b6466d1e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3591,7 +3591,7 @@ check_log_stats(bool *newval, void **extra, GucSource source) /* GUC assign hook for transaction_timeout */ void -assign_transaction_timeout(int newval, void *extra) +assign_transaction_timeout(int newval, void *extra, bool *pending) { if (IsTransactionState()) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 667df448732..bb681f5bc60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1679,6 +1679,7 @@ InitializeOneGUCOption(struct config_generic *gconf) struct config_int *conf = (struct config_int *) gconf; int newval = conf->boot_val; void *extra = NULL; + bool pending = false; Assert(newval >= conf->min); Assert(newval <= conf->max); @@ -1687,9 +1688,13 @@ InitializeOneGUCOption(struct config_generic *gconf) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, newval); if (conf->assign_hook) - conf->assign_hook(newval, extra); - *conf->variable = conf->reset_val = newval; - conf->gen.extra = conf->reset_extra = extra; + conf->assign_hook(newval, extra, &pending); + + if (!pending) + { + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; + } break; } case PGC_REAL: @@ -2041,13 +2046,18 @@ ResetAllOptions(void) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; + bool pending = false; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->reset_extra); - *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->reset_extra); + conf->reset_extra, + &pending); + if (!pending) + { + *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); + } break; } case PGC_REAL: @@ -2424,16 +2434,21 @@ AtEOXact_GUC(bool isCommit, int nestLevel) struct config_int *conf = (struct config_int *) gconf; int newval = newvalue.val.intval; void *newextra = newvalue.extra; + bool pending = false; if (*conf->variable != newval || conf->gen.extra != newextra) { if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - changed = true; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + changed = true; + } } break; } @@ -3850,18 +3865,24 @@ set_config_with_handle(const char *name, config_handle *handle, if (changeVal) { + bool pending = false; + /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen, action); if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, - newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + conf->assign_hook(newval, newextra, &pending); + + if (!pending) + { + *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); + set_guc_source(&conf->gen, source); + conf->gen.scontext = context; + conf->gen.srole = srole; + } } if (makeDefault) { diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c index 8f7cf531fbc..ef59ae62008 100644 --- a/src/backend/utils/misc/stack_depth.c +++ b/src/backend/utils/misc/stack_depth.c @@ -156,7 +156,7 @@ check_max_stack_depth(int *newval, void **extra, GucSource source) /* GUC assign hook for max_stack_depth */ void -assign_max_stack_depth(int newval, void *extra) +assign_max_stack_depth(int newval, void *extra, bool *pending) { ssize_t newval_bytes = newval * (ssize_t) 1024; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index f619100467d..8802ad8a3cb 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -187,7 +187,7 @@ typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource sourc typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); typedef void (*GucBoolAssignHook) (bool newval, void *extra); -typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra, bool *pending); typedef void (*GucRealAssignHook) (double newval, void *extra); typedef void (*GucStringAssignHook) (const char *newval, void *extra); typedef void (*GucEnumAssignHook) (int newval, void *extra); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 799fa7ace68..c8300cffa8e 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -81,14 +81,14 @@ extern bool check_log_stats(bool *newval, void **extra, GucSource source); extern bool check_log_timezone(char **newval, void **extra, GucSource source); extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); -extern void assign_maintenance_io_concurrency(int newval, void *extra); -extern void assign_io_max_combine_limit(int newval, void *extra); -extern void assign_io_combine_limit(int newval, void *extra); +extern void assign_maintenance_io_concurrency(int newval, void *extra, bool *pending); +extern void assign_io_max_combine_limit(int newval, void *extra, bool *pending); +extern void assign_io_combine_limit(int newval, void *extra, bool *pending); extern bool check_max_slot_wal_keep_size(int *newval, void **extra, GucSource source); -extern void assign_max_wal_size(int newval, void *extra); +extern void assign_max_wal_size(int newval, void *extra, bool *pending); extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); -extern void assign_max_stack_depth(int newval, void *extra); +extern void assign_max_stack_depth(int newval, void *extra, bool *pending); extern bool check_multixact_member_buffers(int *newval, void **extra, GucSource source); extern bool check_multixact_offset_buffers(int *newval, void **extra, @@ -143,13 +143,13 @@ extern void assign_synchronous_standby_names(const char *newval, void *extra); extern void assign_synchronous_commit(int newval, void *extra); extern void assign_syslog_facility(int newval, void *extra); extern void assign_syslog_ident(const char *newval, void *extra); -extern void assign_tcp_keepalives_count(int newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_count(void); -extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern void assign_tcp_keepalives_idle(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_idle(void); -extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern void assign_tcp_keepalives_interval(int newval, void *extra, bool *pending); extern const char *show_tcp_keepalives_interval(void); -extern void assign_tcp_user_timeout(int newval, void *extra); +extern void assign_tcp_user_timeout(int newval, void *extra, bool *pending); extern const char *show_tcp_user_timeout(void); extern bool check_temp_buffers(int *newval, void **extra, GucSource source); extern bool check_temp_tablespaces(char **newval, void **extra, @@ -165,7 +165,7 @@ extern bool check_transaction_buffers(int *newval, void **extra, GucSource sourc extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); -extern void assign_transaction_timeout(int newval, void *extra); +extern void assign_transaction_timeout(int newval, void *extra, bool *pending); extern const char *show_unix_socket_permissions(void); extern bool check_wal_buffers(int *newval, void **extra, GucSource source); extern bool check_wal_consistency_checking(char **newval, void **extra, -- 2.49.0 --bwrlgp6w2ubxykjq Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v5-0003-Introduce-pss_barrierReceivedGeneration.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
* [PATCH v46 6/7] Error out any process that would block at REPACK @ 2026-03-25 19:35 Álvaro Herrera <alvherre@kurilemu.de> 0 siblings, 0 replies; 319+ messages in thread From: Álvaro Herrera @ 2026-03-25 19:35 UTC (permalink / raw) Any process waiting on REPACK to release its lock would actually cause it to deadlock when it tries to upgrade its lock to AEL, losing all work done to that point. We avoid this by teaching the deadlock detector to raise an error when this condition is detected. --- src/backend/commands/repack.c | 53 ++++++++---- src/backend/storage/lmgr/deadlock.c | 15 ++++ src/include/storage/proc.h | 6 +- src/test/modules/injection_points/Makefile | 1 + .../expected/repack_deadlock.out | 63 ++++++++++++++ src/test/modules/injection_points/meson.build | 1 + .../specs/repack_deadlock.spec | 83 +++++++++++++++++++ 7 files changed, 202 insertions(+), 20 deletions(-) create mode 100644 src/test/modules/injection_points/expected/repack_deadlock.out create mode 100644 src/test/modules/injection_points/specs/repack_deadlock.spec diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c index a58277bb6c1..21ab81c6f7f 100644 --- a/src/backend/commands/repack.c +++ b/src/backend/commands/repack.c @@ -276,6 +276,16 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel) /* Determine the lock mode to use. */ lockmode = RepackLockLevel((params.options & CLUOPT_CONCURRENT) != 0); + /* + * If in concurrent mode, set the PROC_IN_CONCURRENT_REPACK flag. This + * makes the deadlock checker cause anyone that would conflict with us + * to error out. It's important to set this flag ahead of actually locking + * the relation; it won't of course affect anyone until we do have a lock + * that others can conflict with. + */ + if ((params.options & CLUOPT_CONCURRENT) != 0) + MyProc->statusFlags |= PROC_IN_CONCURRENT_REPACK; + /* * If a single relation is specified, process it and we're done ... unless * the relation is a partitioned table, in which case we fall through. @@ -476,11 +486,8 @@ RepackLockLevel(bool concurrent) * If indexOid is InvalidOid, the table will be rewritten in physical order * instead of index order. * - * Note that, in the concurrent case, the function releases the lock at some - * point, in order to get AccessExclusiveLock for the final steps (i.e. to - * swap the relation files). To make things simpler, the caller should expect - * OldHeap to be closed on return, regardless CLUOPT_CONCURRENT. (The - * AccessExclusiveLock is kept till the end of the transaction.) + * On return, OldHeap is closed but locked with AccessExclusiveLock - the lock + * will be released at end of the transaction. * * 'cmd' indicates which command is being executed, to be used for error * messages. @@ -512,10 +519,12 @@ cluster_rel(RepackCommand cmd, Relation OldHeap, Oid indexOid, /* * Make sure we're not in a transaction block. * - * The reason is that repack_setup_logical_decoding() could deadlock - * if there's an XID already assigned. It would be possible to run in - * a transaction block if we had no XID, but this restriction is - * simpler for users to understand and we don't lose anything. + * The reason is that repack_setup_logical_decoding() could wait + * indefinitely for our XID to complete. (The deadlock detector would + * not recognize it because we'd be waiting for ourselves, i.e. no + * real lock conflict.) It would be possible to run in a transaction + * block if we had no XID, but this restriction is simpler for users + * to understand and we don't lose anything. */ PreventInTransactionBlock(isTopLevel, "REPACK (CONCURRENTLY)"); @@ -998,10 +1007,8 @@ rebuild_relation(Relation OldHeap, Relation index, bool verbose, * Note that the worker has to wait for all transactions with XID * already assigned to finish. If some of those transactions is * waiting for a lock conflicting with ShareUpdateExclusiveLock on our - * table (e.g. it runs CREATE INDEX), we can end up in a deadlock. - * Not sure this risk is worth unlocking/locking the table (and its - * clustering index) and checking again if it's still eligible for - * REPACK CONCURRENTLY. + * table (e.g. it runs CREATE INDEX), it should encounter ERROR in the + * deadlock checking code. */ start_repack_decoding_worker(tableOid); @@ -3123,10 +3130,18 @@ rebuild_relation_finish_concurrent(Relation NewHeap, Relation OldHeap, LockRelationOid(OldHeap->rd_rel->reltoastrelid, AccessExclusiveLock); /* - * Tuples and pages of the old heap will be gone, but the heap will stay. + * Now that we have all access-exclusive locks on all relations, we no + * longer want other processes to error out when trying to acquire a + * conflicting lock. Therefore, unset our flag. + */ + MyProc->statusFlags &= ~PROC_IN_CONCURRENT_REPACK; + + /* + * Tuples and pages of the old heap will be gone, but the heap itself will + * stay. In order for predicate locks to continue to work, convert them + * to relation-level locks. We do this both for table and indexes. */ TransferPredicateLocksToHeapRelation(OldHeap); - /* The same for indexes. */ for (int i = 0; i < nind; i++) { Relation index = ind_refs[i]; @@ -3346,9 +3361,11 @@ start_repack_decoding_worker(Oid relid) /* * The decoding setup must be done before the caller can have XID assigned - * for any reason, otherwise the worker might end up in a deadlock, - * waiting for the caller's transaction to end. Therefore wait here until - * the worker indicates that it has the logical decoding initialized. + * for any reason, otherwise the worker might end up waiting for the + * caller's transaction to end. (Deadlock detector does not consider this + * a conflict because the worker is in the same locking group as the + * backend that launched it.) Therefore wait here until the worker + * indicates that it has the logical decoding initialized. */ ConditionVariablePrepareToSleep(&shared->cv); for (;;) diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c index b8962d875b6..3d3ec0da111 100644 --- a/src/backend/storage/lmgr/deadlock.c +++ b/src/backend/storage/lmgr/deadlock.c @@ -620,6 +620,21 @@ FindLockCycleRecurseMember(PGPROC *checkProc, proc->statusFlags & PROC_IS_AUTOVACUUM) blocking_autovacuum_proc = proc; + /* + * Similarly, if we note that we're blocked by some process + * running REPACK (CONCURRENTLY), just fail. That process + * is going to upgrade its lock at some point, and it would + * be inappropriate for any other process to cause that + * to fail. + */ + if (checkProc == MyProc && + proc->statusFlags & PROC_IN_CONCURRENT_REPACK) + ereport(ERROR, + errcode(ERRCODE_OBJECT_IN_USE), + errmsg("could not wait for concurrent REPACK"), + errdetail("Process %d waits for REPACK running on process %d", + MyProc->pid, proc->pid)); + /* We're done looking at this proclock */ break; } diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 1dad125706e..8ad9718f3d6 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -69,10 +69,12 @@ struct XidCache #define PROC_AFFECTS_ALL_HORIZONS 0x20 /* this proc's xmin must be * included in vacuum horizons * in all databases */ +#define PROC_IN_CONCURRENT_REPACK 0x40 /* REPACK (CONCURRENTLY) */ -/* flags reset at EOXact */ +/* flags reset at EOXact. A bit of a misnomer ... */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_IN_SAFE_IC | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_IC | PROC_VACUUM_FOR_WRAPAROUND | \ + PROC_IN_CONCURRENT_REPACK) /* * Xmin-related flags. Make sure any flags that affect how the process' Xmin diff --git a/src/test/modules/injection_points/Makefile b/src/test/modules/injection_points/Makefile index 2cd7d87c533..f7663859fe2 100644 --- a/src/test/modules/injection_points/Makefile +++ b/src/test/modules/injection_points/Makefile @@ -15,6 +15,7 @@ REGRESS_OPTS = --dlpath=$(top_builddir)/src/test/regress ISOLATION = basic \ inplace \ repack \ + repack_deadlock \ repack_toast \ syscache-update-pruned \ heap_lock_update diff --git a/src/test/modules/injection_points/expected/repack_deadlock.out b/src/test/modules/injection_points/expected/repack_deadlock.out new file mode 100644 index 00000000000..a86e4767536 --- /dev/null +++ b/src/test/modules/injection_points/expected/repack_deadlock.out @@ -0,0 +1,63 @@ +Parsed test spec with 2 sessions + +starting permutation: wait_before_lock add_column wakeup_before_lock check1 +injection_points_attach +----------------------- + +(1 row) + +step wait_before_lock: + REPACK (CONCURRENTLY) repack_deadlock USING INDEX repack_deadlock_pkey; + <waiting ...> +step add_column: + alter table repack_deadlock add column noise text; + <waiting ...> +step add_column: <... completed> +ERROR: could not wait for concurrent REPACK +step wakeup_before_lock: + SELECT injection_points_wakeup('repack-concurrently-before-lock'); + +injection_points_wakeup +----------------------- + +(1 row) + +step wait_before_lock: <... completed> +step check1: + INSERT INTO relfilenodes(node) + SELECT relfilenode FROM pg_class WHERE relname='repack_deadlock'; + + SELECT count(DISTINCT node) FROM relfilenodes; + + SELECT i, j FROM repack_deadlock ORDER BY i, j; + + INSERT INTO data_s1(i, j) + SELECT i, j FROM repack_deadlock; + + SELECT count(*) + FROM data_s1 d1 FULL JOIN data_s2 d2 USING (i, j) + WHERE d1.i ISNULL OR d2.i ISNULL; + +count +----- + 1 +(1 row) + +i|j +-+- +1|1 +2|2 +3|3 +4|4 +(4 rows) + +count +----- + 4 +(1 row) + +injection_points_detach +----------------------- + +(1 row) + diff --git a/src/test/modules/injection_points/meson.build b/src/test/modules/injection_points/meson.build index a414abb924b..1cd88d6db65 100644 --- a/src/test/modules/injection_points/meson.build +++ b/src/test/modules/injection_points/meson.build @@ -46,6 +46,7 @@ tests += { 'basic', 'inplace', 'repack', + 'repack_deadlock', 'repack_toast', 'syscache-update-pruned', 'heap_lock_update', diff --git a/src/test/modules/injection_points/specs/repack_deadlock.spec b/src/test/modules/injection_points/specs/repack_deadlock.spec new file mode 100644 index 00000000000..9d23a6588c2 --- /dev/null +++ b/src/test/modules/injection_points/specs/repack_deadlock.spec @@ -0,0 +1,83 @@ +# Test REPACK with a concurrent transaction that would cause a deadlock +setup +{ + CREATE EXTENSION injection_points; + + CREATE TABLE repack_deadlock(i int PRIMARY KEY, j int); + INSERT INTO repack_deadlock(i, j) VALUES (1, 1), (2, 2), (3, 3), (4, 4); + + CREATE TABLE relfilenodes(node oid); + + CREATE TABLE data_s1(i int, j int); + CREATE TABLE data_s2(i int, j int); +} + +teardown +{ + DROP TABLE repack_deadlock; + DROP EXTENSION injection_points; + + DROP TABLE relfilenodes; + DROP TABLE data_s1; + DROP TABLE data_s2; +} + +session s1 +setup +{ + SELECT injection_points_set_local(); + SELECT injection_points_attach('repack-concurrently-before-lock', 'wait'); +} +# Perform the initial load and wait for s2 to do some data changes. +step wait_before_lock +{ + REPACK (CONCURRENTLY) repack_deadlock USING INDEX repack_deadlock_pkey; +} +# Check the table from the perspective of s1. +# +# Besides the contents, we also check that relfilenode has changed. + +# Have each session write the contents into a table and use FULL JOIN to check +# if the outputs are identical. +step check1 +{ + INSERT INTO relfilenodes(node) + SELECT relfilenode FROM pg_class WHERE relname='repack_deadlock'; + + SELECT count(DISTINCT node) FROM relfilenodes; + + SELECT i, j FROM repack_deadlock ORDER BY i, j; + + INSERT INTO data_s1(i, j) + SELECT i, j FROM repack_deadlock; + + SELECT count(*) + FROM data_s1 d1 FULL JOIN data_s2 d2 USING (i, j) + WHERE d1.i ISNULL OR d2.i ISNULL; +} +teardown +{ + SELECT injection_points_detach('repack-concurrently-before-lock'); +} + +session s2 +# Change the existing data. UPDATE changes both key and non-key columns. Also +# update one row twice to test whether tuple version generated by this session +# can be found. +step add_column +{ + alter table repack_deadlock add column noise text; +} + +step wakeup_before_lock +{ + SELECT injection_points_wakeup('repack-concurrently-before-lock'); +} + +# Test if data changes introduced while one session is performing REPACK +# CONCURRENTLY find their way into the table. +permutation + wait_before_lock + add_column + wakeup_before_lock + check1 -- 2.47.3 --mdsv5bdgfjjj6d77 Content-Type: text/x-diff; charset=utf-8 Content-Disposition: attachment; filename="v46-0007-Teach-snapshot-builder-to-skip-transactions-runn.patch" ^ permalink raw reply [nested|flat] 319+ messages in thread
end of thread, other threads:[~2026-03-25 19:35 UTC | newest] Thread overview: 319+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-02-19 16:45 [PATCH v2 4/6] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2026-03-25 19:35 [PATCH v46 6/7] Error out any process that would block at REPACK Álvaro Herrera <alvherre@kurilemu.de>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox