agora inbox for pgsql-hackers@postgresql.orghelp / color / mirror / Atom feed
[PATCH v7 1/7] Row pattern recognition patch for raw parser. 319+ messages / 2 participants [nested] [flat]
* [PATCH v7 1/7] Row pattern recognition patch for raw parser. @ 2023-09-22 04:53 Tatsuo Ishii <ishii@postgresql.org> 0 siblings, 0 replies; 319+ messages in thread From: Tatsuo Ishii @ 2023-09-22 04:53 UTC (permalink / raw) --- src/backend/parser/gram.y | 222 ++++++++++++++++++++++++++++++-- src/include/nodes/parsenodes.h | 56 ++++++++ src/include/parser/kwlist.h | 8 ++ src/include/parser/parse_node.h | 1 + 4 files changed, 273 insertions(+), 14 deletions(-) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 7d2032885e..74c2069050 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -251,6 +251,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); DefElem *defelt; SortBy *sortby; WindowDef *windef; + RPCommonSyntax *rpcom; + RPSubsetItem *rpsubset; JoinExpr *jexpr; IndexElem *ielem; StatsElem *selem; @@ -278,6 +280,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); MergeWhenClause *mergewhen; struct KeyActions *keyactions; struct KeyAction *keyaction; + RPSkipTo skipto; } %type <node> stmt toplevel_stmt schema_stmt routine_body_stmt @@ -453,8 +456,12 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); TriggerTransitions TriggerReferencing vacuum_relation_list opt_vacuum_relation_list drop_option_list pub_obj_list - -%type <node> opt_routine_body + row_pattern_measure_list row_pattern_definition_list + opt_row_pattern_subset_clause + row_pattern_subset_list row_pattern_subset_rhs + row_pattern +%type <rpsubset> row_pattern_subset_item +%type <node> opt_routine_body row_pattern_term %type <groupclause> group_clause %type <list> group_by_list %type <node> group_by_item empty_grouping_set rollup_clause cube_clause @@ -551,6 +558,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <range> relation_expr_opt_alias %type <node> tablesample_clause opt_repeatable_clause %type <target> target_el set_target insert_column_item + row_pattern_measure_item row_pattern_definition +%type <skipto> first_or_last %type <str> generic_option_name %type <node> generic_option_arg @@ -633,6 +642,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <list> window_clause window_definition_list opt_partition_clause %type <windef> window_definition over_clause window_specification opt_frame_clause frame_extent frame_bound +%type <rpcom> opt_row_pattern_common_syntax opt_row_pattern_skip_to +%type <boolean> opt_row_pattern_initial_or_seek +%type <list> opt_row_pattern_measures %type <ival> opt_window_exclusion_clause %type <str> opt_existing_window_name %type <boolean> opt_if_not_exists @@ -659,7 +671,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); json_object_constructor_null_clause_opt json_array_constructor_null_clause_opt - /* * Non-keyword token types. These are hard-wired into the "flex" lexer. * They must be listed first so that their numeric codes do not depend on @@ -702,7 +713,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS - DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC + DEFERRABLE DEFERRED DEFINE DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP @@ -718,7 +729,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); HANDLER HAVING HEADER_P HOLD HOUR_P IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IMPORT_P IN_P INCLUDE - INCLUDING INCREMENT INDENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P + INCLUDING INCREMENT INDENT INDEX INDEXES INHERIT INHERITS INITIAL INITIALLY INLINE_P INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION @@ -731,7 +742,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED - MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MERGE METHOD + MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MEASURES MERGE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NFC NFD NFKC NFKD NO NONE @@ -743,8 +754,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); ORDER ORDINALITY OTHERS OUT_P OUTER_P OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER - PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD - PLACING PLANS POLICY + PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PAST + PATTERN_P PERMUTE PLACING PLANS POLICY POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION @@ -755,12 +766,13 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); RESET RESTART RESTRICT RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP ROUTINE ROUTINES ROW ROWS RULE - SAVEPOINT SCALAR SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT + SAVEPOINT SCALAR SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SEEK SELECT SEQUENCE SEQUENCES + SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P START STATEMENT STATISTICS STDIN STDOUT STORAGE STORED STRICT_P STRIP_P - SUBSCRIPTION SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P SYSTEM_USER + SUBSCRIPTION SUBSET SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P SYSTEM_USER TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIES TIME TIMESTAMP TO TRAILING TRANSACTION TRANSFORM @@ -853,6 +865,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); */ %nonassoc UNBOUNDED /* ideally would have same precedence as IDENT */ %nonassoc IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP +%nonassoc MEASURES AFTER INITIAL SEEK PATTERN_P %left Op OPERATOR /* multi-character ops and user-defined operators */ %left '+' '-' %left '*' '/' '%' @@ -15857,7 +15870,8 @@ over_clause: OVER window_specification ; window_specification: '(' opt_existing_window_name opt_partition_clause - opt_sort_clause opt_frame_clause ')' + opt_sort_clause opt_row_pattern_measures opt_frame_clause + opt_row_pattern_common_syntax ')' { WindowDef *n = makeNode(WindowDef); @@ -15865,10 +15879,12 @@ window_specification: '(' opt_existing_window_name opt_partition_clause n->refname = $2; n->partitionClause = $3; n->orderClause = $4; + n->rowPatternMeasures = $5; /* copy relevant fields of opt_frame_clause */ - n->frameOptions = $5->frameOptions; - n->startOffset = $5->startOffset; - n->endOffset = $5->endOffset; + n->frameOptions = $6->frameOptions; + n->startOffset = $6->startOffset; + n->endOffset = $6->endOffset; + n->rpCommonSyntax = $7; n->location = @1; $$ = n; } @@ -15892,6 +15908,31 @@ opt_partition_clause: PARTITION BY expr_list { $$ = $3; } | /*EMPTY*/ { $$ = NIL; } ; +/* + * ROW PATTERN_P MEASURES + */ +opt_row_pattern_measures: MEASURES row_pattern_measure_list { $$ = $2; } + | /*EMPTY*/ { $$ = NIL; } + ; + +row_pattern_measure_list: + row_pattern_measure_item + { $$ = list_make1($1); } + | row_pattern_measure_list ',' row_pattern_measure_item + { $$ = lappend($1, $3); } + ; + +row_pattern_measure_item: + a_expr AS ColLabel + { + $$ = makeNode(ResTarget); + $$->name = $3; + $$->indirection = NIL; + $$->val = (Node *) $1; + $$->location = @1; + } + ; + /* * For frame clauses, we return a WindowDef, but only some fields are used: * frameOptions, startOffset, and endOffset. @@ -16051,6 +16092,143 @@ opt_window_exclusion_clause: | /*EMPTY*/ { $$ = 0; } ; +opt_row_pattern_common_syntax: +opt_row_pattern_skip_to opt_row_pattern_initial_or_seek + PATTERN_P '(' row_pattern ')' + opt_row_pattern_subset_clause + DEFINE row_pattern_definition_list + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = $1->rpSkipTo; + n->rpSkipVariable = $1->rpSkipVariable; + n->initial = $2; + n->rpPatterns = $5; + n->rpSubsetClause = $7; + n->rpDefs = $9; + $$ = n; + } + | /*EMPTY*/ { $$ = NULL; } + ; + +opt_row_pattern_skip_to: + AFTER MATCH SKIP TO NEXT ROW + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = ST_NEXT_ROW; + n->rpSkipVariable = NULL; + $$ = n; + } + | AFTER MATCH SKIP PAST LAST_P ROW + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = ST_PAST_LAST_ROW; + n->rpSkipVariable = NULL; + $$ = n; + } + | AFTER MATCH SKIP TO first_or_last ColId + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = $5; + n->rpSkipVariable = $6; + $$ = n; + } +/* + | AFTER MATCH SKIP TO LAST_P ColId %prec LAST_P + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = ST_LAST_VARIABLE; + n->rpSkipVariable = $6; + $$ = n; + } + | AFTER MATCH SKIP TO ColId + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = ST_VARIABLE; + n->rpSkipVariable = $5; + $$ = n; + } +*/ + | /*EMPTY*/ + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + /* temporary set default to ST_NEXT_ROW */ + n->rpSkipTo = ST_PAST_LAST_ROW; + n->rpSkipVariable = NULL; + $$ = n; + } + ; + +first_or_last: + FIRST_P { $$ = ST_FIRST_VARIABLE; } + | LAST_P { $$ = ST_LAST_VARIABLE; } + ; + +opt_row_pattern_initial_or_seek: + INITIAL { $$ = true; } + | SEEK + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("SEEK is not supported"), + errhint("Use INITIAL."), + parser_errposition(@1))); + } + | /*EMPTY*/ { $$ = true; } + ; + +row_pattern: + row_pattern_term { $$ = list_make1($1); } + | row_pattern row_pattern_term { $$ = lappend($1, $2); } + ; + +row_pattern_term: + ColId { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "", (Node *)makeString($1), NULL, @1); } + | ColId '*' { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", (Node *)makeString($1), NULL, @1); } + | ColId '+' { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", (Node *)makeString($1), NULL, @1); } + | ColId '?' { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "?", (Node *)makeString($1), NULL, @1); } + ; + +opt_row_pattern_subset_clause: + SUBSET row_pattern_subset_list { $$ = $2; } + | /*EMPTY*/ { $$ = NIL; } + ; + +row_pattern_subset_list: + row_pattern_subset_item { $$ = list_make1($1); } + | row_pattern_subset_list ',' row_pattern_subset_item { $$ = lappend($1, $3); } + | /*EMPTY*/ { $$ = NIL; } + ; + +row_pattern_subset_item: ColId '=' '(' row_pattern_subset_rhs ')' + { + RPSubsetItem *n = makeNode(RPSubsetItem); + n->name = $1; + n->rhsVariable = $4; + $$ = n; + } + ; + +row_pattern_subset_rhs: + ColId { $$ = list_make1(makeStringConst($1, @1)); } + | row_pattern_subset_rhs ',' ColId { $$ = lappend($1, makeStringConst($3, @1)); } + | /*EMPTY*/ { $$ = NIL; } + ; + +row_pattern_definition_list: + row_pattern_definition { $$ = list_make1($1); } + | row_pattern_definition_list ',' row_pattern_definition { $$ = lappend($1, $3); } + ; + +row_pattern_definition: + ColId AS a_expr + { + $$ = makeNode(ResTarget); + $$->name = $1; + $$->indirection = NIL; + $$->val = (Node *) $3; + $$->location = @1; + } + ; /* * Supporting nonterminals for expressions. @@ -17146,6 +17324,7 @@ unreserved_keyword: | INDEXES | INHERIT | INHERITS + | INITIAL | INLINE_P | INPUT_P | INSENSITIVE @@ -17173,6 +17352,7 @@ unreserved_keyword: | MATCHED | MATERIALIZED | MAXVALUE + | MEASURES | MERGE | METHOD | MINUTE_P @@ -17215,6 +17395,9 @@ unreserved_keyword: | PARTITION | PASSING | PASSWORD + | PAST + | PATTERN_P + | PERMUTE | PLANS | POLICY | PRECEDING @@ -17265,6 +17448,7 @@ unreserved_keyword: | SEARCH | SECOND_P | SECURITY + | SEEK | SEQUENCE | SEQUENCES | SERIALIZABLE @@ -17290,6 +17474,7 @@ unreserved_keyword: | STRICT_P | STRIP_P | SUBSCRIPTION + | SUBSET | SUPPORT | SYSID | SYSTEM_P @@ -17477,6 +17662,7 @@ reserved_keyword: | CURRENT_USER | DEFAULT | DEFERRABLE + | DEFINE | DESC | DISTINCT | DO @@ -17639,6 +17825,7 @@ bare_label_keyword: | DEFAULTS | DEFERRABLE | DEFERRED + | DEFINE | DEFINER | DELETE_P | DELIMITER @@ -17714,6 +17901,7 @@ bare_label_keyword: | INDEXES | INHERIT | INHERITS + | INITIAL | INITIALLY | INLINE_P | INNER_P @@ -17763,6 +17951,7 @@ bare_label_keyword: | MATCHED | MATERIALIZED | MAXVALUE + | MEASURES | MERGE | METHOD | MINVALUE @@ -17816,6 +18005,9 @@ bare_label_keyword: | PARTITION | PASSING | PASSWORD + | PAST + | PATTERN_P + | PERMUTE | PLACING | PLANS | POLICY @@ -17872,6 +18064,7 @@ bare_label_keyword: | SCROLL | SEARCH | SECURITY + | SEEK | SELECT | SEQUENCE | SEQUENCES @@ -17903,6 +18096,7 @@ bare_label_keyword: | STRICT_P | STRIP_P | SUBSCRIPTION + | SUBSET | SUBSTRING | SUPPORT | SYMMETRIC diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index fef4c714b8..657651df1d 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -547,6 +547,44 @@ typedef struct SortBy int location; /* operator location, or -1 if none/unknown */ } SortBy; +/* + * AFTER MATCH row pattern skip to types in row pattern common syntax + */ +typedef enum RPSkipTo +{ + ST_NONE, /* AFTER MATCH omitted */ + ST_NEXT_ROW, /* SKIP TO NEXT ROW */ + ST_PAST_LAST_ROW, /* SKIP TO PAST LAST ROW */ + ST_FIRST_VARIABLE, /* SKIP TO FIRST variable name */ + ST_LAST_VARIABLE, /* SKIP TO LAST variable name */ + ST_VARIABLE /* SKIP TO variable name */ +} RPSkipTo; + +/* + * Row Pattern SUBSET clause item + */ +typedef struct RPSubsetItem +{ + NodeTag type; + char *name; /* Row Pattern SUBSET clause variable name */ + List *rhsVariable; /* Row Pattern SUBSET rhs variables (list of char *string) */ +} RPSubsetItem; + +/* + * RowPatternCommonSyntax - raw representation of row pattern common syntax + * + */ +typedef struct RPCommonSyntax +{ + NodeTag type; + RPSkipTo rpSkipTo; /* Row Pattern AFTER MATCH SKIP type */ + char *rpSkipVariable; /* Row Pattern Skip To variable name, if any */ + bool initial; /* true if <row pattern initial or seek> is initial */ + List *rpPatterns; /* PATTERN variables (list of A_Expr) */ + List *rpSubsetClause; /* row pattern subset clause (list of RPSubsetItem), if any */ + List *rpDefs; /* row pattern definitions clause (list of ResTarget) */ +} RPCommonSyntax; + /* * WindowDef - raw representation of WINDOW and OVER clauses * @@ -562,6 +600,8 @@ typedef struct WindowDef char *refname; /* referenced window name, if any */ List *partitionClause; /* PARTITION BY expression list */ List *orderClause; /* ORDER BY (list of SortBy) */ + List *rowPatternMeasures; /* row pattern measures (list of ResTarget) */ + RPCommonSyntax *rpCommonSyntax; /* row pattern common syntax */ int frameOptions; /* frame_clause options, see below */ Node *startOffset; /* expression for starting bound, if any */ Node *endOffset; /* expression for ending bound, if any */ @@ -1483,6 +1523,11 @@ typedef struct GroupingSet * the orderClause might or might not be copied (see copiedOrder); the framing * options are never copied, per spec. * + * "defineClause" is Row Pattern Recognition DEFINE clause (list of + * TargetEntry). TargetEntry.resname represents row pattern definition + * variable name. "patternVariable" and "patternRegexp" represents PATTERN + * clause. + * * The information relevant for the query jumbling is the partition clause * type and its bounds. */ @@ -1514,6 +1559,17 @@ typedef struct WindowClause Index winref; /* ID referenced by window functions */ /* did we copy orderClause from refname? */ bool copiedOrder pg_node_attr(query_jumble_ignore); + /* Row Pattern AFTER MACH SKIP clause */ + RPSkipTo rpSkipTo; /* Row Pattern Skip To type */ + bool initial; /* true if <row pattern initial or seek> is initial */ + /* Row Pattern DEFINE clause (list of TargetEntry) */ + List *defineClause; + /* Row Pattern DEFINE variable initial names (list of String) */ + List *defineInitial; + /* Row Pattern PATTERN variable name (list of String) */ + List *patternVariable; + /* Row Pattern PATTERN regular expression quantifier ('+' or ''. list of String) */ + List *patternRegexp; } WindowClause; /* diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 5984dcfa4b..2804333b53 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -128,6 +128,7 @@ PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("define", DEFINE, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, BARE_LABEL) @@ -212,6 +213,7 @@ PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("initial", INITIAL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) @@ -265,6 +267,7 @@ PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("matched", MATCHED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("measures", MEASURES, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("merge", MERGE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, AS_LABEL) @@ -326,6 +329,9 @@ PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("past", PAST, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("pattern", PATTERN_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("permute", PERMUTE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE_LABEL) @@ -385,6 +391,7 @@ PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("seek", SEEK, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, BARE_LABEL) @@ -416,6 +423,7 @@ PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("subset", SUBSET, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, BARE_LABEL) diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index f589112d5e..6640090910 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -51,6 +51,7 @@ typedef enum ParseExprKind EXPR_KIND_WINDOW_FRAME_RANGE, /* window frame clause with RANGE */ EXPR_KIND_WINDOW_FRAME_ROWS, /* window frame clause with ROWS */ EXPR_KIND_WINDOW_FRAME_GROUPS, /* window frame clause with GROUPS */ + EXPR_KIND_RPR_DEFINE, /* DEFINE */ EXPR_KIND_SELECT_TARGET, /* SELECT target list item */ EXPR_KIND_INSERT_TARGET, /* INSERT target list item */ EXPR_KIND_UPDATE_SOURCE, /* UPDATE assignment source item */ -- 2.25.1 ----Next_Part(Fri_Sep_22_14_16_40_2023_530)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="v7-0002-Row-pattern-recognition-patch-parse-analysis.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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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
end of thread, other threads:[~2025-04-06 14:40 UTC | newest] Thread overview: 319+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2023-09-22 04:53 [PATCH v7 1/7] Row pattern recognition patch for raw parser. Tatsuo Ishii <ishii@postgresql.org> 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 v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH 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 v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH 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 v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH 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 v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH 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 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 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 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 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 v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH 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 v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v5 02/10] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH v4 4/8] Introduce pending flag for GUC assign hooks Dmitrii Dolgov <9erthalion6@gmail.com> 2025-04-06 14:40 [PATCH 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 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>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox