agora inbox for pgsql-hackers@postgresql.org  
help / 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 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 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] Introduce an option to make logical replication database specific.
@ 2026-04-03 10:34  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 319+ messages in thread

From: Antonin Houska @ 2026-04-03 10:34 UTC (permalink / raw)

By default, the logical decoding assumes access to shared catalogs, so the
snapshot builder needs to consider cluster-wide XIDs during startup. That in
turn means that, if any transaction is already running (and has XID assigned),
the snapshot builder needs to wait for its completion, as it does not know if
that transaction performed catalog changes earlier.

Possible problem with this concept is that if REPACK (CONCURRENTLY) is running
in some database, backends running the same command in other databases get
stuck until the first one has committed. Thus only as single backend in the
cluster can run REPACK (CONCURRENTLY) at any time. Likewise, REPACK
(CONCURRENTLY) can block walsenders starting on behalf of subscriptions
throughout the cluster.

This patch introduces the possibility for a backend to declare that its output
plugin does not use shared catalogs (i.e. catalogs that can be changed by
transactions running in other databases in the cluster). In that case, no
snapshot the backend will use during the decoding needs to contain information
about transactions running in other databases. Thus the snapshot builder only
needs to wait for completion of transactions in the current database.

Currently we only use this option in the REPACK background worker. It could
possibly be used in walsender involved in logical replication too, however
that would need thorough analysis of its output plugin.

The patch bumps WAL version number, due to a new field in xl_running_xacts.
---
 contrib/pg_visibility/pg_visibility.c       |  4 ++--
 src/backend/access/index/genam.c            | 18 ++++++++++++++++
 src/backend/access/rmgrdesc/standbydesc.c   |  2 ++
 src/backend/access/transam/xlog.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c      |  2 +-
 src/backend/commands/repack_worker.c        |  8 +++++++
 src/backend/postmaster/bgwriter.c           |  2 +-
 src/backend/replication/logical/snapbuild.c | 10 ++++++++-
 src/backend/replication/slot.c              | 12 +++++++++--
 src/backend/storage/ipc/procarray.c         | 23 ++++++++++++++++++++-
 src/backend/storage/ipc/standby.c           | 14 +++++++++++--
 src/include/access/genam.h                  |  8 +++++++
 src/include/access/xlog_internal.h          |  2 +-
 src/include/storage/procarray.h             |  2 +-
 src/include/storage/standby.h               |  3 ++-
 src/include/storage/standbydefs.h           |  1 +
 16 files changed, 99 insertions(+), 14 deletions(-)

diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dfab0b64cf5..d564bd2a00c 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -621,7 +621,7 @@ GetStrictOldestNonRemovableTransactionId(Relation rel)
 	else if (rel == NULL || rel->rd_rel->relisshared)
 	{
 		/* Shared relation: take into account all running xids */
-		runningTransactions = GetRunningTransactionData();
+		runningTransactions = GetRunningTransactionData(InvalidOid);
 		LWLockRelease(ProcArrayLock);
 		LWLockRelease(XidGenLock);
 		return runningTransactions->oldestRunningXid;
@@ -632,7 +632,7 @@ GetStrictOldestNonRemovableTransactionId(Relation rel)
 		 * Normal relation: take into account xids running within the current
 		 * database
 		 */
-		runningTransactions = GetRunningTransactionData();
+		runningTransactions = GetRunningTransactionData(InvalidOid);
 		LWLockRelease(ProcArrayLock);
 		LWLockRelease(XidGenLock);
 		return runningTransactions->oldestDatabaseRunningXid;
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c
index 1408989c568..97ea882cf71 100644
--- a/src/backend/access/index/genam.c
+++ b/src/backend/access/index/genam.c
@@ -37,6 +37,14 @@
 #include "utils/ruleutils.h"
 #include "utils/snapmgr.h"
 
+/*
+ * If a backend is going to do logical decoding and if the output plugin does
+ * not need to access shared catalogs, setting this variable to false can make
+ * the decoding startup faster. In particular, the backend will not need to
+ * wait for completion of already running transactions in other databases.
+ */
+bool accessSharedCatalogsInDecoding = true;
+
 
 /* ----------------------------------------------------------------
  *		general access method routines
@@ -394,6 +402,16 @@ systable_beginscan(Relation heapRelation,
 	SysScanDesc sysscan;
 	Relation	irel;
 
+	/*
+	 * If this backend promised that it won't access shared catalogs during
+	 * logical decoding, this seems to be the right place to check.
+	 *
+	 * XXX Should this be ereport(ERROR) ?
+	 */
+	Assert(!HistoricSnapshotActive() ||
+		   accessSharedCatalogsInDecoding ||
+		   !heapRelation->rd_rel->relisshared);
+
 	if (indexOK &&
 		!IgnoreSystemIndexes &&
 		!ReindexIsProcessingIndex(indexId))
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index 0a291354ae2..685d1bdb024 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -41,6 +41,8 @@ standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec)
 		for (i = 0; i < xlrec->subxcnt; i++)
 			appendStringInfo(buf, " %u", xlrec->xids[xlrec->xcnt + i]);
 	}
+
+	appendStringInfo(buf, "; dbid: %u", xlrec->dbid);
 }
 
 void
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 2c1c6f88b74..8da8eff93e4 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7336,7 +7336,7 @@ CreateCheckPoint(int flags)
 	 * recovery we don't need to write running xact data.
 	 */
 	if (!shutdown && XLogStandbyInfoActive())
-		LogStandbySnapshot();
+		LogStandbySnapshot(InvalidOid);
 
 	START_CRIT_SECTION();
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 65bbaeda59c..0f5979691e6 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -245,7 +245,7 @@ pg_log_standby_snapshot(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("pg_log_standby_snapshot() can only be used if \"wal_level\" >= \"replica\"")));
 
-	recptr = LogStandbySnapshot();
+	recptr = LogStandbySnapshot(InvalidOid);
 
 	/*
 	 * As a convenience, return the WAL location of the last inserted record
diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index 00b21ede481..c25dbeadff3 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -16,6 +16,7 @@
  */
 #include "postgres.h"
 
+#include "access/genam.h"
 #include "access/table.h"
 #include "access/xlog_internal.h"
 #include "access/xlogutils.h"
@@ -233,6 +234,13 @@ repack_setup_logical_decoding(Oid relid)
 
 	EnsureLogicalDecodingEnabled();
 
+	/*
+	 * By declaring that our output plugin does not need shared catalogs, we
+	 * avoid waiting for completion of transactions running in other databases
+	 * than the one we're connected to.
+	 */
+	accessSharedCatalogsInDecoding = false;
+
 	/*
 	 * Neither prepare_write nor do_write callback nor update_progress is
 	 * useful for us.
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index 1d8947774a9..a30de4262eb 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -289,7 +289,7 @@ BackgroundWriterMain(const void *startup_data, size_t startup_data_len)
 			if (now >= timeout &&
 				last_snapshot_lsn <= GetLastImportantRecPtr())
 			{
-				last_snapshot_lsn = LogStandbySnapshot();
+				last_snapshot_lsn = LogStandbySnapshot(InvalidOid);
 				last_snapshot_ts = now;
 			}
 		}
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 0f6b5df322c..16009fa75a4 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -125,6 +125,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "access/genam.h"
 #include "access/heapam_xlog.h"
 #include "access/transam.h"
 #include "access/xact.h"
@@ -1470,7 +1471,14 @@ SnapBuildWaitSnapshot(xl_running_xacts *running, TransactionId cutoff)
 	 */
 	if (!RecoveryInProgress())
 	{
-		LogStandbySnapshot();
+		Oid		dbid;
+
+		/*
+		 * Only consider transactions of the current database if our plugin is
+		 * not supposed to access shared catalogs.
+		 */
+		dbid = accessSharedCatalogsInDecoding ? InvalidOid : MyDatabaseId;
+		LogStandbySnapshot(dbid);
 	}
 }
 
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index fe6bfeba25e..0d415f5f8f2 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -39,6 +39,7 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
+#include "access/genam.h"
 #include "access/transam.h"
 #include "access/xlog_internal.h"
 #include "access/xlogrecovery.h"
@@ -1776,9 +1777,16 @@ ReplicationSlotReserveWal(void)
 	if (!RecoveryInProgress() && SlotIsLogical(slot))
 	{
 		XLogRecPtr	flushptr;
+		Oid		dbid;
 
-		/* make sure we have enough information to start */
-		flushptr = LogStandbySnapshot();
+		/*
+		 * Make sure we have enough information to start.
+		 *
+		 * Only consider transactions of the current database if our plugin
+		 * is not supposed to access shared catalogs.
+		 */
+		dbid = accessSharedCatalogsInDecoding ? InvalidOid : MyDatabaseId;
+		flushptr = LogStandbySnapshot(dbid);
 
 		/* and make sure it's fsynced to disk */
 		XLogFlush(flushptr);
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index cc207cb56e3..49d1bf4bfac 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -2631,9 +2631,11 @@ ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc)
  *
  * Note that if any transaction has overflowed its cached subtransactions
  * then there is no real need include any subtransactions.
+ *
+ * If 'dbid' is valid, only gather transactions running in that database.
  */
 RunningTransactions
-GetRunningTransactionData(void)
+GetRunningTransactionData(Oid dbid)
 {
 	/* result workspace */
 	static RunningTransactionsData CurrentRunningXactsData;
@@ -2708,6 +2710,18 @@ GetRunningTransactionData(void)
 		if (!TransactionIdIsValid(xid))
 			continue;
 
+		/*
+		 * Filter by database OID if requested.
+		 */
+		if (OidIsValid(dbid))
+		{
+			int			pgprocno = arrayP->pgprocnos[index];
+			PGPROC	   *proc = &allProcs[pgprocno];
+
+			if (proc->databaseId != dbid)
+				continue;
+		}
+
 		/*
 		 * Be careful not to exclude any xids before calculating the values of
 		 * oldestRunningXid and suboverflowed, since these are used to clean
@@ -2758,6 +2772,12 @@ GetRunningTransactionData(void)
 			PGPROC	   *proc = &allProcs[pgprocno];
 			int			nsubxids;
 
+			/*
+			 * Filter by database OID if requested.
+			 */
+			if (OidIsValid(dbid) && proc->databaseId != dbid)
+					continue;
+
 			/*
 			 * Save subtransaction XIDs. Other backends can't add or remove
 			 * entries while we're holding XidGenLock.
@@ -2791,6 +2811,7 @@ GetRunningTransactionData(void)
 	 * increases if slots do.
 	 */
 
+	CurrentRunningXacts->dbid = dbid;
 	CurrentRunningXacts->xcnt = count - subcount;
 	CurrentRunningXacts->subxcnt = subcount;
 	CurrentRunningXacts->subxid_status = suboverflowed ? SUBXIDS_IN_SUBTRANS : SUBXIDS_IN_ARRAY;
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index de9092fdf5b..c653ea742bc 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -1188,6 +1188,14 @@ standby_redo(XLogReaderState *record)
 		xl_running_xacts *xlrec = (xl_running_xacts *) XLogRecGetData(record);
 		RunningTransactionsData running;
 
+		/*
+		 * Records issued for specific database are not suitable for physical
+		 * replication because that affects the whole cluster. In particular,
+		 * the list of XID is probably incomplete here.
+		 */
+		if (OidIsValid(xlrec->dbid))
+			return;
+
 		running.xcnt = xlrec->xcnt;
 		running.subxcnt = xlrec->subxcnt;
 		running.subxid_status = xlrec->subxid_overflow ? SUBXIDS_MISSING : SUBXIDS_IN_ARRAY;
@@ -1277,11 +1285,12 @@ standby_redo(XLogReaderState *record)
  * as there's no independent knob to just enable logical decoding. For
  * details of how this is used, check snapbuild.c's introductory comment.
  *
+ * If 'dbid' is valid, only gather transactions running in that database.
  *
  * Returns the RecPtr of the last inserted record.
  */
 XLogRecPtr
-LogStandbySnapshot(void)
+LogStandbySnapshot(Oid dbid)
 {
 	XLogRecPtr	recptr;
 	RunningTransactions running;
@@ -1314,7 +1323,7 @@ LogStandbySnapshot(void)
 	 * Log details of all in-progress transactions. This should be the last
 	 * record we write, because standby will open up when it sees this.
 	 */
-	running = GetRunningTransactionData();
+	running = GetRunningTransactionData(dbid);
 
 	/*
 	 * GetRunningTransactionData() acquired ProcArrayLock, we must release it.
@@ -1358,6 +1367,7 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
 	xl_running_xacts xlrec;
 	XLogRecPtr	recptr;
 
+	xlrec.dbid = CurrRunningXacts->dbid;
 	xlrec.xcnt = CurrRunningXacts->xcnt;
 	xlrec.subxcnt = CurrRunningXacts->subxcnt;
 	xlrec.subxid_overflow = (CurrRunningXacts->subxid_status != SUBXIDS_IN_ARRAY);
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index b69320a7fc8..56c573399ab 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -136,6 +136,14 @@ typedef struct IndexOrderByDistance
 	bool		isnull;
 } IndexOrderByDistance;
 
+/*
+ * Is the backend interested in shared catalogs when performing logical
+ * decoding?
+ *
+ * XXX Is there a better place for this declaration?
+ */
+extern bool accessSharedCatalogsInDecoding;
+
 /*
  * generalized index_ interface routines (in indexam.c)
  */
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 755835d63bf..ae19982d88d 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -31,7 +31,7 @@
 /*
  * Each page of XLOG file has a header like this:
  */
-#define XLOG_PAGE_MAGIC 0xD11E	/* can be used as WAL version indicator */
+#define XLOG_PAGE_MAGIC 0xD11F	/* can be used as WAL version indicator */
 
 typedef struct XLogPageHeaderData
 {
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index abdf021e66e..377b3060b9f 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -49,7 +49,7 @@ extern bool ProcArrayInstallImportedXmin(TransactionId xmin,
 										 VirtualTransactionId *sourcevxid);
 extern bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc);
 
-extern RunningTransactions GetRunningTransactionData(void);
+extern RunningTransactions GetRunningTransactionData(Oid dbid);
 
 extern bool TransactionIdIsInProgress(TransactionId xid);
 extern TransactionId GetOldestNonRemovableTransactionId(Relation rel);
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index 6a314c693cd..8715c08e94f 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -126,6 +126,7 @@ typedef enum
 
 typedef struct RunningTransactionsData
 {
+	Oid			dbid;			/* only track xacts in this database */
 	int			xcnt;			/* # of xact ids in xids[] */
 	int			subxcnt;		/* # of subxact ids in xids[] */
 	subxids_array_status subxid_status;
@@ -143,7 +144,7 @@ typedef RunningTransactionsData *RunningTransactions;
 extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid);
 extern void LogAccessExclusiveLockPrepare(void);
 
-extern XLogRecPtr LogStandbySnapshot(void);
+extern XLogRecPtr LogStandbySnapshot(Oid dbid);
 extern void LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs,
 									bool relcacheInitFileInval);
 
diff --git a/src/include/storage/standbydefs.h b/src/include/storage/standbydefs.h
index 231d251fd51..e75b7078766 100644
--- a/src/include/storage/standbydefs.h
+++ b/src/include/storage/standbydefs.h
@@ -46,6 +46,7 @@ typedef struct xl_standby_locks
  */
 typedef struct xl_running_xacts
 {
+	Oid			dbid;			/* only track xacts in this database */
 	int			xcnt;			/* # of xact ids in xids[] */
 	int			subxcnt;		/* # of subxact ids in xids[] */
 	bool		subxid_overflow;	/* snapshot overflowed, subxids missing */
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 319+ messages in thread


end of thread, other threads:[~2026-04-03 10:34 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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>
2026-04-03 10:34 [PATCH] Introduce an option to make logical replication database specific. Antonin Houska <ah@cybertec.at>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox